evui 3.3.11 → 3.3.14

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 (29) hide show
  1. package/dist/evui.common.js +1855 -836
  2. package/dist/evui.common.js.map +1 -1
  3. package/dist/evui.umd.js +1855 -836
  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 +21 -2
  9. package/src/components/chart/chart.core.js +12 -9
  10. package/src/components/chart/element/element.heatmap.js +195 -51
  11. package/src/components/chart/element/element.line.js +20 -9
  12. package/src/components/chart/element/element.tip.js +69 -73
  13. package/src/components/chart/helpers/helpers.constant.js +13 -11
  14. package/src/components/chart/model/model.series.js +1 -1
  15. package/src/components/chart/model/model.store.js +114 -74
  16. package/src/components/chart/plugins/plugins.interaction.js +72 -17
  17. package/src/components/chart/plugins/plugins.legend.js +18 -5
  18. package/src/components/chart/plugins/plugins.pie.js +17 -0
  19. package/src/components/chart/plugins/plugins.tooltip.js +30 -14
  20. package/src/components/chart/scale/scale.js +5 -4
  21. package/src/components/chart/scale/scale.step.js +29 -2
  22. package/src/components/chart/scale/scale.time.category.js +27 -3
  23. package/src/components/chart/uses.js +22 -1
  24. package/src/components/grid/Grid.vue +19 -7
  25. package/src/components/grid/grid.summary.vue +20 -6
  26. package/src/components/grid/uses.js +1 -1
  27. package/src/components/treeGrid/TreeGrid.vue +269 -36
  28. package/src/components/treeGrid/TreeGridNode.vue +8 -9
  29. package/src/components/treeGrid/uses.js +152 -37
@@ -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 } = this.defaultSelectLabelInfo;
253
+ const { dataIndex, data, label } = this.defaultSelectInfo;
254
254
  let drawTip = false;
255
255
 
