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.
Files changed (35) hide show
  1. package/dist/evui.common.js +3546 -973
  2. package/dist/evui.common.js.map +1 -1
  3. package/dist/evui.umd.js +3546 -973
  4. package/dist/evui.umd.js.map +1 -1
  5. package/dist/evui.umd.min.js +1 -1
  6. package/dist/evui.umd.min.js.map +1 -1
  7. package/package.json +1 -1
  8. package/src/components/chart/Chart.vue +15 -6
  9. package/src/components/chart/chart.core.js +86 -31
  10. package/src/components/chart/element/element.bar.js +7 -1
  11. package/src/components/chart/element/element.heatmap.js +213 -0
  12. package/src/components/chart/element/element.line.js +20 -9
  13. package/src/components/chart/element/element.pie.js +13 -5
  14. package/src/components/chart/element/element.scatter.js +26 -9
  15. package/src/components/chart/element/element.tip.js +154 -13
  16. package/src/components/chart/helpers/helpers.constant.js +15 -0
  17. package/src/components/chart/model/model.series.js +4 -0
  18. package/src/components/chart/model/model.store.js +160 -2
  19. package/src/components/chart/plugins/plugins.interaction.js +82 -10
  20. package/src/components/chart/plugins/plugins.legend.js +213 -42
  21. package/src/components/chart/plugins/plugins.tooltip.js +249 -6
  22. package/src/components/chart/scale/scale.js +9 -0
  23. package/src/components/chart/scale/scale.step.js +20 -5
  24. package/src/components/chart/scale/scale.time.category.js +20 -2
  25. package/src/components/chart/uses.js +20 -3
  26. package/src/components/grid/Grid.vue +276 -132
  27. package/src/components/grid/grid.filter.window.vue +1 -0
  28. package/src/components/grid/grid.pagination.vue +75 -0
  29. package/src/components/grid/grid.summary.vue +235 -0
  30. package/src/components/grid/style/grid.scss +0 -14
  31. package/src/components/grid/uses.js +158 -79
  32. package/src/components/pagination/Pagination.vue +20 -17
  33. package/src/components/treeGrid/TreeGrid.vue +253 -34
  34. package/src/components/treeGrid/TreeGridNode.vue +8 -9
  35. 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
- colorDOM.style.backgroundColor = series.color[series.color.length - 1][1];
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 = series.color;
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 resizeDOM click event
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.onResizeMouseDown = (e) => {
139
- e.stopPropagation();
140
- e.preventDefault();
179
+ this.onLegendBoxOver = (e) => {
180
+ const type = e.target.dataset.type;
141
181
 
142
- const opt = this.options;
143
- const pos = opt.legend.position;
144
- const title = opt.title.show ? opt.title.height : 0;
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
- const ghostDOM = this.ghostDOM;
147
- this.resizeDOM.style.display = 'none';
148
- this.wrapperDOM.appendChild(ghostDOM);
193
+ Object.values(this.seriesList).forEach((series) => {
194
+ series.state = series.sId === targetId ? 'highlight' : 'downplay';
195
+ });
149
196
 
150
- // mouse down 시, resizeDOM의 위치를 기반으로 ghostDOM의 위치를 세팅
151
- if (pos === 'left' || pos === 'right') {
152
- ghostDOM.style.top = `${title}px`;
153
- ghostDOM.style.left = this.resizeDOM.style.left;
154
- ghostDOM.style.right = this.resizeDOM.style.right;
155
- ghostDOM.style.height = this.resizeDOM.style.height;
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
- ghostDOM.classList.add('horizontal');
247
+ return;
248
+ }
158
249
 
159
- if (pos === 'top') {
160
- ghostDOM.style.top = this.resizeDOM.style.top;
161
- } else if (pos === 'bottom') {
162
- ghostDOM.style.bottom = this.resizeDOM.style.bottom;
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
- this.wrapperDOM.addEventListener('mousemove', this.mouseMove, false);
167
- this.wrapperDOM.addEventListener('mouseup', this.mouseUp, false);
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.sId;
304
+ const targetId = nameDOM.series.cId;
188
305
 
189
- Object.values(this.seriesList).forEach((series) => {
190
- series.state = series.sId === targetId ? 'highlight' : 'downplay';
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).forEach((series) => {
206
- series.state = 'normal';
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.addLegendList();
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
- colorDOM.style.backgroundColor = series.color[series.color.length - 1][1];
440
+ seriesColor = series.color[series.color.length - 1][1];
277
441
  } else {
278
- colorDOM.style.backgroundColor = series.color;
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
- // set tooltipDOM's style
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 = opt.backgroundColor;
341
- this.tooltipDOM.style.border = `1px solid ${opt.borderColor}`;
342
- this.tooltipDOM.style.color = opt.fontColor;
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 (opt.useShadow) {
345
- const shadowColor = `rgba(0, 0, 0, ${opt.shadowOpacity})`;
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 (this.options?.selectItem?.showLabelTip
129
- && hitInfo?.label
130
- && !this.options?.horizontal
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);