evui 3.3.9 → 3.3.12
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 +3546 -973
- package/dist/evui.common.js.map +1 -1
- package/dist/evui.umd.js +3546 -973
- 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 +15 -6
- package/src/components/chart/chart.core.js +86 -31
- package/src/components/chart/element/element.bar.js +7 -1
- package/src/components/chart/element/element.heatmap.js +213 -0
- package/src/components/chart/element/element.line.js +20 -9
- package/src/components/chart/element/element.pie.js +13 -5
- package/src/components/chart/element/element.scatter.js +26 -9
- package/src/components/chart/element/element.tip.js +154 -13
- package/src/components/chart/helpers/helpers.constant.js +15 -0
- package/src/components/chart/model/model.series.js +4 -0
- package/src/components/chart/model/model.store.js +160 -2
- package/src/components/chart/plugins/plugins.interaction.js +82 -10
- package/src/components/chart/plugins/plugins.legend.js +213 -42
- package/src/components/chart/plugins/plugins.tooltip.js +249 -6
- package/src/components/chart/scale/scale.js +9 -0
- package/src/components/chart/scale/scale.step.js +20 -5
- package/src/components/chart/scale/scale.time.category.js +20 -2
- package/src/components/chart/uses.js +20 -3
- package/src/components/grid/Grid.vue +276 -132
- package/src/components/grid/grid.filter.window.vue +1 -0
- package/src/components/grid/grid.pagination.vue +75 -0
- package/src/components/grid/grid.summary.vue +235 -0
- package/src/components/grid/style/grid.scss +0 -14
- package/src/components/grid/uses.js +158 -79
- package/src/components/pagination/Pagination.vue +20 -17
- package/src/components/treeGrid/TreeGrid.vue +253 -34
- package/src/components/treeGrid/TreeGridNode.vue +8 -9
- package/src/components/treeGrid/uses.js +152 -37
|
@@ -30,12 +30,20 @@ const modules = {
|
|
|
30
30
|
* @returns {undefined}
|
|
31
31
|
*/
|
|
32
32
|
initLegend() {
|
|
33
|
+
this.isHeatMapType = this.options.type === 'heatMap';
|
|
33
34
|
if (!this.isInitLegend) {
|
|
34
35
|
this.createLegendLayout();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (this.isHeatMapType) {
|
|
39
|
+
this.initEventForColorLegend();
|
|
40
|
+
this.addColorLegendList();
|
|
41
|
+
} else {
|
|
35
42
|
this.initEvent();
|
|
43
|
+
this.addLegendList();
|
|
36
44
|
}
|
|
45
|
+
this.initResizeEvent();
|
|
37
46
|
|
|
38
|
-
this.addLegendList();
|
|
39
47
|
this.isInitLegend = true;
|
|
40
48
|
this.isLegendMove = false;
|
|
41
49
|
},
|
|
@@ -66,12 +74,36 @@ const modules = {
|
|
|
66
74
|
});
|
|
67
75
|
},
|
|
68
76
|
|
|
77
|
+
addColorLegendList() {
|
|
78
|
+
const seriesList = this.seriesList;
|
|
79
|
+
|
|
80
|
+
Object.values(seriesList).forEach((series) => {
|
|
81
|
+
if (!series.isExistGrp && series.showLegend) {
|
|
82
|
+
const { colorAxis, valueOpt } = series;
|
|
83
|
+
colorAxis.forEach((colorItem, index) => {
|
|
84
|
+
const maxValue = valueOpt.interval * (index + 1);
|
|
85
|
+
const minValue = maxValue - valueOpt.interval;
|
|
86
|
+
const name = valueOpt.existError && index === colorAxis.length - 1
|
|
87
|
+
? 'error' : `${minValue} - ${maxValue}`;
|
|
88
|
+
this.addLegend({
|
|
89
|
+
cId: colorItem.id,
|
|
90
|
+
color: colorItem.value,
|
|
91
|
+
name,
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
},
|
|
97
|
+
|
|
69
98
|
/**
|
|
70
99
|
* Initialize legend event
|
|
71
100
|
*
|
|
72
101
|
* @returns {undefined}
|
|
73
102
|
*/
|
|
74
103
|
initEvent() {
|
|
104
|
+
if (this.isInitLegend) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
75
107
|
/**
|
|
76
108
|
* callback for legendBoxDOM to show/hide clicked series
|
|
77
109
|
*
|
|
@@ -106,13 +138,24 @@ const modules = {
|
|
|
106
138
|
if (isActive) {
|
|
107
139
|
this.seriesInfo.count--;
|
|
108
140
|
colorDOM.style.backgroundColor = opt.inactive;
|
|
141
|
+
colorDOM.style.borderColor = opt.inactive;
|
|
109
142
|
nameDOM.style.color = opt.inactive;
|
|
110
143
|
} else {
|
|
111
144
|
this.seriesInfo.count++;
|
|
145
|
+
|
|
146
|
+
let seriesColor;
|
|
112
147
|
if (typeof series.color !== 'string') {
|
|
113
|
-
|
|
148
|
+
seriesColor = series.color[series.color.length - 1][1];
|
|
149
|
+
} else {
|
|
150
|
+
seriesColor = series.color;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (series.type === 'line' && series.fill) {
|
|
154
|
+
colorDOM.style.height = '8px';
|
|
155
|
+
colorDOM.style.backgroundColor = `${seriesColor}80`;
|
|
156
|
+
colorDOM.style.border = `1px solid ${seriesColor}`;
|
|
114
157
|
} else {
|
|
115
|
-
colorDOM.style.backgroundColor =
|
|
158
|
+
colorDOM.style.backgroundColor = seriesColor;
|
|
116
159
|
}
|
|
117
160
|
|
|
118
161
|
nameDOM.style.color = opt.color;
|
|
@@ -129,44 +172,117 @@ const modules = {
|
|
|
129
172
|
};
|
|
130
173
|
|
|
131
174
|
/**
|
|
132
|
-
* callback for
|
|
133
|
-
* 1. hide resizeDOM
|
|
134
|
-
* 2. show ghost DOM on same position with hidden resizeDOM
|
|
175
|
+
* callback for legendBoxDOM hovering
|
|
135
176
|
*
|
|
136
177
|
* @returns {undefined}
|
|
137
178
|
*/
|
|
138
|
-
this.
|
|
139
|
-
e.
|
|
140
|
-
e.preventDefault();
|
|
179
|
+
this.onLegendBoxOver = (e) => {
|
|
180
|
+
const type = e.target.dataset.type;
|
|
141
181
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
182
|
+
let targetDOM;
|
|
183
|
+
if (type === 'container') {
|
|
184
|
+
targetDOM = e.target;
|
|
185
|
+
} else if (type === 'name' || type === 'color') {
|
|
186
|
+
targetDOM = e.target.parentElement;
|
|
187
|
+
} else {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
const nameDOM = targetDOM.getElementsByClassName('ev-chart-legend-name')[0];
|
|
191
|
+
const targetId = nameDOM.series.sId;
|
|
145
192
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
193
|
+
Object.values(this.seriesList).forEach((series) => {
|
|
194
|
+
series.state = series.sId === targetId ? 'highlight' : 'downplay';
|
|
195
|
+
});
|
|
149
196
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
197
|
+
this.update({
|
|
198
|
+
updateSeries: false,
|
|
199
|
+
updateSelTip: { update: false, keepDomain: false },
|
|
200
|
+
hitInfo: { sId: targetId },
|
|
201
|
+
});
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* callback for mouseleave event on legendBoxDOM
|
|
206
|
+
*
|
|
207
|
+
* @returns {undefined}
|
|
208
|
+
*/
|
|
209
|
+
this.onLegendBoxLeave = () => {
|
|
210
|
+
Object.values(this.seriesList).forEach((series) => {
|
|
211
|
+
series.state = 'normal';
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
this.update({
|
|
215
|
+
updateSeries: false,
|
|
216
|
+
updateSelTip: { update: false, keepDomain: false },
|
|
217
|
+
});
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
this.legendBoxDOM.addEventListener('click', this.onLegendBoxClick);
|
|
221
|
+
this.legendBoxDOM.addEventListener('mouseover', this.onLegendBoxOver);
|
|
222
|
+
this.legendBoxDOM.addEventListener('mouseleave', this.onLegendBoxLeave);
|
|
223
|
+
|
|
224
|
+
this.initResizeEvent();
|
|
225
|
+
},
|
|
226
|
+
|
|
227
|
+
initEventForColorLegend() {
|
|
228
|
+
if (this.isInitLegend) {
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* callback for legendBoxDOM to show/hide clicked series
|
|
233
|
+
*
|
|
234
|
+
* @returns {undefined}
|
|
235
|
+
*/
|
|
236
|
+
this.onLegendBoxClick = (e) => {
|
|
237
|
+
const opt = this.options.legend;
|
|
238
|
+
const series = Object.values(this.seriesList)[0];
|
|
239
|
+
const type = e.target.dataset.type;
|
|
240
|
+
|
|
241
|
+
let targetDOM;
|
|
242
|
+
if (type === 'container') {
|
|
243
|
+
targetDOM = e.target;
|
|
244
|
+
} else if (type === 'name' || type === 'color') {
|
|
245
|
+
targetDOM = e.target.parentElement;
|
|
156
246
|
} else {
|
|
157
|
-
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
158
249
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
250
|
+
const colorDOM = targetDOM?.getElementsByClassName('ev-chart-legend-color')[0];
|
|
251
|
+
const nameDOM = targetDOM?.getElementsByClassName('ev-chart-legend-name')[0];
|
|
252
|
+
const isActive = !colorDOM?.className.includes('inactive');
|
|
253
|
+
const targetId = nameDOM.series.cId;
|
|
254
|
+
const activeCount = series.colorAxis.filter(colorItem => colorItem.show).length;
|
|
255
|
+
|
|
256
|
+
if (isActive && activeCount === 1) {
|
|
257
|
+
return;
|
|
164
258
|
}
|
|
165
259
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
260
|
+
if (!colorDOM || !nameDOM) {
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if (isActive) {
|
|
265
|
+
colorDOM.style.backgroundColor = opt.inactive;
|
|
266
|
+
colorDOM.style.borderColor = opt.inactive;
|
|
267
|
+
nameDOM.style.color = opt.inactive;
|
|
268
|
+
} else {
|
|
269
|
+
colorDOM.style.backgroundColor = nameDOM.series.color;
|
|
270
|
+
nameDOM.style.color = opt.color;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const targetIndex = series.colorAxis.findIndex(colorItem => colorItem.id === targetId);
|
|
274
|
+
if (targetIndex > -1) {
|
|
275
|
+
series.colorAxis[targetIndex].show = !isActive;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
colorDOM.classList.toggle('inactive');
|
|
279
|
+
nameDOM.classList.toggle('inactive');
|
|
169
280
|
|
|
281
|
+
this.update({
|
|
282
|
+
updateSeries: false,
|
|
283
|
+
updateSelTip: { update: true, keepDomain: true },
|
|
284
|
+
});
|
|
285
|
+
};
|
|
170
286
|
/**
|
|
171
287
|
* callback for legendBoxDOM hovering
|
|
172
288
|
*
|
|
@@ -174,6 +290,7 @@ const modules = {
|
|
|
174
290
|
*/
|
|
175
291
|
this.onLegendBoxOver = (e) => {
|
|
176
292
|
const type = e.target.dataset.type;
|
|
293
|
+
const series = Object.values(this.seriesList)[0];
|
|
177
294
|
|
|
178
295
|
let targetDOM;
|
|
179
296
|
if (type === 'container') {
|
|
@@ -184,10 +301,10 @@ const modules = {
|
|
|
184
301
|
return;
|
|
185
302
|
}
|
|
186
303
|
const nameDOM = targetDOM.getElementsByClassName('ev-chart-legend-name')[0];
|
|
187
|
-
const targetId = nameDOM.series.
|
|
304
|
+
const targetId = nameDOM.series.cId;
|
|
188
305
|
|
|
189
|
-
|
|
190
|
-
|
|
306
|
+
series.colorAxis.forEach((colorItem) => {
|
|
307
|
+
colorItem.state = colorItem.id === targetId ? 'highlight' : 'downplay';
|
|
191
308
|
});
|
|
192
309
|
|
|
193
310
|
this.update({
|
|
@@ -202,8 +319,9 @@ const modules = {
|
|
|
202
319
|
* @returns {undefined}
|
|
203
320
|
*/
|
|
204
321
|
this.onLegendBoxLeave = () => {
|
|
205
|
-
Object.values(this.seriesList)
|
|
206
|
-
|
|
322
|
+
const series = Object.values(this.seriesList)[0];
|
|
323
|
+
series.colorAxis.forEach((item) => {
|
|
324
|
+
item.state = 'normal';
|
|
207
325
|
});
|
|
208
326
|
|
|
209
327
|
this.update({
|
|
@@ -211,11 +329,53 @@ const modules = {
|
|
|
211
329
|
updateSelTip: { update: false, keepDomain: false },
|
|
212
330
|
});
|
|
213
331
|
};
|
|
214
|
-
|
|
215
332
|
this.legendBoxDOM.addEventListener('click', this.onLegendBoxClick);
|
|
216
333
|
this.legendBoxDOM.addEventListener('mouseover', this.onLegendBoxOver);
|
|
217
334
|
this.legendBoxDOM.addEventListener('mouseleave', this.onLegendBoxLeave);
|
|
218
335
|
|
|
336
|
+
this.initResizeEvent();
|
|
337
|
+
},
|
|
338
|
+
|
|
339
|
+
initResizeEvent() {
|
|
340
|
+
/**
|
|
341
|
+
* callback for resizeDOM click event
|
|
342
|
+
* 1. hide resizeDOM
|
|
343
|
+
* 2. show ghost DOM on same position with hidden resizeDOM
|
|
344
|
+
*
|
|
345
|
+
* @returns {undefined}
|
|
346
|
+
*/
|
|
347
|
+
this.onResizeMouseDown = (e) => {
|
|
348
|
+
e.stopPropagation();
|
|
349
|
+
e.preventDefault();
|
|
350
|
+
|
|
351
|
+
const opt = this.options;
|
|
352
|
+
const pos = opt.legend.position;
|
|
353
|
+
const title = opt.title.show ? opt.title.height : 0;
|
|
354
|
+
|
|
355
|
+
const ghostDOM = this.ghostDOM;
|
|
356
|
+
this.resizeDOM.style.display = 'none';
|
|
357
|
+
this.wrapperDOM.appendChild(ghostDOM);
|
|
358
|
+
|
|
359
|
+
// mouse down 시, resizeDOM의 위치를 기반으로 ghostDOM의 위치를 세팅
|
|
360
|
+
if (pos === 'left' || pos === 'right') {
|
|
361
|
+
ghostDOM.style.top = `${title}px`;
|
|
362
|
+
ghostDOM.style.left = this.resizeDOM.style.left;
|
|
363
|
+
ghostDOM.style.right = this.resizeDOM.style.right;
|
|
364
|
+
ghostDOM.style.height = this.resizeDOM.style.height;
|
|
365
|
+
} else {
|
|
366
|
+
ghostDOM.classList.add('horizontal');
|
|
367
|
+
|
|
368
|
+
if (pos === 'top') {
|
|
369
|
+
ghostDOM.style.top = this.resizeDOM.style.top;
|
|
370
|
+
} else if (pos === 'bottom') {
|
|
371
|
+
ghostDOM.style.bottom = this.resizeDOM.style.bottom;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
this.wrapperDOM.addEventListener('mousemove', this.mouseMove, false);
|
|
376
|
+
this.wrapperDOM.addEventListener('mouseup', this.mouseUp, false);
|
|
377
|
+
};
|
|
378
|
+
|
|
219
379
|
if (this.resizeDOM) {
|
|
220
380
|
this.resizeDOM.addEventListener('mousedown', this.onResizeMouseDown);
|
|
221
381
|
this.mouseMove = this.onMouseMove.bind(this); // resizing function
|
|
@@ -230,7 +390,11 @@ const modules = {
|
|
|
230
390
|
*/
|
|
231
391
|
updateLegend() {
|
|
232
392
|
this.resetLegend();
|
|
233
|
-
this.
|
|
393
|
+
if (this.isHeatMapType) {
|
|
394
|
+
this.addColorLegendList();
|
|
395
|
+
} else {
|
|
396
|
+
this.addLegendList();
|
|
397
|
+
}
|
|
234
398
|
},
|
|
235
399
|
|
|
236
400
|
/**
|
|
@@ -264,18 +428,26 @@ const modules = {
|
|
|
264
428
|
containerDOM.className = 'ev-chart-legend-container';
|
|
265
429
|
colorDOM.className = 'ev-chart-legend-color';
|
|
266
430
|
|
|
267
|
-
if (series.type === 'line' && series.point) {
|
|
431
|
+
if (series.type === 'line' && series.point && !series.fill) {
|
|
268
432
|
colorDOM.className += ' ev-chart-legend-color--point-line';
|
|
269
433
|
}
|
|
270
434
|
|
|
271
435
|
nameDOM.className = 'ev-chart-legend-name';
|
|
272
|
-
|
|
273
436
|
nameDOM.series = series;
|
|
274
437
|
|
|
438
|
+
let seriesColor;
|
|
275
439
|
if (typeof series.color !== 'string') {
|
|
276
|
-
|
|
440
|
+
seriesColor = series.color[series.color.length - 1][1];
|
|
277
441
|
} else {
|
|
278
|
-
|
|
442
|
+
seriesColor = series.color;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
if (series.type === 'line' && series.fill) {
|
|
446
|
+
colorDOM.style.height = '8px';
|
|
447
|
+
colorDOM.style.backgroundColor = `${seriesColor}80`;
|
|
448
|
+
colorDOM.style.border = `1px solid ${seriesColor}`;
|
|
449
|
+
} else {
|
|
450
|
+
colorDOM.style.backgroundColor = seriesColor;
|
|
279
451
|
}
|
|
280
452
|
|
|
281
453
|
colorDOM.dataset.type = 'color';
|
|
@@ -466,7 +638,6 @@ const modules = {
|
|
|
466
638
|
}
|
|
467
639
|
}
|
|
468
640
|
},
|
|
469
|
-
|
|
470
641
|
/**
|
|
471
642
|
* When user moves resizeDOM, this function will change css
|
|
472
643
|
*
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { numberWithComma } from '@/common/utils';
|
|
2
2
|
import debounce from '@/common/utils.debounce';
|
|
3
|
+
import dayjs from 'dayjs';
|
|
3
4
|
import Canvas from '../helpers/helpers.canvas';
|
|
4
5
|
import Util from '../helpers/helpers.util';
|
|
5
6
|
|
|
@@ -310,6 +311,13 @@ const modules = {
|
|
|
310
311
|
value,
|
|
311
312
|
name,
|
|
312
313
|
});
|
|
314
|
+
} else if (this.options.type === 'heatMap') {
|
|
315
|
+
formattedTxt = opt.formatter({
|
|
316
|
+
x: this.options.horizontal ? hitItem.y : hitItem.x,
|
|
317
|
+
y: this.options.horizontal ? hitItem.x : hitItem.y,
|
|
318
|
+
name,
|
|
319
|
+
value,
|
|
320
|
+
});
|
|
313
321
|
} else {
|
|
314
322
|
formattedTxt = opt.formatter({
|
|
315
323
|
x: this.options.horizontal ? value : hitItem.x,
|
|
@@ -335,14 +343,249 @@ const modules = {
|
|
|
335
343
|
|
|
336
344
|
ctx.restore();
|
|
337
345
|
|
|
338
|
-
|
|
346
|
+
this.setTooltipDOMStyle(opt);
|
|
347
|
+
},
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Draw tooltip canvas for heatmap
|
|
351
|
+
* @param {object} hitInfo mousemove callback
|
|
352
|
+
* @param {object} context tooltip canvas context
|
|
353
|
+
*
|
|
354
|
+
* @returns {undefined}
|
|
355
|
+
*/
|
|
356
|
+
drawToolTipForHeatMap(hitInfo, context) {
|
|
357
|
+
const ctx = context;
|
|
358
|
+
const items = hitInfo.items;
|
|
359
|
+
const sId = hitInfo.hitId;
|
|
360
|
+
const hitItem = items[sId].data;
|
|
361
|
+
const hitAxis = items[sId].axis;
|
|
362
|
+
const hitColor = items[sId].color;
|
|
363
|
+
const boxPadding = { t: 8, b: 8, r: 20, l: 16 };
|
|
364
|
+
const isHorizontal = this.options.horizontal;
|
|
365
|
+
const opt = this.options.tooltip;
|
|
366
|
+
|
|
367
|
+
// draw tooltip Title(axis label) and add style class for wrap line about too much long label.
|
|
368
|
+
if (this.axesX.length && this.axesY.length) {
|
|
369
|
+
this.tooltipHeaderDOM.textContent = this.options.horizontal
|
|
370
|
+
? `${this.axesY[hitAxis.y].getLabelFormat(hitItem.y)} / ${this.axesX[hitAxis.x].getLabelFormat(hitItem.x)}`
|
|
371
|
+
: `${this.axesX[hitAxis.x].getLabelFormat(hitItem.x)} / ${this.axesY[hitAxis.y].getLabelFormat(hitItem.y)}`;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
if (opt.textOverflow) {
|
|
375
|
+
this.tooltipHeaderDOM.classList.add(`ev-chart-tooltip-header--${opt.textOverflow}`);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// draw tooltip contents (series, value combination)
|
|
379
|
+
ctx.save();
|
|
380
|
+
ctx.scale(this.pixelRatio, this.pixelRatio);
|
|
381
|
+
|
|
382
|
+
if (this.tooltipBodyDOM.style.overflowY === 'auto') {
|
|
383
|
+
boxPadding.r += SCROLL_WIDTH;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
const itemX = boxPadding.l + 2;
|
|
387
|
+
const itemY = boxPadding.t + TEXT_HEIGHT + 2;
|
|
388
|
+
const itemValue = hitItem.o > -1 ? hitItem.o : 'error';
|
|
389
|
+
|
|
390
|
+
ctx.font = FONT_STYLE;
|
|
391
|
+
|
|
392
|
+
ctx.beginPath();
|
|
393
|
+
|
|
394
|
+
if (typeof hitColor !== 'string') {
|
|
395
|
+
ctx.fillStyle = Canvas.createGradient(
|
|
396
|
+
ctx,
|
|
397
|
+
isHorizontal,
|
|
398
|
+
{ x: itemX, y: itemY, w: 12, h: -12 },
|
|
399
|
+
hitColor,
|
|
400
|
+
);
|
|
401
|
+
} else {
|
|
402
|
+
ctx.fillStyle = hitColor;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
// 1. Draw series color
|
|
406
|
+
ctx.fillRect(itemX - 4, itemY - 12, 12, 12);
|
|
407
|
+
ctx.fillStyle = opt.fontColor;
|
|
408
|
+
|
|
409
|
+
// 2. Draw series name
|
|
410
|
+
ctx.textBaseline = 'Bottom';
|
|
411
|
+
ctx.fillText(itemValue, itemX + COLOR_MARGIN, itemY);
|
|
412
|
+
ctx.closePath();
|
|
413
|
+
|
|
414
|
+
this.setTooltipDOMStyle(opt);
|
|
415
|
+
},
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
*
|
|
419
|
+
* @param hitInfo
|
|
420
|
+
* @param context
|
|
421
|
+
*/
|
|
422
|
+
drawTooltipForScatter(hitInfo, context) {
|
|
423
|
+
const ctx = context;
|
|
424
|
+
const items = hitInfo.items;
|
|
425
|
+
const [, maxValue] = hitInfo.maxTip;
|
|
426
|
+
const seriesKeys = this.alignSeriesList(Object.keys(items));
|
|
427
|
+
const boxPadding = { t: 8, b: 8, r: 8, l: 8 };
|
|
428
|
+
const opt = this.options.tooltip;
|
|
429
|
+
const xAxisOpt = this.options.axesX[0];
|
|
430
|
+
|
|
431
|
+
let x = 2;
|
|
432
|
+
let y = 2;
|
|
433
|
+
|
|
434
|
+
x += Util.aliasPixel(x);
|
|
435
|
+
y += Util.aliasPixel(y);
|
|
436
|
+
|
|
437
|
+
ctx.save();
|
|
438
|
+
ctx.scale(this.pixelRatio, this.pixelRatio);
|
|
439
|
+
|
|
440
|
+
if (this.tooltipBodyDOM.style.overflowY === 'auto') {
|
|
441
|
+
boxPadding.r += SCROLL_WIDTH;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
x += boxPadding.l;
|
|
445
|
+
y += boxPadding.t;
|
|
446
|
+
|
|
447
|
+
ctx.font = FONT_STYLE;
|
|
448
|
+
|
|
449
|
+
const seriesList = [];
|
|
450
|
+
seriesKeys.forEach((seriesName) => {
|
|
451
|
+
seriesList.push({
|
|
452
|
+
data: items[seriesName].data,
|
|
453
|
+
color: items[seriesName].color,
|
|
454
|
+
name: items[seriesName].name,
|
|
455
|
+
});
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
if (opt.sortByValue) {
|
|
459
|
+
seriesList.sort((a, b) => {
|
|
460
|
+
let prev = a.data.o;
|
|
461
|
+
let next = b.data.o;
|
|
462
|
+
|
|
463
|
+
if (prev === null || prev === undefined) {
|
|
464
|
+
prev = a.data.y;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
if (next === null || next === undefined) {
|
|
468
|
+
next = b.data.y;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
return next - prev;
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
let textLineCnt = 1;
|
|
476
|
+
for (let ix = 0; ix < seriesList.length; ix++) {
|
|
477
|
+
const gdata = seriesList[ix].data;
|
|
478
|
+
const color = seriesList[ix].color;
|
|
479
|
+
const name = seriesList[ix].name;
|
|
480
|
+
const xValue = gdata.x;
|
|
481
|
+
let yValue;
|
|
482
|
+
if (gdata.o === null) {
|
|
483
|
+
yValue = gdata.y;
|
|
484
|
+
} else if (!isNaN(gdata.o)) {
|
|
485
|
+
yValue = gdata.o;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
let itemX = x + 4;
|
|
489
|
+
let itemY = y + (textLineCnt * TEXT_HEIGHT);
|
|
490
|
+
itemX += Util.aliasPixel(itemX);
|
|
491
|
+
itemY += Util.aliasPixel(itemY);
|
|
492
|
+
|
|
493
|
+
ctx.beginPath();
|
|
494
|
+
|
|
495
|
+
if (typeof color !== 'string') {
|
|
496
|
+
ctx.fillStyle = Canvas.createGradient(
|
|
497
|
+
ctx,
|
|
498
|
+
false,
|
|
499
|
+
{ x: itemX - 4, y: itemY, w: 12, h: -12 },
|
|
500
|
+
color,
|
|
501
|
+
);
|
|
502
|
+
} else {
|
|
503
|
+
ctx.fillStyle = color;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
// 1. Draw series color
|
|
507
|
+
ctx.fillRect(itemX - 4, itemY - 12, 12, 12);
|
|
508
|
+
ctx.fillStyle = opt.fontColor;
|
|
509
|
+
|
|
510
|
+
// 2. Draw series name
|
|
511
|
+
ctx.textBaseline = 'Bottom';
|
|
512
|
+
const seriesNameSpaceWidth = opt.maxWidth - Math.round(ctx.measureText(maxValue).width)
|
|
513
|
+
- boxPadding.l - boxPadding.r - COLOR_MARGIN - VALUE_MARGIN;
|
|
514
|
+
const xPos = itemX + COLOR_MARGIN;
|
|
515
|
+
const yPos = itemY;
|
|
516
|
+
|
|
517
|
+
if (seriesNameSpaceWidth > ctx.measureText(name).width) { // draw normally
|
|
518
|
+
ctx.fillText(name, xPos, yPos);
|
|
519
|
+
} else if (opt.textOverflow === 'wrap') { // draw with wrap
|
|
520
|
+
let line = '';
|
|
521
|
+
let yPosWithWrap = yPos;
|
|
522
|
+
|
|
523
|
+
for (let jx = 0; jx < name.length; jx++) {
|
|
524
|
+
const char = name[jx];
|
|
525
|
+
const temp = `${line}${char}`;
|
|
526
|
+
|
|
527
|
+
if (ctx.measureText(temp).width > seriesNameSpaceWidth) {
|
|
528
|
+
ctx.fillText(line, xPos, yPosWithWrap);
|
|
529
|
+
line = char;
|
|
530
|
+
textLineCnt += 1;
|
|
531
|
+
yPosWithWrap += TEXT_HEIGHT;
|
|
532
|
+
} else {
|
|
533
|
+
line = temp;
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
ctx.fillText(line, xPos, yPosWithWrap);
|
|
537
|
+
} else { // draw with ellipsis
|
|
538
|
+
const shortSeriesName = Util.truncateLabelWithEllipsis(name, seriesNameSpaceWidth, ctx);
|
|
539
|
+
ctx.fillText(shortSeriesName, xPos, yPos);
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
ctx.save();
|
|
543
|
+
|
|
544
|
+
// 3. Draw value
|
|
545
|
+
let formattedTxt;
|
|
546
|
+
if (opt.formatter) {
|
|
547
|
+
formattedTxt = opt.formatter({
|
|
548
|
+
x: xValue,
|
|
549
|
+
y: yValue,
|
|
550
|
+
name,
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
if (!opt.formatter || typeof formattedTxt !== 'string') {
|
|
555
|
+
const formattedXValue = xAxisOpt.type === 'time'
|
|
556
|
+
? dayjs(xValue).format(xAxisOpt.timeFormat)
|
|
557
|
+
: numberWithComma(xValue);
|
|
558
|
+
const formattedYValue = numberWithComma(yValue);
|
|
559
|
+
formattedTxt = `${formattedXValue}, ${formattedYValue}`;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
ctx.textAlign = 'right';
|
|
563
|
+
ctx.fillText(formattedTxt, this.tooltipDOM.offsetWidth - boxPadding.r, itemY);
|
|
564
|
+
ctx.restore();
|
|
565
|
+
ctx.closePath();
|
|
566
|
+
|
|
567
|
+
// 4. add lineSpacing
|
|
568
|
+
y += LINE_SPACING;
|
|
569
|
+
textLineCnt += 1;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
ctx.restore();
|
|
573
|
+
|
|
574
|
+
this.setTooltipDOMStyle(opt);
|
|
575
|
+
},
|
|
576
|
+
|
|
577
|
+
/**
|
|
578
|
+
* set style properties on tooltip DOM
|
|
579
|
+
* @param tooltipOptions
|
|
580
|
+
*/
|
|
581
|
+
setTooltipDOMStyle(tooltipOptions) {
|
|
339
582
|
this.tooltipDOM.style.overflowY = 'hidden';
|
|
340
|
-
this.tooltipDOM.style.backgroundColor =
|
|
341
|
-
this.tooltipDOM.style.border = `1px solid ${
|
|
342
|
-
this.tooltipDOM.style.color =
|
|
583
|
+
this.tooltipDOM.style.backgroundColor = tooltipOptions.backgroundColor;
|
|
584
|
+
this.tooltipDOM.style.border = `1px solid ${tooltipOptions.borderColor}`;
|
|
585
|
+
this.tooltipDOM.style.color = tooltipOptions.fontColor;
|
|
343
586
|
|
|
344
|
-
if (
|
|
345
|
-
const shadowColor = `rgba(0, 0, 0, ${
|
|
587
|
+
if (tooltipOptions.useShadow) {
|
|
588
|
+
const shadowColor = `rgba(0, 0, 0, ${tooltipOptions.shadowOpacity})`;
|
|
346
589
|
this.tooltipDOM.style.boxShadow = `2px 2px 2px ${shadowColor}`;
|
|
347
590
|
}
|
|
348
591
|
|
|
@@ -239,6 +239,15 @@ class Scale {
|
|
|
239
239
|
linePosition = labelCenter + aliasPixel;
|
|
240
240
|
labelText = this.getLabelFormat(Math.min(axisMax, ticks[ix]));
|
|
241
241
|
|
|
242
|
+
const labelColor = this.labelStyle.color;
|
|
243
|
+
let defaultOpacity = 1;
|
|
244
|
+
|
|
245
|
+
if (Util.getColorStringType(labelColor) === 'RGBA') {
|
|
246
|
+
defaultOpacity = Util.getOpacity(labelColor);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
ctx.fillStyle = Util.colorStringToRgba(labelColor, defaultOpacity);
|
|
250
|
+
|
|
242
251
|
let labelPoint;
|
|
243
252
|
|
|
244
253
|
if (this.type === 'x') {
|
|
@@ -57,7 +57,7 @@ class StepScale extends Scale {
|
|
|
57
57
|
*
|
|
58
58
|
* @returns {undefined}
|
|
59
59
|
*/
|
|
60
|
-
draw(chartRect, labelOffset, stepInfo, hitInfo) {
|
|
60
|
+
draw(chartRect, labelOffset, stepInfo, hitInfo, selectLabelInfo) {
|
|
61
61
|
const ctx = this.ctx;
|
|
62
62
|
const labels = this.labels;
|
|
63
63
|
const aPos = {
|
|
@@ -121,14 +121,29 @@ class StepScale extends Scale {
|
|
|
121
121
|
linePosition = labelCenter + aliasPixel;
|
|
122
122
|
labelText = this.getLabelFormat(item, maxWidth);
|
|
123
123
|
|
|
124
|
+
const isBlurredLabel = this.options?.selectLabel?.use
|
|
125
|
+
&& this.options?.selectLabel?.useLabelOpacity
|
|
126
|
+
&& (this.options.horizontal === (this.type === 'y'))
|
|
127
|
+
&& selectLabelInfo?.dataIndex?.length
|
|
128
|
+
&& !selectLabelInfo?.dataIndex?.includes(index);
|
|
129
|
+
|
|
130
|
+
const labelColor = this.labelStyle.color;
|
|
131
|
+
let defaultOpacity = 1;
|
|
132
|
+
|
|
133
|
+
if (Util.getColorStringType(labelColor) === 'RGBA') {
|
|
134
|
+
defaultOpacity = Util.getOpacity(labelColor);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
ctx.fillStyle = Util.colorStringToRgba(labelColor, isBlurredLabel ? 0.1 : defaultOpacity);
|
|
138
|
+
|
|
124
139
|
if (this.type === 'x') {
|
|
125
140
|
labelPoint = this.position === 'top' ? offsetPoint - 10 : offsetPoint + 10;
|
|
126
141
|
ctx.fillText(labelText, labelCenter + (labelGap / 2), labelPoint);
|
|
127
142
|
|
|
128
|
-
if (
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
143
|
+
if (!isBlurredLabel
|
|
144
|
+
&& this.options?.selectItem?.showLabelTip
|
|
145
|
+
&& hitInfo?.label
|
|
146
|
+
&& !this.options?.horizontal) {
|
|
132
147
|
const selectedLabel = hitInfo.label;
|
|
133
148
|
if (selectedLabel === labelText) {
|
|
134
149
|
const height = Math.round(ctx.measureText(this.labelStyle?.fontSize).width);
|