256
256
  if (dataIndex.length) {
@@ -264,86 +264,82 @@ const modules = {
264
264
  y1: chartRect.y1 + labelOffset.top,
265
265
  y2: chartRect.y2 - labelOffset.bottom,
266
266
  };
267
+ const labelAxes = isHorizontal ? this.axesY[0] : this.axesX[0];
268
+ const valueAxes = isHorizontal ? this.axesX[0] : this.axesY[0];
269
+ const valueAxesRange = isHorizontal ? this.axesRange.x[0] : this.axesRange.y[0];
270
+ const valuePositionCalcFunction = isHorizontal ? Canvas.calculateX : Canvas.calculateY;
271
+ const labelPositionCalcFunction = isHorizontal ? Canvas.calculateY : Canvas.calculateX;
267
272
 
268
- const labelAxes = this.options.horizontal ? this.axesY[0] : this.axesX[0];
269
- const labelStartPoint = aPos[labelAxes.units.rectStart];
270
- const labelEndPoint = aPos[labelAxes.units.rectEnd];
271
- const labelGap = (labelEndPoint - labelStartPoint) / labelAxes.labels.length;
272
-
273
- const valueAxes = this.options.horizontal ? this.axesX[0] : this.axesY[0];
274
- const valueStartPoint = aPos[valueAxes.units.rectStart];
275
-
276
- const offset = this.options.type === 'bar' ? 4 : 6;
277
273
  const chartWidth = chartRect.chartWidth - (labelOffset.left + labelOffset.right);
278
274
  const chartHeight = chartRect.chartHeight - (labelOffset.top + labelOffset.bottom);
275
+ const valueSpace = isHorizontal ? chartWidth : chartHeight;
276
+ const valueStartPoint = aPos[valueAxes.units.rectStart];
277
+ let offset = this.options.type === 'bar' ? 4 : 6;
278
+ offset *= isHorizontal ? 1 : -1;
279
+
280
+ const seriesList = Object.keys(this.seriesList ?? {});
281
+ const visibleSeries = seriesList.filter(sId => this.seriesList[sId].show);
282
+ const isExistGrp = seriesList.some(sId => this.seriesList[sId].isExistGrp);
283
+ const groups = this.data.groups?.[0] ?? [];
284
+
285
+ let gp;
286
+ let dp;
287
+ let value;
288
+ let labelStartPoint;
289
+ let labelEndPoint;
290
+ let labelGap;
291
+ let graphX;
292
+ let lineSeries;
293
+ let sizeObj;
294
+
295
+ if (labelAxes.labels) {
296
+ labelStartPoint = aPos[labelAxes.units.rectStart];
297
+ labelEndPoint = aPos[labelAxes.units.rectEnd];
298
+ labelGap = (labelEndPoint - labelStartPoint) / labelAxes.labels.length;
299
+ } else {
300
+ graphX = this.axesSteps.x[0];
301
+ lineSeries = seriesList.find(sId => this.seriesList[sId]?.type === 'line');
302
+ sizeObj = this.seriesList[lineSeries].size;
303
+ }
279
304
 
280
- dataIndex.forEach((idx, i) => {
281
- const labelCenter = Math.round(labelStartPoint + (labelGap * idx));
282
- let gp;
283
- const dp = labelCenter + (labelGap / 2);
305
+ data.forEach((selectedData, i) => {
284
306
  if (labelTipOpt.fixedPosTop) {
285
- if (isHorizontal) {
286
- gp = Canvas.calculateX(
287
- this.axesRange.x[0].max,
288
- this.axesRange.x[0].min,
289
- this.axesRange.x[0].max,
290
- chartWidth,
291
- valueStartPoint);
292
- gp += offset;
293
- } else {
294
- gp = Canvas.calculateY(
295
- this.axesRange.y[0].max,
296
- this.axesRange.y[0].min,
297
- this.axesRange.y[0].max,
298
- chartHeight,
299
- valueStartPoint);
300
- gp -= offset;
301
- }
302
- } else if (isHorizontal) {
303
- const seriesList = Object.keys(data[i] ?? {});
304
- const visibleSeries = seriesList.filter(sId => this.seriesList[sId].show);
305
- const visibleValue = visibleSeries.map(sId => data[i][sId]);
306
- const isExistGrp = seriesList.some(sId => this.seriesList[sId].isExistGrp);
307
-
308
- let maxValue;
309
- if (isExistGrp) {
310
- maxValue = visibleValue.reduce((acc, v) => acc + v) ?? 0;
311
- } else if (visibleValue.length) {
312
- maxValue = Math.max(...visibleValue);
313
- } else {
314
- maxValue = this.axesRange.x[0].max;
315
- }
316
-
317
- gp = Canvas.calculateX(
318
- maxValue,
319
- this.axesRange.x[0].min,
320
- this.axesRange.x[0].max,
321
- chartWidth,
322
- valueStartPoint);
323
- gp += offset;
307
+ value = valueAxesRange.max;
308
+ } else if (isExistGrp) {
309
+ const sumValue = visibleSeries.reduce((ac, sId) => (
310
+ groups.includes(sId) ? ac + (selectedData[sId]?.value ?? selectedData[sId]) : ac), 0);
311
+ const nonGroupValues = visibleSeries
312
+ .filter(sId => !groups.includes(sId))
313
+ .map(sId => selectedData[sId]?.value ?? selectedData[sId]);
314
+ value = Math.max(...nonGroupValues, sumValue);
315
+ } else if (visibleSeries.length) {
316
+ const visibleValue = visibleSeries
317
+ .map(sId => selectedData[sId]?.value ?? selectedData[sId]);
318
+ value = Math.max(...visibleValue);
324
319
  } else {
325
- const seriesList = Object.keys(data[i] ?? {});
326
- const visibleSeries = seriesList.filter(sId => this.seriesList[sId].show);
327
- const visibleValue = visibleSeries.map(sId => data[i][sId]);
328
- const isExistGrp = seriesList.some(sId => this.seriesList[sId].isExistGrp);
329
-
330
- let maxValue;
331
- if (isExistGrp) {
332
- maxValue = visibleValue.reduce((acc, v) => acc + v) ?? 0;
333
- } else if (visibleValue.length) {
334
- maxValue = Math.max(...visibleValue);
335
- } else {
336
- maxValue = this.axesRange.y[0].max;
337
- }
320
+ value = valueAxesRange.max;
321
+ }
322
+
323
+ if (labelAxes.labels) {
324
+ const labelCenter = Math.round(labelStartPoint + (labelGap * dataIndex[i]));
338
325
 
339
- gp = Canvas.calculateY(
340
- maxValue,
341
- this.axesRange.y[0].min,
342
- this.axesRange.y[0].max,
343
- chartHeight,
344
- valueStartPoint);
345
- gp -= offset;
326
+ dp = labelCenter + (labelGap / 2);
327
+ } else {
328
+ dp = labelPositionCalcFunction(
329
+ label[i],
330
+ graphX.graphMin,
331
+ graphX.graphMax,
332
+ chartWidth - sizeObj.comboOffset,
333
+ aPos.x1 + (sizeObj.comboOffset / 2),
334
+ );
346
335
  }
336
+ gp = valuePositionCalcFunction(
337
+ value,
338
+ valueAxesRange.min,
339
+ valueAxesRange.max,
340
+ valueSpace,
341
+ valueStartPoint);
342
+ gp += offset;
347
343
 
348
344
  this.showTip({
349
345
  context: this.bufferCtx,
@@ -129,17 +129,19 @@ export const PLOT_BAND_OPTION = {
129
129
  };
130
130
 
131
131
  export const HEAT_MAP_OPTION = {
132
- ...LINE_OPTION,
133
- colorOpt: {
134
- min: '#FFFFFF',
135
- max: '#0052FF',
136
- categoryCnt: 5,
137
- border: '#FFFFFF',
138
- error: '#FF0000',
139
- },
140
- spaces: {
141
- x: 0,
142
- y: 0,
132
+ show: true,
133
+ highlight: {
134
+ maxShadowOpacity: 0.4,
135
+ },
136
+ xAxisIndex: 0,
137
+ yAxisIndex: 0,
138
+ showLegend: true,
139
+ showValue: {
140
+ use: false,
141
+ fontSize: 12,
142
+ textColor: '#000000',
143
+ formatter: null,
144
+ decimalPoint: 0,
143
145
  },
144
146
  };
145
147
 
@@ -54,7 +54,7 @@ const modules = {
54
54
  return new Pie(id, opt, index);
55
55
  } else if (type === 'heatMap') {
56
56
  this.seriesInfo.charts.heatMap.push(id);
57
- return new HeatMap(id, opt, index);
57
+ return new HeatMap(id, opt, this.options.heatMapColor);
58
58
  }
59
59
 
60
60
  return false;
@@ -1,6 +1,5 @@
1
1
  import { reverse } from 'lodash-es';
2
2
  import Util from '../helpers/helpers.util';
3
- import { TIME_INTERVALS } from '../helpers/helpers.constant';
4
3
 
5
4
  const modules = {
6
5
  /**
@@ -37,8 +36,9 @@ const modules = {
37
36
  const sData = data[seriesID];
38
37
 
39
38
  if (series && sData) {
39
+ series.labels = label;
40
40
  series.data = this.addSeriesDSForHeatMap(sData);
41
- series.minMax = this.getSeriesMinMaxForHeatMap(series.data, series.spaces);
41
+ series.minMax = this.getSeriesMinMax(series.data);
42
42
  series.valueOpt = this.getSeriesValueOptForHeatMap(series);
43
43
  }
44
44
  });
@@ -301,17 +301,20 @@ const modules = {
301
301
  /**
302
302
  * Take data to create data for each series
303
303
  * @param {array} data data array for each series
304
+ * @param {object} label chart label
305
+ *
304
306
  * @returns {array} data info added position and etc
305
307
  */
306
308
  addSeriesDSForHeatMap(data) {
307
- return data.map(item => ({
308
- x: item.x,
309
- y: item.y,
310
- o: item.value,
309
+ return data.map(({ x, y, value }) => ({
310
+ x,
311
+ y,
312
+ o: value,
311
313
  xp: null,
312
314
  yp: null,
315
+ w: null,
316
+ h: null,
313
317
  dataColor: null,
314
- value: item.value,
315
318
  cId: null,
316
319
  }));
317
320
  },
@@ -414,73 +417,14 @@ const modules = {
414
417
  return def;
415
418
  },
416
419
 
417
- adjustMinMax(max, min, opt, space) {
418
- if ((opt.type === 'time' && opt.categoryMode) || opt.type === 'step') {
419
- return {
420
- max,
421
- min,
422
- };
423
- }
424
-
425
- let targetMax = max;
426
- let targetMin = min;
427
- if (targetMax > 0 && opt.interval && space) {
428
- if (targetMax < (opt.interval * space)) {
429
- targetMax += opt.interval;
430
- }
431
- }
432
-
433
- let targetInterval = opt.interval;
434
- if (opt.type === 'time') {
435
- if (typeof targetInterval === 'string') {
436
- targetInterval = TIME_INTERVALS[targetInterval].size;
437
- } else if (typeof targetInterval === 'object') {
438
- targetInterval = targetInterval.time * TIME_INTERVALS[targetInterval.unit].size;
439
- }
440
- }
441
-
442
- if (!opt.startToZero || targetMin > 0) {
443
- const targetSpace = space ? (space - 1) : (targetMax - targetMin);
444
- const targetStep = Math.ceil((max - targetMin) / targetSpace);
445
- targetMin = targetMin < targetStep ? 0 : targetMin - targetStep;
446
- }
447
-
448
- return {
449
- max: targetMax,
450
- min: targetMin,
451
- };
452
- },
453
- /**
454
- * Take series data to create min/max info for each series
455
- * @param data
456
- * @param spaces
457
- * @returns {*|{maxDomain: null, minY: null, minX: null, maxY: null, maxX: null}}
458
- */
459
- getSeriesMinMaxForHeatMap(data, spaces) {
460
- const axesXOption = this.options.axesX[0];
461
- const axesYOption = this.options.axesY[0];
462
- const seriesMinMax = this.getSeriesMinMax(data);
463
-
464
- const adjustX = this.adjustMinMax(seriesMinMax.maxX, seriesMinMax.minX, axesXOption, spaces.x);
465
- seriesMinMax.maxX = adjustX.max;
466
- seriesMinMax.minX = adjustX.min;
467
-
468
- const adjustY = this.adjustMinMax(seriesMinMax.maxY, seriesMinMax.minY, axesYOption, spaces.y);
469
- seriesMinMax.maxY = adjustY.max;
470
- seriesMinMax.minY = adjustY.min;
471
-
472
- return seriesMinMax;
473
- },
474
-
475
420
  getSeriesValueOptForHeatMap(series) {
476
421
  const data = series.data;
477
- const colorOpt = series.colorOpt;
478
- const colorAxis = series.colorAxis;
422
+ const colorOpt = this.options.heatMapColor;
479
423
  const categoryCnt = colorOpt.categoryCnt;
480
424
 
481
425
  let maxValue = 0;
482
426
  let isExistError = false;
483
- data.forEach(({ value }) => {
427
+ data.forEach(({ o: value }) => {
484
428
  if (maxValue < value) {
485
429
  maxValue = value;
486
430
  }
@@ -488,18 +432,19 @@ const modules = {
488
432
  isExistError = true;
489
433
  }
490
434
  });
491
- const valueInterval = Math.ceil(maxValue / categoryCnt);
492
- if (isExistError && colorAxis.length === categoryCnt) {
493
- colorAxis.push({
435
+
436
+ if (isExistError && series.colorAxis.length === categoryCnt) {
437
+ series.colorAxis.push({
494
438
  id: `color#${categoryCnt}`,
495
439
  value: colorOpt.error,
496
440
  state: 'normal',
497
441
  show: true,
498
442
  });
499
443
  }
444
+
500
445
  return {
501
446
  max: maxValue,
502
- interval: valueInterval,
447
+ interval: Math.ceil(maxValue / categoryCnt),
503
448
  existError: isExistError,
504
449
  };
505
450
  },
@@ -673,6 +618,101 @@ const modules = {
673
618
  };
674
619
  },
675
620
 
621
+ /**
622
+ * Find seriesId by position x and y
623
+ * @param {array} offset position x and y
624
+ *
625
+ * @returns {object} clicked series id
626
+ */
627
+ getSeriesIdByPosition(offset) {
628
+ const [clickedX, clickedY] = offset;
629
+ const chartRect = this.chartRect;
630
+ const labelOffset = this.labelOffset;
631
+ const aPos = {
632
+ x1: chartRect.x1 + labelOffset.left,
633
+ x2: chartRect.x2 - labelOffset.right,
634
+ y1: chartRect.y1 + labelOffset.top,
635
+ y2: chartRect.y2 - labelOffset.bottom,
636
+ };
637
+ const valueAxes = this.axesY[0];
638
+ const labelAxes = this.axesX[0];
639
+ const valueStartPoint = aPos[valueAxes.units.rectStart];
640
+ const valueEndPoint = aPos[valueAxes.units.rectEnd];
641
+ const labelStartPoint = aPos[labelAxes.units.rectStart];
642
+ const labelEndPoint = aPos[labelAxes.units.rectEnd];
643
+
644
+ const result = { sId: null };
645
+
646
+ if (clickedY > valueEndPoint && clickedY < valueStartPoint
647
+ && clickedX < labelEndPoint && clickedX > labelStartPoint) {
648
+ let hitSeries;
649
+ let positionList;
650
+ const hitItem = this.findHitItem(offset);
651
+ const hitSeriesList = Object.keys(hitItem.items);
652
+
653
+ switch (this.options.type) {
654
+ case 'line': {
655
+ const orderedSeriesList = this.seriesInfo.charts.line;
656
+ const isStackChart = Object.values(this.seriesList).some(({ stackIndex }) => stackIndex);
657
+
658
+ if (hitSeriesList.length) { // 클릭한 위치에 data 가 존재하는 경우
659
+ if (isStackChart) {
660
+ positionList = orderedSeriesList.filter(sId => hitSeriesList.includes(sId))
661
+ .map(sId => ({ sId, position: hitItem.items[sId]?.data?.yp }));
662
+ hitSeries = positionList.find(({ position }) => clickedY > position)?.sId;
663
+ } else {
664
+ hitSeries = Object.entries(hitItem.items).find(([, { hit }]) => hit)?.[0];
665
+ }
666
+ } else { // 클릭한 위치에 data 가 존재하지 않는 경우
667
+ const visibleSeriesList = orderedSeriesList.filter(sId => this.seriesList[sId].show);
668
+ positionList = visibleSeriesList.map(sId => ({
669
+ sId,
670
+ position: this.seriesList[sId].data?.map(({ xp, yp }) => [xp, yp]),
671
+ }));
672
+ const dataIndex = positionList[0].position?.findIndex(([xp]) => xp >= clickedX);
673
+ const vectorList = positionList.map(({ sId, position }) => ({
674
+ sId,
675
+ vector: { start: position[dataIndex - 1], end: position[dataIndex] },
676
+ }));
677
+
678
+ // canvas 의 클릭 위치값은 제 4 사분면의 위치이므로 clickedY, y1, y2 의 값은 음수를 취한다.
679
+ if (isStackChart) {
680
+ hitSeries = vectorList.find(({ vector }) => {
681
+ const [x1, y1] = vector.start;
682
+ const [x2, y2] = vector.end;
683
+ const v1 = [x2 - x1, y1 - y2];
684
+ const v2 = [x2 - clickedX, clickedY - y2];
685
+ const xp = v1[0] * v2[1] - v1[1] * v2[0];
686
+
687
+ return vector.start.every(v => typeof v === 'number')
688
+ && vector.end.every(v => typeof v === 'number')
689
+ && xp > 0;
690
+ })?.sId;
691
+ } else {
692
+ hitSeries = vectorList.find(({ vector }) => {
693
+ const [x1, y1] = vector.start;
694
+ const [x2, y2] = vector.end;
695
+ const a = (y1 - y2) / (x2 - x1);
696
+ const b = -1;
697
+ const c = -y1 - a * x1;
698
+ const distance = Math.abs(a * clickedX - b * clickedY + c)
699
+ / Math.sqrt(a ** 2 + b ** 2);
700
+
701
+ return distance < 3;
702
+ })?.sId;
703
+ }
704
+ }
705
+ break;
706
+ }
707
+ default:
708
+ break;
709
+ }
710
+
711
+ result.sId = hitSeries;
712
+ }
713
+
714
+ return result;
715
+ },
676
716
  /**
677
717
  * Find label info by position x and y
678
718
  * @param {array} offset position x and y
@@ -699,8 +739,8 @@ const modules = {
699
739
  const index = Math.floor(((this.options.horizontal ? y : x) - startPoint) / labelGap);
700
740
  labelIndex = scale.labels.length > index ? index : -1;
701
741
  } else {
702
- hitInfo = this.getItemByPosition(offset, false);
703
- labelIndex = hitInfo.maxIndex;
742
+ hitInfo = this.getItemByPosition(offset, this.options.selectLabel.useApproximateValue);
743
+ labelIndex = hitInfo.maxIndex ?? -1;
704
744
  }
705
745
 
706
746
  return {
@@ -56,6 +56,8 @@ const modules = {
56
56
  this.setTooltipLayoutPosition(hitInfo, e);
57
57
  if (type === 'scatter') {
58
58
  this.drawTooltipForScatter(hitInfo, this.tooltipCtx);
59
+ } else if (type === 'heatMap') {
60
+ this.drawToolTipForHeatMap(hitInfo, this.tooltipCtx);
59
61
  } else {
60
62
  this.drawTooltip(hitInfo, this.tooltipCtx);
61
63
  }
@@ -112,7 +114,7 @@ const modules = {
112
114
  this.render(hitInfo);
113
115
  }
114
116
 
115
- ({ label: args.label, value: args.value, sId: args.seriesId } = hitInfo);
117
+ ({ label: args.label, value: args.value, sId: args.seriesId, acc: args.acc } = hitInfo);
116
118
  }
117
119
 
118
120
  if (typeof this.listeners['dbl-click'] === 'function') {
@@ -140,16 +142,24 @@ const modules = {
140
142
  value: args.value,
141
143
  sId: args.seriesId,
142
144
  maxIndex: args.dataIndex,
145
+ acc: args.acc,
143
146
  } = hitInfo);
144
- }
145
-
146
- if (this.options.selectLabel.use) {
147
+ } else if (this.options.selectLabel.use) {
147
148
  const offset = this.getMousePosition(e);
148
149
  const clickedLabelInfo = this.getLabelInfoByPosition(offset);
149
150
  const selected = this.selectLabel(clickedLabelInfo.labelIndex);
150
- this.renderWithSelectLabel(selected.dataIndex);
151
+ this.renderWithSelected(selected.dataIndex);
152
+
153
+ args.selected = cloneDeep(this.defaultSelectInfo);
154
+ } else if (this.options.selectSeries.use) {
155
+ const offset = this.getMousePosition(e);
156
+ const hitInfo = this.getSeriesIdByPosition(offset);
157
+ if (hitInfo.sId !== null) {
158
+ const selected = this.selectSeries(hitInfo.sId);
159
+ this.renderWithSelected(selected.seriesId);
160
+ }
151
161
 
152
- args.selected = cloneDeep(this.defaultSelectLabelInfo);
162
+ args.selected = cloneDeep(this.defaultSelectInfo);
153
163
  }
154
164
 
155
165
  if (typeof this.listeners.click === 'function') {
@@ -453,28 +463,51 @@ const modules = {
453
463
  },
454
464
 
455
465
  /**
456
- * render after select label by index list
466
+ * render after selected label or selected series
457
467
  * @param indexList {array} '[0, 1 ...]'
458
468
  */
459
- renderWithSelectLabel(indexList) {
460
- this.defaultSelectLabelInfo.dataIndex = indexList;
461
- this.initSelectedLabelInfo();
469
+ renderWithSelected(list) {
470
+ if (this.options.selectLabel.use) {
471
+ this.defaultSelectInfo.dataIndex = list;
472
+ } else if (this.options.selectSeries.use) {
473
+ this.defaultSelectInfo.seriesId = list;
474
+ }
475
+ this.initSelectedInfo();
462
476
  this.render();
463
477
  },
464
478
 
465
479
  /**
466
- * init defaultSelectLabelInfo object.
467
- * (set each series data and label text)
480
+ * init defaultSelectInfo object.
481
+ * - at selectLabel using: set each series data and label text
482
+ * - at selectSeries using: set series state
468
483
  */
469
- initSelectedLabelInfo() {
470
- const { use, limit } = this.options.selectLabel;
471
- const infoObj = this.defaultSelectLabelInfo;
472
- if (use && infoObj?.dataIndex) {
484
+ initSelectedInfo() {
485
+ if (this.options.selectLabel.use) {
486
+ const { limit } = this.options.selectLabel;
487
+ if (!this.defaultSelectInfo) {
488
+ this.defaultSelectInfo = { dataIndex: [] };
489
+ }
490
+ const infoObj = this.defaultSelectInfo;
473
491
  infoObj.dataIndex.splice(limit);
474
492
  infoObj.label = infoObj.dataIndex.map(i => this.data.labels[i]);
475
493
  const dataEntries = Object.entries(this.data.data);
476
494
  infoObj.data = infoObj.dataIndex.map(labelIdx => Object.fromEntries(
477
495
  dataEntries.map(([sId, data]) => [sId, data[labelIdx]])));
496
+ } else if (this.options.selectSeries.use) {
497
+ if (!this.defaultSelectInfo) {
498
+ this.defaultSelectInfo = { seriesId: [] };
499
+ }
500
+
501
+ const selectedList = this.defaultSelectInfo.seriesId;
502
+ Object.values(this.seriesList).forEach((series) => {
503
+ if (!selectedList.length) {
504
+ series.state = 'normal';
505
+ } else if (selectedList.includes(series.sId)) {
506
+ series.state = 'highlight';
507
+ } else {
508
+ series.state = 'downplay';
509
+ }
510
+ });
478
511
  }
479
512
  },
480
513
 
@@ -485,7 +518,7 @@ const modules = {
485
518
  */
486
519
  selectLabel(labelIndex) {
487
520
  const option = this.options?.selectLabel ?? {};
488
- const before = this.defaultSelectLabelInfo ?? { dataIndex: [] };
521
+ const before = this.defaultSelectInfo ?? { dataIndex: [] };
489
522
  const after = cloneDeep(before);
490
523
 
491
524
  if (before.dataIndex.includes(labelIndex)) {
@@ -505,6 +538,28 @@ const modules = {
505
538
  return after;
506
539
  },
507
540
 
541
+ selectSeries(seriesId) {
542
+ const option = this.options?.selectSeries ?? {};
543
+ const before = this.defaultSelectInfo ?? { seriesId: [] };
544
+ const after = cloneDeep(before);
545
+
546
+ if (before.seriesId.includes(seriesId)) {
547
+ const idx = before.seriesId.indexOf(seriesId);
548
+ after.seriesId.splice(idx, 1);
549
+ } else if (seriesId) {
550
+ after.seriesId.push(seriesId);
551
+ if (option.limit > 0 && option.limit < after.seriesId.length) {
552
+ if (option.useDeselectOverflow) {
553
+ after.seriesId.splice(0, 1);
554
+ } else {
555
+ after.seriesId.pop();
556
+ }
557
+ }
558
+ }
559
+
560
+ return after;
561
+ },
562
+
508
563
  /**
509
564
  * Find items by series within a range
510
565
  * @param {object} range object for find series items
@@ -80,10 +80,12 @@ const modules = {
80
80
  Object.values(seriesList).forEach((series) => {
81
81
  if (!series.isExistGrp && series.showLegend) {
82
82
  const { colorAxis, valueOpt } = series;
83
+ const { max, interval, existError } = valueOpt;
83
84
  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
85
+ const minValue = interval * index;
86
+ const maxValue = index === colorAxis.length - 1
87
+ ? max : minValue + interval - 1;
88
+ const name = existError && index === colorAxis.length - 1
87
89
  ? 'error' : `${minValue} - ${maxValue}`;
88
90
  this.addLegend({
89
91
  cId: colorItem.id,
@@ -189,9 +191,13 @@ const modules = {
189
191
  }
190
192
  const nameDOM = targetDOM.getElementsByClassName('ev-chart-legend-name')[0];
191
193
  const targetId = nameDOM.series.sId;
194
+ const selectSeriesOption = this.options.selectSeries;
195
+ const selectedList = this.defaultSelectInfo?.seriesId ?? [];
192
196
 
193
197
  Object.values(this.seriesList).forEach((series) => {
194
- series.state = series.sId === targetId ? 'highlight' : 'downplay';
198
+ series.state = series.sId === targetId
199
+ || (selectSeriesOption.use && selectedList.includes(targetId))
200
+ ? 'highlight' : 'downplay';
195
201
  });
196
202
 
197
203
  this.update({
@@ -207,8 +213,15 @@ const modules = {
207
213
  * @returns {undefined}
208
214
  */
209
215
  this.onLegendBoxLeave = () => {
216
+ const selectSeriesOption = this.options.selectSeries;
217
+ const selectedList = this.defaultSelectInfo?.seriesId ?? [];
210
218
  Object.values(this.seriesList).forEach((series) => {
211
- series.state = 'normal';
219
+ if (selectSeriesOption.use && selectedList.length) {
220
+ series.state = selectedList.includes(series.sId)
221
+ ? 'highlight' : 'downplay';
222
+ } else {
223
+ series.state = 'normal';
224
+ }
212
225
  });
213
226
 
214
227
  this.update({