evui 3.3.13 → 3.3.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/evui.common.js +1083 -449
- package/dist/evui.common.js.map +1 -1
- package/dist/evui.umd.js +1083 -449
- package/dist/evui.umd.js.map +1 -1
- package/dist/evui.umd.min.js +1 -1
- package/dist/evui.umd.min.js.map +1 -1
- package/package.json +1 -1
- package/src/components/chart/Chart.vue +23 -3
- package/src/components/chart/chart.core.js +11 -10
- package/src/components/chart/element/element.bar.js +8 -1
- package/src/components/chart/element/element.heatmap.js +108 -10
- package/src/components/chart/element/element.line.js +35 -40
- package/src/components/chart/element/element.pie.js +17 -17
- package/src/components/chart/element/element.tip.js +1 -1
- package/src/components/chart/model/model.store.js +105 -2
- package/src/components/chart/plugins/plugins.interaction.js +107 -24
- package/src/components/chart/plugins/plugins.legend.js +28 -9
- package/src/components/chart/plugins/plugins.tooltip.js +1 -3
- package/src/components/chart/scale/scale.js +13 -3
- package/src/components/chart/scale/scale.step.js +25 -10
- package/src/components/chart/uses.js +13 -1
- package/src/components/grid/Grid.vue +7 -4
- package/src/components/grid/grid.summary.vue +36 -6
- package/src/components/grid/uses.js +4 -1
- package/src/components/treeGrid/TreeGrid.vue +5 -1
- package/src/components/treeGrid/uses.js +4 -1
package/package.json
CHANGED
|
@@ -24,6 +24,10 @@ import { onMounted, onBeforeUnmount, watch, onDeactivated } from 'vue';
|
|
|
24
24
|
type: Object,
|
|
25
25
|
default: null,
|
|
26
26
|
},
|
|
27
|
+
selectedSeries: {
|
|
28
|
+
type: Object,
|
|
29
|
+
default: null,
|
|
30
|
+
},
|
|
27
31
|
options: {
|
|
28
32
|
type: Object,
|
|
29
33
|
default: () => ({}),
|
|
@@ -43,6 +47,7 @@ import { onMounted, onBeforeUnmount, watch, onDeactivated } from 'vue';
|
|
|
43
47
|
'drag-select',
|
|
44
48
|
'update:selectedItem',
|
|
45
49
|
'update:selectedLabel',
|
|
50
|
+
'update:selectedSeries',
|
|
46
51
|
],
|
|
47
52
|
setup(props) {
|
|
48
53
|
let evChart = {};
|
|
@@ -52,6 +57,7 @@ import { onMounted, onBeforeUnmount, watch, onDeactivated } from 'vue';
|
|
|
52
57
|
eventListeners,
|
|
53
58
|
selectItemInfo,
|
|
54
59
|
selectLabelInfo,
|
|
60
|
+
selectSeriesInfo,
|
|
55
61
|
getNormalizedData,
|
|
56
62
|
getNormalizedOptions,
|
|
57
63
|
} = useModel();
|
|
@@ -67,13 +73,20 @@ import { onMounted, onBeforeUnmount, watch, onDeactivated } from 'vue';
|
|
|
67
73
|
);
|
|
68
74
|
|
|
69
75
|
const createChart = () => {
|
|
76
|
+
let selected;
|
|
77
|
+
if (normalizedOptions.selectLabel.use) {
|
|
78
|
+
selected = selectLabelInfo;
|
|
79
|
+
} else if (normalizedOptions.selectSeries.use) {
|
|
80
|
+
selected = selectSeriesInfo;
|
|
81
|
+
}
|
|
82
|
+
|
|
70
83
|
evChart = new EvChart(
|
|
71
84
|
wrapper.value,
|
|
72
85
|
normalizedData,
|
|
73
86
|
normalizedOptions,
|
|
74
87
|
eventListeners,
|
|
75
88
|
selectItemInfo,
|
|
76
|
-
|
|
89
|
+
selected,
|
|
77
90
|
);
|
|
78
91
|
};
|
|
79
92
|
|
|
@@ -100,7 +113,8 @@ import { onMounted, onBeforeUnmount, watch, onDeactivated } from 'vue';
|
|
|
100
113
|
await watch(() => props.data, (chartData) => {
|
|
101
114
|
const newData = getNormalizedData(chartData);
|
|
102
115
|
const isUpdateSeries = !isEqual(newData.series, evChart.data.series)
|
|
103
|
-
|| !isEqual(newData.groups, evChart.data.groups)
|
|
116
|
+
|| !isEqual(newData.groups, evChart.data.groups)
|
|
117
|
+
|| props.options.type === 'heatMap';
|
|
104
118
|
evChart.data = cloneDeep(newData);
|
|
105
119
|
evChart.update({
|
|
106
120
|
updateSeries: isUpdateSeries,
|
|
@@ -115,7 +129,13 @@ import { onMounted, onBeforeUnmount, watch, onDeactivated } from 'vue';
|
|
|
115
129
|
|
|
116
130
|
await watch(() => props.selectedLabel, (newValue) => {
|
|
117
131
|
if (newValue.dataIndex) {
|
|
118
|
-
evChart.
|
|
132
|
+
evChart.renderWithSelected(newValue.dataIndex);
|
|
133
|
+
}
|
|
134
|
+
}, { deep: true });
|
|
135
|
+
|
|
136
|
+
await watch(() => props.selectedSeries, (newValue) => {
|
|
137
|
+
if (newValue.seriesId) {
|
|
138
|
+
evChart.renderWithSelected(newValue.seriesId);
|
|
119
139
|
}
|
|
120
140
|
}, { deep: true });
|
|
121
141
|
});
|
|
@@ -14,7 +14,7 @@ import Pie from './plugins/plugins.pie';
|
|
|
14
14
|
import Tip from './element/element.tip';
|
|
15
15
|
|
|
16
16
|
class EvChart {
|
|
17
|
-
constructor(target, data, options, listeners, defaultSelectItemInfo,
|
|
17
|
+
constructor(target, data, options, listeners, defaultSelectItemInfo, defaultSelectInfo) {
|
|
18
18
|
Object.keys(Model).forEach(key => Object.assign(this, Model[key]));
|
|
19
19
|
Object.assign(this, Title);
|
|
20
20
|
Object.assign(this, Legend);
|
|
@@ -66,7 +66,7 @@ class EvChart {
|
|
|
66
66
|
};
|
|
67
67
|
|
|
68
68
|
this.defaultSelectItemInfo = defaultSelectItemInfo;
|
|
69
|
-
this.
|
|
69
|
+
this.defaultSelectInfo = defaultSelectInfo;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
/**
|
|
@@ -93,7 +93,7 @@ class EvChart {
|
|
|
93
93
|
|
|
94
94
|
this.axesRange = this.getAxesRange();
|
|
95
95
|
this.labelOffset = this.getLabelOffset();
|
|
96
|
-
this.
|
|
96
|
+
this.initSelectedInfo();
|
|
97
97
|
|
|
98
98
|
this.drawChart();
|
|
99
99
|
|
|
@@ -153,7 +153,7 @@ class EvChart {
|
|
|
153
153
|
* @returns {undefined}
|
|
154
154
|
*/
|
|
155
155
|
drawSeries(hitInfo) {
|
|
156
|
-
const { maxTip, selectLabel, selectItem } = this.options;
|
|
156
|
+
const { maxTip, selectLabel, selectItem, selectSeries } = this.options;
|
|
157
157
|
|
|
158
158
|
const opt = {
|
|
159
159
|
ctx: this.bufferCtx,
|
|
@@ -161,7 +161,8 @@ class EvChart {
|
|
|
161
161
|
labelOffset: this.labelOffset,
|
|
162
162
|
axesSteps: this.axesSteps,
|
|
163
163
|
maxTipOpt: { background: maxTip.background, color: maxTip.color },
|
|
164
|
-
selectLabel: { option: selectLabel, selected: this.
|
|
164
|
+
selectLabel: { option: selectLabel, selected: this.defaultSelectInfo },
|
|
165
|
+
selectSeries: { option: selectSeries, selected: this.defaultSelectInfo },
|
|
165
166
|
};
|
|
166
167
|
|
|
167
168
|
let showIndex = 0;
|
|
@@ -188,8 +189,8 @@ class EvChart {
|
|
|
188
189
|
break;
|
|
189
190
|
}
|
|
190
191
|
case 'bar': {
|
|
191
|
-
const { thickness, borderRadius } = this.options;
|
|
192
|
-
series.draw({ thickness, borderRadius, showSeriesCount, showIndex, ...opt });
|
|
192
|
+
const { thickness, cPadRatio, borderRadius } = this.options;
|
|
193
|
+
series.draw({ thickness, cPadRatio, borderRadius, showSeriesCount, showIndex, ...opt });
|
|
193
194
|
if (series.show) {
|
|
194
195
|
showIndex++;
|
|
195
196
|
}
|
|
@@ -331,7 +332,7 @@ class EvChart {
|
|
|
331
332
|
this.labelOffset,
|
|
332
333
|
this.axesSteps.x[index],
|
|
333
334
|
hitInfo,
|
|
334
|
-
this.
|
|
335
|
+
this.defaultSelectInfo);
|
|
335
336
|
});
|
|
336
337
|
|
|
337
338
|
this.axesY.forEach((axis, index) => {
|
|
@@ -340,7 +341,7 @@ class EvChart {
|
|
|
340
341
|
this.labelOffset,
|
|
341
342
|
this.axesSteps.y[index],
|
|
342
343
|
hitInfo,
|
|
343
|
-
this.
|
|
344
|
+
this.defaultSelectInfo);
|
|
344
345
|
});
|
|
345
346
|
}
|
|
346
347
|
|
|
@@ -660,7 +661,7 @@ class EvChart {
|
|
|
660
661
|
this.axesY = this.createAxes('y', options.axesY);
|
|
661
662
|
this.axesRange = this.getAxesRange();
|
|
662
663
|
this.labelOffset = this.getLabelOffset();
|
|
663
|
-
this.
|
|
664
|
+
this.initSelectedInfo();
|
|
664
665
|
|
|
665
666
|
this.render(updateInfo?.hitInfo);
|
|
666
667
|
|
|
@@ -67,7 +67,14 @@ class Bar {
|
|
|
67
67
|
|
|
68
68
|
const dArea = isHorizontal ? yArea : xArea;
|
|
69
69
|
const cArea = dArea / (this.data.length || 1);
|
|
70
|
-
|
|
70
|
+
|
|
71
|
+
let cPad;
|
|
72
|
+
const isUnableToDrawCategoryPadding = param.cPadRatio >= 1 || param.cPadRatio <= 0;
|
|
73
|
+
if (isUnableToDrawCategoryPadding) {
|
|
74
|
+
cPad = 2;
|
|
75
|
+
} else {
|
|
76
|
+
cPad = Math.max((dArea * (param.cPadRatio / 2)) / this.data.length, 2);
|
|
77
|
+
}
|
|
71
78
|
|
|
72
79
|
let bArea;
|
|
73
80
|
let w;
|
|
@@ -77,8 +77,8 @@ class HeatMap {
|
|
|
77
77
|
drawItem(ctx, x, y, w, h) {
|
|
78
78
|
ctx.beginPath();
|
|
79
79
|
if (this.stroke.show) {
|
|
80
|
-
ctx.fillRect(x, y, w, h);
|
|
81
80
|
ctx.strokeRect(x, y, w, h);
|
|
81
|
+
ctx.fillRect(x, y, w, h);
|
|
82
82
|
} else {
|
|
83
83
|
const aliasPixel = Util.aliasPixel(1);
|
|
84
84
|
ctx.fillRect(
|
|
@@ -148,8 +148,11 @@ class HeatMap {
|
|
|
148
148
|
if (this.colorAxis[colorIndex].show) {
|
|
149
149
|
ctx.fillStyle = Util.colorStringToRgba(item.dataColor, opacity);
|
|
150
150
|
if (this.stroke.show) {
|
|
151
|
-
const { color, lineWidth } = this.stroke;
|
|
152
|
-
ctx.strokeStyle = Util.colorStringToRgba(
|
|
151
|
+
const { color, lineWidth, opacity: sOpacity } = this.stroke;
|
|
152
|
+
ctx.strokeStyle = Util.colorStringToRgba(
|
|
153
|
+
color,
|
|
154
|
+
opacity === 1 ? sOpacity : opacity,
|
|
155
|
+
);
|
|
153
156
|
ctx.lineWidth = lineWidth;
|
|
154
157
|
xp += (lineWidth * 1.5);
|
|
155
158
|
yp += (lineWidth * 1.5);
|
|
@@ -216,7 +219,7 @@ class HeatMap {
|
|
|
216
219
|
const centerX = x + (w / 2);
|
|
217
220
|
const centerY = y + (h / 2);
|
|
218
221
|
|
|
219
|
-
if (vw >= w || formattedTxt < 0) {
|
|
222
|
+
if (vw >= w || vh >= h || formattedTxt < 0) {
|
|
220
223
|
return;
|
|
221
224
|
}
|
|
222
225
|
|
|
@@ -267,13 +270,10 @@ class HeatMap {
|
|
|
267
270
|
const y1 = yp;
|
|
268
271
|
const y2 = yp + h;
|
|
269
272
|
|
|
270
|
-
return ((x1
|
|
271
|
-
|| ((x1 <= xep && x2 >= xep) && (y1 <= ysp && y2 >= ysp))
|
|
272
|
-
|| ((x1 <= xsp && x2 >= xsp) && (y1 <= yep && y2 >= yep))
|
|
273
|
-
|| ((x1 <= xep && x2 >= xep) && (y1 <= yep && y2 >= yep))
|
|
274
|
-
|| ((x1 >= xsp && x1 <= xep) && (y1 >= ysp && y1 <= yep))
|
|
273
|
+
return ((x1 >= xsp && x1 <= xep) && (y1 >= ysp && y1 <= yep))
|
|
275
274
|
|| ((x1 >= xsp && x1 <= xep) && (y2 >= ysp && y2 <= yep))
|
|
276
|
-
|| ((x2 >= xsp && x2 <= xep) && (y1 >= ysp && y1 <= yep))
|
|
275
|
+
|| ((x2 >= xsp && x2 <= xep) && (y1 >= ysp && y1 <= yep))
|
|
276
|
+
|| ((x2 >= xsp && x2 <= xep) && (y2 >= ysp && y2 <= yep));
|
|
277
277
|
});
|
|
278
278
|
}
|
|
279
279
|
|
|
@@ -352,6 +352,104 @@ class HeatMap {
|
|
|
352
352
|
|
|
353
353
|
return item;
|
|
354
354
|
}
|
|
355
|
+
|
|
356
|
+
findBlockRange({ xcp, xep, ycp, yep, range }) {
|
|
357
|
+
const labels = this.labels;
|
|
358
|
+
|
|
359
|
+
const blockRange = {
|
|
360
|
+
xsp: Math.min(xcp, xep),
|
|
361
|
+
ysp: Math.min(ycp, yep),
|
|
362
|
+
width: Math.ceil(Math.abs(xep - xcp)),
|
|
363
|
+
height: Math.ceil(Math.abs(yep - ycp)),
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
if (labels.x.length && labels.y.length) {
|
|
367
|
+
const { x1, x2, y1, y2 } = range;
|
|
368
|
+
const gapX = (x2 - x1) / labels.x.length;
|
|
369
|
+
const gapY = (y2 - y1) / labels.y.length;
|
|
370
|
+
|
|
371
|
+
const point = {
|
|
372
|
+
xsp: xcp,
|
|
373
|
+
xep,
|
|
374
|
+
ysp: ycp,
|
|
375
|
+
yep,
|
|
376
|
+
};
|
|
377
|
+
|
|
378
|
+
const setPoint = (dir, target, key) => {
|
|
379
|
+
let itemPoint;
|
|
380
|
+
let gap;
|
|
381
|
+
let startPoint;
|
|
382
|
+
|
|
383
|
+
if (dir === 'x') {
|
|
384
|
+
gap = gapX;
|
|
385
|
+
startPoint = x1;
|
|
386
|
+
} else {
|
|
387
|
+
gap = gapY;
|
|
388
|
+
startPoint = y1;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
const findItem = labels[dir].findIndex((item, index) => {
|
|
392
|
+
itemPoint = Math.round(startPoint + (gap * index)) + Util.aliasPixel(1);
|
|
393
|
+
return itemPoint <= target && target <= itemPoint + gap;
|
|
394
|
+
});
|
|
395
|
+
|
|
396
|
+
if (findItem > -1) {
|
|
397
|
+
point[key] = ['xsp', 'ysp'].includes(key) ? itemPoint : itemPoint + gap;
|
|
398
|
+
}
|
|
399
|
+
};
|
|
400
|
+
|
|
401
|
+
setPoint('x', Math.min(xcp, xep), 'xsp');
|
|
402
|
+
setPoint('x', Math.max(xcp, xep), 'xep');
|
|
403
|
+
setPoint('y', Math.min(ycp, yep), 'ysp');
|
|
404
|
+
setPoint('y', Math.max(ycp, yep), 'yep');
|
|
405
|
+
|
|
406
|
+
blockRange.xsp = Math.min(point.xsp, point.xep);
|
|
407
|
+
blockRange.ysp = Math.min(point.ysp, point.yep);
|
|
408
|
+
blockRange.width = Math.abs(point.xep - point.xsp);
|
|
409
|
+
blockRange.height = Math.abs(point.yep - point.ysp);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
return blockRange;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
findSelectionRange(rangeInfo) {
|
|
416
|
+
const { xcp, ycp, width, height, range } = rangeInfo;
|
|
417
|
+
|
|
418
|
+
let selectionRange = null;
|
|
419
|
+
|
|
420
|
+
const { x1, x2, y1, y2 } = range;
|
|
421
|
+
const { x: labelX, y: labelY } = this.labels;
|
|
422
|
+
|
|
423
|
+
if (labelX.length && labelY.length) {
|
|
424
|
+
const gapX = (x2 - x1) / labelX.length;
|
|
425
|
+
const gapY = (y2 - y1) / labelY.length;
|
|
426
|
+
|
|
427
|
+
const xsp = xcp;
|
|
428
|
+
const xep = xcp + width;
|
|
429
|
+
const ysp = ycp;
|
|
430
|
+
const yep = ycp + height;
|
|
431
|
+
|
|
432
|
+
const xIndex = {
|
|
433
|
+
min: Math.floor((xsp - x1) / gapX),
|
|
434
|
+
max: Math.floor((xep - x1 - gapX) / gapX),
|
|
435
|
+
};
|
|
436
|
+
|
|
437
|
+
const lastIndexY = labelY.length - 1;
|
|
438
|
+
const yIndex = {
|
|
439
|
+
min: lastIndexY - Math.floor((yep - y1 - gapY) / gapY),
|
|
440
|
+
max: lastIndexY - Math.floor((ysp - y1) / gapY),
|
|
441
|
+
};
|
|
442
|
+
|
|
443
|
+
selectionRange = {
|
|
444
|
+
xMin: labelX[xIndex.min],
|
|
445
|
+
xMax: labelX[xIndex.max],
|
|
446
|
+
yMin: labelY[yIndex.min],
|
|
447
|
+
yMax: labelY[yIndex.max],
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
return selectionRange;
|
|
452
|
+
}
|
|
355
453
|
}
|
|
356
454
|
|
|
357
455
|
export default HeatMap;
|
|
@@ -102,7 +102,8 @@ class Line {
|
|
|
102
102
|
const getXPos = val => Canvas.calculateX(val, minmaxX.graphMin, minmaxX.graphMax, xArea, xsp);
|
|
103
103
|
const getYPos = val => Canvas.calculateY(val, minmaxY.graphMin, minmaxY.graphMax, yArea, ysp);
|
|
104
104
|
|
|
105
|
-
|
|
105
|
+
// draw line
|
|
106
|
+
this.data.reduce((prev, curr, ix) => {
|
|
106
107
|
x = getXPos(curr.x);
|
|
107
108
|
y = getYPos(curr.y);
|
|
108
109
|
|
|
@@ -110,22 +111,12 @@ class Line {
|
|
|
110
111
|
x += Util.aliasPixel(x);
|
|
111
112
|
}
|
|
112
113
|
|
|
113
|
-
if (
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
if (this.fill && prev.y !== null && !this.stackIndex) {
|
|
117
|
-
ctx.stroke();
|
|
118
|
-
ctx.lineTo(prev.xp, endPoint);
|
|
119
|
-
ctx.lineTo(item[startFillIndex].xp, endPoint);
|
|
120
|
-
|
|
121
|
-
ctx.fill();
|
|
122
|
-
ctx.beginPath();
|
|
123
|
-
}
|
|
124
|
-
}
|
|
114
|
+
if (ix === 0) {
|
|
115
|
+
ctx.moveTo(x, y);
|
|
116
|
+
}
|
|
125
117
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|| prev.x === null || curr.x === null) {
|
|
118
|
+
const isNullValue = prev.y === null || curr.y === null || prev.x === null || curr.x === null;
|
|
119
|
+
if (isNullValue) {
|
|
129
120
|
ctx.moveTo(x, y);
|
|
130
121
|
} else {
|
|
131
122
|
ctx.lineTo(x, y);
|
|
@@ -139,41 +130,45 @@ class Line {
|
|
|
139
130
|
|
|
140
131
|
ctx.stroke();
|
|
141
132
|
|
|
142
|
-
|
|
133
|
+
// draw fill
|
|
134
|
+
if (this.fill && this.data.length) {
|
|
135
|
+
ctx.beginPath();
|
|
143
136
|
|
|
144
|
-
if (this.fill && dataLen) {
|
|
145
137
|
ctx.fillStyle = Util.colorStringToRgba(mainColor, fillOpacity);
|
|
146
138
|
|
|
147
|
-
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
|
|
139
|
+
this.data.forEach((currData, ix) => {
|
|
140
|
+
const isEmptyPoint = data => data?.x === null || data?.y === null
|
|
141
|
+
|| data?.x === undefined || data?.y === undefined;
|
|
142
|
+
|
|
143
|
+
const nextData = this.data[ix + 1];
|
|
144
|
+
|
|
145
|
+
if (isEmptyPoint(currData)) {
|
|
146
|
+
startFillIndex = ix + 1;
|
|
151
147
|
|
|
152
|
-
|
|
153
|
-
|
|
148
|
+
if (!isEmptyPoint(nextData)) {
|
|
149
|
+
ctx.moveTo(nextData.xp, nextData.yp);
|
|
150
|
+
}
|
|
154
151
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
if (prev && prev.o == null) {
|
|
158
|
-
ctx.moveTo(x, getYPos(curr.b + curr.o));
|
|
159
|
-
}
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
160
154
|
|
|
161
|
-
|
|
155
|
+
ctx.lineTo(currData.xp, currData.yp);
|
|
162
156
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
157
|
+
if (isEmptyPoint(nextData)) {
|
|
158
|
+
for (let jx = ix; jx >= startFillIndex; jx--) {
|
|
159
|
+
const prevData = this.data[jx];
|
|
160
|
+
const xp = prevData.xp;
|
|
161
|
+
const bp = getYPos(prevData.b) ?? endPoint;
|
|
162
|
+
ctx.lineTo(xp, bp);
|
|
168
163
|
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
}
|
|
164
|
+
|
|
165
|
+
ctx.closePath();
|
|
166
|
+
}
|
|
167
|
+
});
|
|
174
168
|
|
|
175
169
|
ctx.fill();
|
|
176
170
|
}
|
|
171
|
+
|
|
177
172
|
if (this.point || isExistSelectedLabel) {
|
|
178
173
|
ctx.strokeStyle = Util.colorStringToRgba(mainColor, mainColorOpacity);
|
|
179
174
|
const focusStyle = Util.colorStringToRgba(pointFillColor, 1);
|
|
@@ -45,7 +45,6 @@ class Pie {
|
|
|
45
45
|
const slice = new Path2D();
|
|
46
46
|
|
|
47
47
|
const radius = this.isSelect ? this.radius + 5 : this.radius;
|
|
48
|
-
const doughnutHoleRadius = this.radius * this.doughnutHoleSize;
|
|
49
48
|
|
|
50
49
|
const color = this.color;
|
|
51
50
|
const noneDownplayOpacity = color.includes('rgba') ? Util.getOpacity(color) : 1;
|
|
@@ -66,7 +65,7 @@ class Pie {
|
|
|
66
65
|
}
|
|
67
66
|
|
|
68
67
|
if (this.showValue?.use) {
|
|
69
|
-
this.drawValueLabels(ctx
|
|
68
|
+
this.drawValueLabels(ctx);
|
|
70
69
|
}
|
|
71
70
|
|
|
72
71
|
ctx.closePath();
|
|
@@ -115,7 +114,6 @@ class Pie {
|
|
|
115
114
|
itemHighlight(item, context) {
|
|
116
115
|
const ctx = context;
|
|
117
116
|
const radius = this.isSelect ? this.radius + 5 : this.radius;
|
|
118
|
-
const doughnutHoleRadius = this.radius * this.doughnutHoleSize;
|
|
119
117
|
|
|
120
118
|
ctx.save();
|
|
121
119
|
ctx.shadowOffsetX = 0;
|
|
@@ -133,7 +131,7 @@ class Pie {
|
|
|
133
131
|
ctx.fill();
|
|
134
132
|
|
|
135
133
|
if (this.showValue?.use) {
|
|
136
|
-
this.drawValueLabels(ctx
|
|
134
|
+
this.drawValueLabels(ctx);
|
|
137
135
|
}
|
|
138
136
|
|
|
139
137
|
ctx.closePath();
|
|
@@ -146,19 +144,9 @@ class Pie {
|
|
|
146
144
|
* @param context canvas context
|
|
147
145
|
*/
|
|
148
146
|
drawValueLabels(context) {
|
|
149
|
-
const { fontSize, textColor, formatter } = this.showValue;
|
|
150
147
|
const ctx = context;
|
|
151
|
-
|
|
152
|
-
ctx.save();
|
|
153
|
-
ctx.beginPath();
|
|
154
|
-
|
|
155
|
-
ctx.font = `normal normal normal ${fontSize}px Roboto`;
|
|
156
|
-
ctx.fillStyle = textColor;
|
|
157
|
-
ctx.lineWidth = 1;
|
|
158
|
-
ctx.textAlign = 'center';
|
|
159
|
-
ctx.textBaseline = 'middle';
|
|
160
|
-
|
|
161
148
|
const value = this.data.o;
|
|
149
|
+
const { fontSize, textColor, formatter } = this.showValue;
|
|
162
150
|
|
|
163
151
|
let formattedTxt;
|
|
164
152
|
if (formatter) {
|
|
@@ -180,15 +168,27 @@ class Pie {
|
|
|
180
168
|
&& radius >= valueWidth * ratio
|
|
181
169
|
&& radius >= valueHeight * ratio
|
|
182
170
|
) {
|
|
171
|
+
ctx.save();
|
|
172
|
+
ctx.beginPath();
|
|
173
|
+
|
|
174
|
+
const noneDownplayOpacity = textColor.includes('rgba') ? Util.getOpacity(textColor) : 1;
|
|
175
|
+
const opacity = this.state === 'downplay' ? 0.1 : noneDownplayOpacity;
|
|
176
|
+
|
|
177
|
+
ctx.font = `normal normal normal ${fontSize}px Roboto`;
|
|
178
|
+
ctx.fillStyle = Util.colorStringToRgba(textColor, opacity);
|
|
179
|
+
ctx.lineWidth = 1;
|
|
180
|
+
ctx.textAlign = 'center';
|
|
181
|
+
ctx.textBaseline = 'middle';
|
|
182
|
+
|
|
183
183
|
const halfRadius = (radius / 2) + this.doughnutHoleSize;
|
|
184
184
|
const centerAngle = ((this.endAngle - this.startAngle) / 2) + this.startAngle;
|
|
185
185
|
const xPos = halfRadius * Math.cos(centerAngle) + this.centerX;
|
|
186
186
|
const yPos = halfRadius * Math.sin(centerAngle) + this.centerY;
|
|
187
187
|
|
|
188
188
|
ctx.fillText(formattedTxt, xPos, yPos);
|
|
189
|
-
}
|
|
190
189
|
|
|
191
|
-
|
|
190
|
+
ctx.restore();
|
|
191
|
+
}
|
|
192
192
|
}
|
|
193
193
|
}
|
|
194
194
|
|
|
@@ -250,7 +250,7 @@ const modules = {
|
|
|
250
250
|
const opt = this.options;
|
|
251
251
|
const isHorizontal = !!opt.horizontal;
|
|
252
252
|
const labelTipOpt = opt.selectLabel;
|
|
253
|
-
const { dataIndex, data, label } = this.
|
|
253
|
+
const { dataIndex, data, label } = this.defaultSelectInfo;
|
|
254
254
|
let drawTip = false;
|
|
255
255
|
|
|
256
256
|
if (dataIndex.length) {
|
|
@@ -422,14 +422,21 @@ const modules = {
|
|
|
422
422
|
const colorOpt = this.options.heatMapColor;
|
|
423
423
|
const categoryCnt = colorOpt.categoryCnt;
|
|
424
424
|
|
|
425
|
+
let minValue;
|
|
425
426
|
let maxValue = 0;
|
|
427
|
+
|
|
426
428
|
let isExistError = false;
|
|
427
429
|
data.forEach(({ o: value }) => {
|
|
428
430
|
if (maxValue < value) {
|
|
429
|
-
maxValue = value;
|
|
431
|
+
maxValue = Math.max(maxValue, value);
|
|
430
432
|
}
|
|
433
|
+
|
|
431
434
|
if (value < 0) {
|
|
432
435
|
isExistError = true;
|
|
436
|
+
} else if (minValue === undefined) {
|
|
437
|
+
minValue = value;
|
|
438
|
+
} else {
|
|
439
|
+
minValue = Math.min(minValue, value);
|
|
433
440
|
}
|
|
434
441
|
});
|
|
435
442
|
|
|
@@ -443,8 +450,9 @@ const modules = {
|
|
|
443
450
|
}
|
|
444
451
|
|
|
445
452
|
return {
|
|
453
|
+
min: minValue,
|
|
446
454
|
max: maxValue,
|
|
447
|
-
interval: Math.ceil(maxValue / categoryCnt),
|
|
455
|
+
interval: Math.ceil((maxValue - minValue) / categoryCnt),
|
|
448
456
|
existError: isExistError,
|
|
449
457
|
};
|
|
450
458
|
},
|
|
@@ -618,6 +626,101 @@ const modules = {
|
|
|
618
626
|
};
|
|
619
627
|
},
|
|
620
628
|
|
|
629
|
+
/**
|
|
630
|
+
* Find seriesId by position x and y
|
|
631
|
+
* @param {array} offset position x and y
|
|
632
|
+
*
|
|
633
|
+
* @returns {object} clicked series id
|
|
634
|
+
*/
|
|
635
|
+
getSeriesIdByPosition(offset) {
|
|
636
|
+
const [clickedX, clickedY] = offset;
|
|
637
|
+
const chartRect = this.chartRect;
|
|
638
|
+
const labelOffset = this.labelOffset;
|
|
639
|
+
const aPos = {
|
|
640
|
+
x1: chartRect.x1 + labelOffset.left,
|
|
641
|
+
x2: chartRect.x2 - labelOffset.right,
|
|
642
|
+
y1: chartRect.y1 + labelOffset.top,
|
|
643
|
+
y2: chartRect.y2 - labelOffset.bottom,
|
|
644
|
+
};
|
|
645
|
+
const valueAxes = this.axesY[0];
|
|
646
|
+
const labelAxes = this.axesX[0];
|
|
647
|
+
const valueStartPoint = aPos[valueAxes.units.rectStart];
|
|
648
|
+
const valueEndPoint = aPos[valueAxes.units.rectEnd];
|
|
649
|
+
const labelStartPoint = aPos[labelAxes.units.rectStart];
|
|
650
|
+
const labelEndPoint = aPos[labelAxes.units.rectEnd];
|
|
651
|
+
|
|
652
|
+
const result = { sId: null };
|
|
653
|
+
|
|
654
|
+
if (clickedY > valueEndPoint && clickedY < valueStartPoint
|
|
655
|
+
&& clickedX < labelEndPoint && clickedX > labelStartPoint) {
|
|
656
|
+
let hitSeries;
|
|
657
|
+
let positionList;
|
|
658
|
+
const hitItem = this.findHitItem(offset);
|
|
659
|
+
const hitSeriesList = Object.keys(hitItem.items);
|
|
660
|
+
|
|
661
|
+
switch (this.options.type) {
|
|
662
|
+
case 'line': {
|
|
663
|
+
const orderedSeriesList = this.seriesInfo.charts.line;
|
|
664
|
+
const isStackChart = Object.values(this.seriesList).some(({ stackIndex }) => stackIndex);
|
|
665
|
+
|
|
666
|
+
if (hitSeriesList.length) { // 클릭한 위치에 data 가 존재하는 경우
|
|
667
|
+
if (isStackChart) {
|
|
668
|
+
positionList = orderedSeriesList.filter(sId => hitSeriesList.includes(sId))
|
|
669
|
+
.map(sId => ({ sId, position: hitItem.items[sId]?.data?.yp }));
|
|
670
|
+
hitSeries = positionList.find(({ position }) => clickedY > position)?.sId;
|
|
671
|
+
} else {
|
|
672
|
+
hitSeries = Object.entries(hitItem.items).find(([, { hit }]) => hit)?.[0];
|
|
673
|
+
}
|
|
674
|
+
} else { // 클릭한 위치에 data 가 존재하지 않는 경우
|
|
675
|
+
const visibleSeriesList = orderedSeriesList.filter(sId => this.seriesList[sId].show);
|
|
676
|
+
positionList = visibleSeriesList.map(sId => ({
|
|
677
|
+
sId,
|
|
678
|
+
position: this.seriesList[sId].data?.map(({ xp, yp }) => [xp, yp]),
|
|
679
|
+
}));
|
|
680
|
+
const dataIndex = positionList[0].position?.findIndex(([xp]) => xp >= clickedX);
|
|
681
|
+
const vectorList = positionList.map(({ sId, position }) => ({
|
|
682
|
+
sId,
|
|
683
|
+
vector: { start: position[dataIndex - 1], end: position[dataIndex] },
|
|
684
|
+
}));
|
|
685
|
+
|
|
686
|
+
// canvas 의 클릭 위치값은 제 4 사분면의 위치이므로 clickedY, y1, y2 의 값은 음수를 취한다.
|
|
687
|
+
if (isStackChart) {
|
|
688
|
+
hitSeries = vectorList.find(({ vector }) => {
|
|
689
|
+
const [x1, y1] = vector.start;
|
|
690
|
+
const [x2, y2] = vector.end;
|
|
691
|
+
const v1 = [x2 - x1, y1 - y2];
|
|
692
|
+
const v2 = [x2 - clickedX, clickedY - y2];
|
|
693
|
+
const xp = v1[0] * v2[1] - v1[1] * v2[0];
|
|
694
|
+
|
|
695
|
+
return vector.start.every(v => typeof v === 'number')
|
|
696
|
+
&& vector.end.every(v => typeof v === 'number')
|
|
697
|
+
&& xp > 0;
|
|
698
|
+
})?.sId;
|
|
699
|
+
} else {
|
|
700
|
+
hitSeries = vectorList.find(({ vector }) => {
|
|
701
|
+
const [x1, y1] = vector.start;
|
|
702
|
+
const [x2, y2] = vector.end;
|
|
703
|
+
const a = (y1 - y2) / (x2 - x1);
|
|
704
|
+
const b = -1;
|
|
705
|
+
const c = -y1 - a * x1;
|
|
706
|
+
const distance = Math.abs(a * clickedX - b * clickedY + c)
|
|
707
|
+
/ Math.sqrt(a ** 2 + b ** 2);
|
|
708
|
+
|
|
709
|
+
return distance < 3;
|
|
710
|
+
})?.sId;
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
break;
|
|
714
|
+
}
|
|
715
|
+
default:
|
|
716
|
+
break;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
result.sId = hitSeries;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
return result;
|
|
723
|
+
},
|
|
621
724
|
/**
|
|
622
725
|
* Find label info by position x and y
|
|
623
726
|
* @param {array} offset position x and y
|