Skip to content

Commit c55ea20

Browse files
c-okellyc-okelly
authored andcommitted
Fix bar overflow issues on time and interval axis by adjusting axis scale
1 parent eb95d20 commit c55ea20

File tree

3 files changed

+213
-1
lines changed

3 files changed

+213
-1
lines changed

src/coord/axisHelper.js

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import * as numberUtil from '../util/number';
88

99
import '../scale/Time';
1010
import '../scale/Log';
11+
import '../layout/barGrid';
1112

1213
/**
1314
* Get axis scale extent before niced.
@@ -111,9 +112,60 @@ export function getScaleExtent(scale, model) {
111112
}
112113
}
113114

115+
// If bars are placed on a base axis of type time or interval account for axis boundary overflow and current axis is base axis
116+
var ecModel = model.getModel().ecModel;
117+
var numberBarPlots = ecModel.getSeriesByType("bar").length;
118+
var isBaseAxis = model.ecModel._componentsMap._ec_series.map(function(x){ return x.getBaseAxis() === model.axis}).indexOf(true) !== -1;
119+
if ((scaleType === 'time' || scaleType === 'interval') && numberBarPlots > 0 && isBaseAxis){
120+
121+
// Adjust axis min and max to account for overflow
122+
var adjustedScale = axisHelper.adjustScaleForOverflow(min, max, model);
123+
min = adjustedScale.min;
124+
max = adjustedScale.max;
125+
}
126+
114127
return [min, max];
115128
}
116129

130+
axisHelper.adjustScaleForOverflow = function (min, max, model) {
131+
132+
var ecModel = model.getModel().ecModel;
133+
// Get Axis Length
134+
var axisExtent = model.axis._extent;
135+
var axisLength = axisExtent[1] - axisExtent[0]
136+
137+
// Calculate placement of bars on axis
138+
var barWidthAndOffset = barGrid.calBarWidthAndOffset(zrUtil.filter(
139+
ecModel.getSeriesByType('bar'),
140+
function (seriesModel) {
141+
return !ecModel.isSeriesFiltered(seriesModel)
142+
&& seriesModel.coordinateSystem
143+
&& seriesModel.coordinateSystem.type === 'cartesian2d';
144+
}
145+
));
146+
147+
// Get bars on current base axis and calculate min and max overflow
148+
var baseAxisKey = model.axis.dim + model.axis.index;
149+
var barsOnCurrentAxis = barWidthAndOffset[baseAxisKey];
150+
if (barsOnCurrentAxis === undefined) {
151+
return { "min": min, "max": max };
152+
}
153+
154+
var minOverflow = Math.abs(Math.min.apply(null, Object.values(barsOnCurrentAxis).map(function (x) { return x.offset })));
155+
var maxOverflow = Math.max.apply(null, Object.values(barsOnCurrentAxis).map(function (x) { return x.offset + x.width }));
156+
var totalOverFlow = minOverflow + maxOverflow;
157+
158+
// Calulate required buffer based on old range and overflow
159+
var oldRange = max - min;
160+
var oldRangePercentOfNew = (1 - (minOverflow + maxOverflow) / axisLength);
161+
var overflowBuffer = ((oldRange / oldRangePercentOfNew) - oldRange);
162+
163+
max += overflowBuffer * (maxOverflow / totalOverFlow);
164+
min -= overflowBuffer * (minOverflow / totalOverFlow);
165+
166+
return { "min": min, "max": max };
167+
}
168+
117169
export function niceScaleExtent(scale, model) {
118170
var extent = getScaleExtent(scale, model);
119171
var fixMin = model.getMin() != null;

src/layout/barGrid.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,5 +318,6 @@ function barLayoutGrid(seriesType, ecModel, api) {
318318
}
319319

320320
barLayoutGrid.getLayoutOnAxis = getLayoutOnAxis;
321+
barLayoutGrid.calBarWidthAndOffset = calBarWidthAndOffset;
321322

322-
export default barLayoutGrid;
323+
export default barLayoutGrid;

test/bar-overflow-time-plot.html

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
<html>
2+
<head>
3+
<meta charset="utf-8">
4+
<script src="esl.js"></script>
5+
<script src="config.js"></script>
6+
<script src="lib/jquery.min.js"></script>
7+
<script src="lib/facePrint.js"></script>
8+
<script src="lib/testHelper.js"></script>
9+
<meta name="viewport" content="width=device-width, initial-scale=1" />
10+
</head>
11+
<body>
12+
<style>
13+
h1 {
14+
line-height: 60px;
15+
height: 60px;
16+
background: #146402;
17+
text-align: center;
18+
font-weight: bold;
19+
color: #eee;
20+
font-size: 14px;
21+
}
22+
.chart {
23+
height: 600px;
24+
}
25+
</style>
26+
27+
<h1>
28+
<input type="button" onclick="testHelper.setURLParam(['cn', 'en'], 'cn')" value="CN"/>
29+
<input type="button" onclick="testHelper.setURLParam(['cn', 'en'], 'en')" value="EN"/>
30+
</h1>
31+
32+
<div id="main" class="chart"></div>
33+
<script>
34+
35+
require(
36+
(testHelper.hasURLParam('en')
37+
? [
38+
'echarts',
39+
'echarts/lang/en',
40+
]
41+
: [
42+
'echarts'
43+
]
44+
).concat(
45+
[
46+
'echarts/chart/bar',
47+
'echarts/chart/line',
48+
'echarts/component/legend',
49+
'echarts/component/graphic',
50+
'echarts/component/grid',
51+
'echarts/component/tooltip',
52+
'echarts/component/brush',
53+
'echarts/component/toolbox',
54+
'echarts/component/title',
55+
'zrender/vml/vml'
56+
]
57+
),
58+
function (echarts) {
59+
60+
var chart = echarts.init(document.getElementById('main'));
61+
62+
var data1 = [[new Date(1498258800000), 10], [new Date(1498345200000), 15], [new Date(1498431600000), 15], [new Date(1498518000000), 15]];
63+
var data2 = [[new Date(1498258800000), 15], [new Date(1498345200000), 20], [new Date(1498431600000), 15], [new Date(1498518000000), 15]];
64+
65+
66+
var itemStyle = {
67+
normal: {
68+
barBorderRadius: 5,
69+
label: {
70+
show: true,
71+
position: 'outside'
72+
}
73+
},
74+
emphasis: {
75+
label: {
76+
position: 'outside'
77+
},
78+
barBorderColor: '#fff',
79+
barBorderWidth: 1,
80+
shadowBlur: 10,
81+
shadowOffsetX: 0,
82+
shadowOffsetY: 0,
83+
shadowColor: 'rgba(0,0,0,0.5)'
84+
}
85+
};
86+
87+
chart.setOption({
88+
backgroundColor: '#eee',
89+
title: {
90+
text: '酒吧在时间轴上',
91+
padding: 20
92+
},
93+
legend: {
94+
left: 150,
95+
inactiveColor: '#abc',
96+
borderWidth: 1,
97+
selected: {
98+
// 'bar': false
99+
},
100+
// orient: 'vertical',
101+
// x: 'right',
102+
// y: 'bottom',
103+
align: 'left',
104+
tooltip: {
105+
show: true
106+
}
107+
108+
},
109+
xAxis: {
110+
type: 'time',
111+
name: '横轴',
112+
},
113+
yAxis: {
114+
// axisLabel: {
115+
// show: false
116+
// },
117+
axisTick: {
118+
show: false
119+
},
120+
splitArea: {
121+
show: false
122+
}
123+
},
124+
series: [{
125+
name: 'bar',
126+
type: 'bar',
127+
data: data1
128+
}, {
129+
name: 'bar2',
130+
type: 'bar',
131+
data: data2
132+
}]
133+
});
134+
135+
chart.on('click', function (params) {
136+
console.log(params);
137+
});
138+
139+
chart.on('legendselectchanged', function (params) {
140+
chart.setOption({
141+
// title: {
142+
// },
143+
graphic: [{
144+
type: 'circle',
145+
shape: {
146+
cx: 100,
147+
cy: 100,
148+
r: 20,
149+
}
150+
}]
151+
});
152+
});
153+
154+
window.onresize = chart.resize;
155+
}
156+
);
157+
</script>
158+
</body>
159+
</html>

0 commit comments

Comments
 (0)