evui 3.3.31 → 3.3.34

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.
@@ -1,3 +1,5 @@
1
+ import Util from '../helpers/helpers.util';
2
+
1
3
  const modules = {
2
4
  /**
3
5
  * Create legend DOM
@@ -18,10 +20,48 @@ const modules = {
18
20
  this.wrapperDOM.appendChild(this.resizeDOM);
19
21
  }
20
22
 
23
+ if (this.useTable) {
24
+ this.legendTableDOM = document.createElement('table');
25
+ this.legendTableDOM.className = 'ev-chart-legend--table';
26
+ this.setLegendColumnHeader();
27
+ this.legendBoxDOM.appendChild(this.legendTableDOM);
28
+ this.legendDOM.style.overflow = 'auto';
29
+ }
30
+
21
31
  this.legendDOM.appendChild(this.legendBoxDOM);
22
32
  this.wrapperDOM.appendChild(this.legendDOM);
23
33
  },
24
34
 
35
+ /**
36
+ * Create and append Table Header DOM
37
+ * Only chartOption > legend > table > use : true
38
+ *
39
+ * @returns {undefined}
40
+ */
41
+ setLegendColumnHeader() {
42
+ const tableOpt = this.options.legend?.table;
43
+ const columns = tableOpt.columns;
44
+ const columnKeyList = ['color', ...Object.keys(columns)];
45
+
46
+ columnKeyList.forEach((key) => {
47
+ const columnNameDOM = document.createElement('th');
48
+ columnNameDOM.className = 'ev-chart-legend--table__column-name';
49
+
50
+ if (columns[key]?.use || key === 'color' || key === 'name') {
51
+ const columnOpt = columns[key];
52
+ const keyText = columnOpt?.title ?? '';
53
+
54
+ columnNameDOM.textContent = keyText;
55
+ columnNameDOM.setAttribute('title', keyText);
56
+ columnNameDOM.dataset.type = keyText;
57
+
58
+ Util.setDOMStyle(columnNameDOM, tableOpt?.style?.header);
59
+
60
+ this.legendTableDOM.append(columnNameDOM);
61
+ }
62
+ });
63
+ },
64
+
25
65
  /**
26
66
  * Initialize legend
27
67
  * If there was no initialization, create DOM and set default layout.
@@ -31,6 +71,8 @@ const modules = {
31
71
  */
32
72
  initLegend() {
33
73
  this.isHeatMapType = this.options.type === 'heatMap';
74
+ this.useTable = !!this.options.legend?.table?.use && this.options.type !== 'heatmap' && this.options.type !== 'scatter';
75
+
34
76
  if (!this.isInitLegend) {
35
77
  this.createLegendLayout();
36
78
  }
@@ -42,6 +84,7 @@ const modules = {
42
84
  this.initEvent();
43
85
  this.addLegendList();
44
86
  }
87
+
45
88
  this.initResizeEvent();
46
89
 
47
90
  this.isInitLegend = true;
@@ -61,19 +104,37 @@ const modules = {
61
104
 
62
105
  groups.forEach((group) => {
63
106
  group.slice().reverse().forEach((sId) => {
64
- if (seriesList[sId] && seriesList[sId].showLegend) {
65
- this.addLegend(seriesList[sId]);
107
+ const series = seriesList[sId];
108
+
109
+ if (series && series.showLegend) {
110
+ if (this.useTable) {
111
+ this.addLegendWithValues(series);
112
+ } else {
113
+ this.addLegend(series);
114
+ }
66
115
  }
67
116
  });
68
117
  });
69
118
 
70
119
  Object.values(seriesList).forEach((series) => {
71
- if (!series.isExistGrp && series.showLegend) {
120
+ if (series.isExistGrp || !series.showLegend) {
121
+ return;
122
+ }
123
+
124
+ if (this.useTable) {
125
+ this.addLegendWithValues(series);
126
+ } else {
72
127
  this.addLegend(series);
73
128
  }
74
129
  });
75
130
  },
76
131
 
132
+ /**
133
+ * Add Legend with Color Information
134
+ * Only Heatmap chart
135
+ *
136
+ * @returns {undefined}
137
+ */
77
138
  addColorLegendList() {
78
139
  const seriesList = this.seriesList;
79
140
 
@@ -118,6 +179,31 @@ const modules = {
118
179
  });
119
180
  },
120
181
 
182
+ /**
183
+ * Get Container DOM by Event Object
184
+ * @param e Event
185
+ *
186
+ * @returns {Element}
187
+ */
188
+ getContainerDOM(e) {
189
+ let targetDOM = null;
190
+ const type = e.target.dataset.type;
191
+
192
+ const childTypes = ['name', 'color', 'min', 'max', 'avg', 'total', 'last'];
193
+
194
+ if (type === 'container') {
195
+ targetDOM = e.target;
196
+ } else if (childTypes.includes(type)) {
197
+ targetDOM = e.target.parentElement;
198
+
199
+ if (!targetDOM?.series) {
200
+ targetDOM = targetDOM.parentElement;
201
+ }
202
+ }
203
+
204
+ return targetDOM;
205
+ },
206
+
121
207
  /**
122
208
  * Initialize legend event
123
209
  *
@@ -127,6 +213,14 @@ const modules = {
127
213
  if (this.isInitLegend) {
128
214
  return;
129
215
  }
216
+
217
+ const classList = {
218
+ container: `ev-chart-legend${this.useTable ? '--table__container' : '-container'}`,
219
+ color: `ev-chart-legend${this.useTable ? '--table__color' : '-color'}`,
220
+ name: `ev-chart-legend${this.useTable ? '--table__name' : '-name'}`,
221
+ value: `ev-chart-legend${this.useTable ? '--table__value' : '-value'}`,
222
+ };
223
+
130
224
  /**
131
225
  * callback for legendBoxDOM to show/hide clicked series
132
226
  *
@@ -134,22 +228,19 @@ const modules = {
134
228
  */
135
229
  this.onLegendBoxClick = (e) => {
136
230
  const opt = this.options.legend;
137
- const type = e.target.dataset.type;
138
231
 
139
- let targetDOM;
140
- if (type === 'container') {
141
- targetDOM = e.target;
142
- } else if (type === 'name' || type === 'color') {
143
- targetDOM = e.target.parentElement;
144
- } else {
232
+ const targetDOM = this.getContainerDOM(e);
233
+ if (!targetDOM) {
145
234
  return;
146
235
  }
147
236
 
148
- const colorDOM = targetDOM?.getElementsByClassName('ev-chart-legend-color')[0];
149
- const nameDOM = targetDOM?.getElementsByClassName('ev-chart-legend-name')[0];
150
- const isActive = !colorDOM?.className.includes('inactive');
151
- const series = nameDOM?.series;
237
+ const series = targetDOM?.series;
238
+
239
+ const colorDOM = targetDOM?.getElementsByClassName(classList.color)[0];
240
+ const nameDOM = targetDOM?.getElementsByClassName(classList.name)[0];
241
+ const valueDOMList = targetDOM?.getElementsByClassName(classList.value);
152
242
 
243
+ const isActive = !targetDOM?.className.includes('inactive');
153
244
  if (isActive && this.seriesInfo.count === 1) {
154
245
  return;
155
246
  }
@@ -160,9 +251,14 @@ const modules = {
160
251
 
161
252
  if (isActive) {
162
253
  this.seriesInfo.count--;
163
- colorDOM.style.backgroundColor = opt.inactive;
164
- colorDOM.style.borderColor = opt.inactive;
165
- nameDOM.style.color = opt.inactive;
254
+
255
+ const inactiveColor = opt.inactive;
256
+ colorDOM.style.backgroundColor = inactiveColor;
257
+ colorDOM.style.borderColor = inactiveColor;
258
+ nameDOM.style.color = inactiveColor;
259
+ valueDOMList?.forEach((dom) => {
260
+ dom.style.color = inactiveColor;
261
+ });
166
262
  } else {
167
263
  this.seriesInfo.count++;
168
264
 
@@ -182,11 +278,14 @@ const modules = {
182
278
  }
183
279
 
184
280
  nameDOM.style.color = opt.color;
281
+ valueDOMList?.forEach((dom) => {
282
+ const style = opt.table?.columns[dom.dataset.type]?.style;
283
+ dom.style.color = style?.color ? style.color : opt.color;
284
+ });
185
285
  }
186
286
 
187
287
  series.show = !series.show;
188
- colorDOM.classList.toggle('inactive');
189
- nameDOM.classList.toggle('inactive');
288
+ targetDOM.classList.toggle('inactive');
190
289
 
191
290
  this.update({
192
291
  updateSeries: false,
@@ -200,18 +299,12 @@ const modules = {
200
299
  * @returns {undefined}
201
300
  */
202
301
  this.onLegendBoxOver = (e) => {
203
- const type = e.target.dataset.type;
204
-
205
- let targetDOM;
206
- if (type === 'container') {
207
- targetDOM = e.target;
208
- } else if (type === 'name' || type === 'color') {
209
- targetDOM = e.target.parentElement;
210
- } else {
302
+ const targetDOM = this.getContainerDOM(e);
303
+ if (!targetDOM) {
211
304
  return;
212
305
  }
213
- const nameDOM = targetDOM.getElementsByClassName('ev-chart-legend-name')[0];
214
- const targetId = nameDOM.series.sId;
306
+
307
+ const targetId = targetDOM?.series?.sId;
215
308
  const legendHitInfo = { sId: targetId, type: this.options.type };
216
309
 
217
310
  this.update({
@@ -245,10 +338,15 @@ const modules = {
245
338
  this.initResizeEvent();
246
339
  },
247
340
 
341
+ /**
342
+ * Init Event on Color Legend
343
+ * Only Heatmap
344
+ */
248
345
  initEventForColorLegend() {
249
346
  if (this.isInitLegend) {
250
347
  return;
251
348
  }
349
+
252
350
  /**
253
351
  * callback for legendBoxDOM to show/hide clicked series
254
352
  *
@@ -257,21 +355,16 @@ const modules = {
257
355
  this.onLegendBoxClick = (e) => {
258
356
  const opt = this.options.legend;
259
357
  const series = Object.values(this.seriesList)[0];
260
- const type = e.target.dataset.type;
261
358
 
262
- let targetDOM;
263
- if (type === 'container') {
264
- targetDOM = e.target;
265
- } else if (type === 'name' || type === 'color') {
266
- targetDOM = e.target.parentElement;
267
- } else {
359
+ const targetDOM = this.getContainerDOM(e);
360
+ if (!targetDOM) {
268
361
  return;
269
362
  }
270
363
 
271
364
  const colorDOM = targetDOM?.getElementsByClassName('ev-chart-legend-color')[0];
272
365
  const nameDOM = targetDOM?.getElementsByClassName('ev-chart-legend-name')[0];
366
+ const targetId = targetDOM?.series?.cId;
273
367
  const isActive = !colorDOM?.className.includes('inactive');
274
- const targetId = nameDOM.series.cId;
275
368
  const activeCount = series.colorState.filter(colorItem => colorItem.show).length;
276
369
 
277
370
  if (isActive && activeCount === 1) {
@@ -287,7 +380,7 @@ const modules = {
287
380
  colorDOM.style.borderColor = opt.inactive;
288
381
  nameDOM.style.color = opt.inactive;
289
382
  } else {
290
- colorDOM.style.backgroundColor = nameDOM.series.color;
383
+ colorDOM.style.backgroundColor = targetDOM?.series?.color;
291
384
  nameDOM.style.color = opt.color;
292
385
  }
293
386
 
@@ -304,25 +397,21 @@ const modules = {
304
397
  updateSelTip: { update: true, keepDomain: true },
305
398
  });
306
399
  };
400
+
307
401
  /**
308
402
  * callback for legendBoxDOM hovering
309
403
  *
310
404
  * @returns {undefined}
311
405
  */
312
406
  this.onLegendBoxOver = (e) => {
313
- const type = e.target.dataset.type;
314
- const series = Object.values(this.seriesList)[0];
407
+ const series = Object.values(this.seriesList)?.[0];
315
408
 
316
- let targetDOM;
317
- if (type === 'container') {
318
- targetDOM = e.target;
319
- } else if (type === 'name' || type === 'color') {
320
- targetDOM = e.target.parentElement;
321
- } else {
409
+ const targetDOM = this.getContainerDOM(e);
410
+ if (!targetDOM) {
322
411
  return;
323
412
  }
324
- const nameDOM = targetDOM.getElementsByClassName('ev-chart-legend-name')[0];
325
- const targetId = nameDOM.series.cId;
413
+
414
+ const targetId = targetDOM?.series?.cId;
326
415
 
327
416
  series.colorState.forEach((colorItem) => {
328
417
  colorItem.state = colorItem.id === targetId ? 'highlight' : 'downplay';
@@ -350,6 +439,7 @@ const modules = {
350
439
  updateSelTip: { update: false, keepDomain: false },
351
440
  });
352
441
  };
442
+
353
443
  this.legendBoxDOM.addEventListener('click', this.onLegendBoxClick);
354
444
  this.legendBoxDOM.addEventListener('mouseover', this.onLegendBoxOver);
355
445
  this.legendBoxDOM.addEventListener('mouseleave', this.onLegendBoxLeave);
@@ -411,6 +501,7 @@ const modules = {
411
501
  */
412
502
  updateLegend() {
413
503
  this.resetLegend();
504
+
414
505
  if (this.isHeatMapType) {
415
506
  this.addColorLegendList();
416
507
  } else {
@@ -418,21 +509,80 @@ const modules = {
418
509
  }
419
510
  },
420
511
 
512
+ /**
513
+ * To update value text on legend table
514
+ * Only chartOption > legend > table > use : true
515
+ *
516
+ * @returns {undefined}
517
+ */
518
+ updateLegendTableValues() {
519
+ const columns = this.options?.legend?.table?.columns;
520
+ const aggregations = this.getAggregations();
521
+ const rowDOMList = this.legendBoxDOM?.getElementsByClassName('ev-chart-legend--table__row');
522
+
523
+ rowDOMList.forEach((row) => {
524
+ const valueDOMList = row?.getElementsByClassName('ev-chart-legend--table__value');
525
+
526
+ valueDOMList.forEach((dom) => {
527
+ const key = dom.dataset.type;
528
+ if (key === 'name') {
529
+ return;
530
+ }
531
+
532
+ const seriesId = row.series.sId;
533
+ const value = +aggregations?.[seriesId]?.[key];
534
+ dom.textContent = this.getFormattedValue(columns[key], value);
535
+ });
536
+ });
537
+ },
538
+
539
+ /**
540
+ * Force Update Legend. Remove and Create
541
+ *
542
+ * @returns {undefined}
543
+ */
544
+ forceUpdateLegend() {
545
+ this.destroyLegend();
546
+ this.initLegend();
547
+ },
548
+
421
549
  /**
422
550
  * To update legend, remove all of legendBoxDOM's children
423
551
  *
424
552
  * @returns {undefined}
425
553
  */
426
554
  resetLegend() {
427
- const legendDOM = this.legendBoxDOM;
555
+ const legendBoxDOM = this.legendBoxDOM;
428
556
 
429
- if (!legendDOM) {
557
+ if (!legendBoxDOM) {
430
558
  return;
431
559
  }
432
560
 
433
- while (legendDOM.hasChildNodes()) {
434
- legendDOM.removeChild(legendDOM.firstChild);
561
+ while (legendBoxDOM.hasChildNodes()) {
562
+ legendBoxDOM.removeChild(legendBoxDOM.firstChild);
435
563
  }
564
+
565
+ this.seriesInfo.count = 0;
566
+ },
567
+
568
+ /**
569
+ * To update legend, remove all of legendBoxDOM's children
570
+ *
571
+ * @returns {undefined}
572
+ */
573
+ destroyLegend() {
574
+ const legendDOM = this.legendDOM;
575
+
576
+ if (!legendDOM) {
577
+ return;
578
+ }
579
+
580
+ legendDOM.remove();
581
+
582
+ this.legendDOM = null;
583
+ this.legendBoxDOM = null;
584
+ this.resizeDOM = null;
585
+ this.isInitLegend = false;
436
586
  this.seriesInfo.count = 0;
437
587
  },
438
588
 
@@ -447,7 +597,9 @@ const modules = {
447
597
  const colorDOM = document.createElement('span');
448
598
  const nameDOM = document.createElement('div');
449
599
 
450
- containerDOM.className = 'ev-chart-legend-container';
600
+ containerDOM.className = `ev-chart-legend-container ${!series.show ? ' inactive' : ''}`;
601
+ containerDOM.series = series;
602
+
451
603
  colorDOM.className = 'ev-chart-legend-color';
452
604
 
453
605
  if (series.type === 'line' && series.point && !series.fill) {
@@ -455,10 +607,12 @@ const modules = {
455
607
  }
456
608
 
457
609
  nameDOM.className = 'ev-chart-legend-name';
458
- nameDOM.series = series;
459
610
 
611
+ // set series color
460
612
  let seriesColor;
461
- if (typeof series.color !== 'string') {
613
+ if (!series.show) {
614
+ seriesColor = opt.inactive;
615
+ } else if (typeof series.color !== 'string') {
462
616
  seriesColor = series.color[series.color.length - 1][1];
463
617
  } else {
464
618
  seriesColor = series.color;
@@ -466,7 +620,7 @@ const modules = {
466
620
 
467
621
  if (series.type === 'line' && series.fill) {
468
622
  colorDOM.style.height = '8px';
469
- colorDOM.style.backgroundColor = `${seriesColor}80`;
623
+ colorDOM.style.backgroundColor = series.show ? `${seriesColor}80` : opt.inactive;
470
624
  colorDOM.style.border = `1px solid ${seriesColor}`;
471
625
  } else {
472
626
  colorDOM.style.backgroundColor = seriesColor;
@@ -495,7 +649,130 @@ const modules = {
495
649
  containerDOM.dataset.type = 'container';
496
650
 
497
651
  this.legendBoxDOM.appendChild(containerDOM);
498
- this.seriesInfo.count++;
652
+ if (series.show) {
653
+ this.seriesInfo.count++;
654
+ }
655
+ },
656
+
657
+ /**
658
+ * Add Legend Items With aggregation Values
659
+ * Only chartOption > legend > table > use : true
660
+ * @param series
661
+ */
662
+ addLegendWithValues(series) {
663
+ const opt = this.options.legend;
664
+ const columns = opt?.table?.columns;
665
+
666
+ const aggregations = this.getAggregations()?.[series?.sId];
667
+ if (!aggregations || !columns) {
668
+ return;
669
+ }
670
+
671
+ // create row
672
+ const rowDOM = document.createElement('tr');
673
+ rowDOM.className = `ev-chart-legend--table__row ${!series.show ? ' inactive' : ''}`;
674
+ Util.setDOMStyle(rowDOM, opt.table?.style?.row);
675
+ rowDOM.series = series;
676
+ rowDOM.dataset.type = 'container';
677
+
678
+ // create td - color
679
+ const colorWrapperDOM = document.createElement('td');
680
+ colorWrapperDOM.className = 'ev-chart-legend--table__color-wrapper';
681
+ colorWrapperDOM.dataset.type = 'color';
682
+
683
+ const colorDOM = document.createElement('div');
684
+ colorDOM.className = 'ev-chart-legend--table__color';
685
+ colorDOM.dataset.type = 'color';
686
+
687
+ // set series color
688
+ let seriesColor;
689
+ if (!series.show) {
690
+ seriesColor = opt.inactive;
691
+ } else if (typeof series.color !== 'string') {
692
+ seriesColor = series.color[series.color.length - 1][1];
693
+ } else {
694
+ seriesColor = series.color;
695
+ }
696
+
697
+ switch (series.type) {
698
+ case 'line': {
699
+ if (series.fill) {
700
+ colorDOM.style.backgroundColor = `${seriesColor}80`;
701
+ colorDOM.style.border = `1px solid ${seriesColor}`;
702
+ } else {
703
+ if (series.point) {
704
+ colorDOM.className += ' ev-chart-legend--table__color--point-line';
705
+ }
706
+
707
+ colorDOM.className += ' ev-chart-legend--table__color--line';
708
+ colorDOM.style.backgroundColor = seriesColor;
709
+ }
710
+ break;
711
+ }
712
+
713
+ case 'bar':
714
+ case 'pie':
715
+ default: {
716
+ colorDOM.style.height = '10px';
717
+ colorDOM.style.backgroundColor = seriesColor;
718
+ break;
719
+ }
720
+ }
721
+
722
+ if (series.type === 'line' && series.fill) {
723
+ colorDOM.style.height = '8px';
724
+ colorDOM.style.backgroundColor = series.show ? `${seriesColor}80` : opt.inactive;
725
+ colorDOM.style.border = `1px solid ${seriesColor}`;
726
+ } else {
727
+ colorDOM.style.backgroundColor = seriesColor;
728
+ }
729
+
730
+ colorWrapperDOM.appendChild(colorDOM);
731
+ rowDOM.appendChild(colorWrapperDOM);
732
+
733
+ // create td - name
734
+ const nameDOM = document.createElement('td');
735
+ nameDOM.className = 'ev-chart-legend--table__name';
736
+ nameDOM.style.color = series.show ? opt.color : opt.inactive;
737
+ nameDOM.textContent = series.name;
738
+ nameDOM.setAttribute('title', series.name);
739
+ nameDOM.dataset.type = 'name';
740
+ Util.setDOMStyle(nameDOM, columns?.name?.style);
741
+
742
+ if (!series.show) {
743
+ nameDOM.style.color = opt.inactive;
744
+ }
745
+
746
+ rowDOM.appendChild(nameDOM);
747
+
748
+ // create td - values
749
+ const columnKeyList = Object.keys(columns);
750
+ columnKeyList?.forEach((key) => {
751
+ if (key === 'name') {
752
+ return;
753
+ }
754
+
755
+ if (columns[key].use) {
756
+ const formattedTxt = this.getFormattedValue(columns[key], +aggregations[key]);
757
+ const valueDOM = document.createElement('td');
758
+ valueDOM.className = 'ev-chart-legend--table__value';
759
+ valueDOM.style.color = series.show ? opt.color : opt.inactive;
760
+ valueDOM.textContent = formattedTxt;
761
+ valueDOM.dataset.type = key.toString();
762
+ Util.setDOMStyle(valueDOM, columns[key]?.style);
763
+
764
+ if (!series.show) {
765
+ valueDOM.style.color = opt.inactive;
766
+ }
767
+
768
+ rowDOM.appendChild(valueDOM);
769
+ }
770
+ });
771
+
772
+ this.legendTableDOM.appendChild(rowDOM);
773
+ if (series.show) {
774
+ this.seriesInfo.count++;
775
+ }
499
776
  },
500
777
 
501
778
  /**
@@ -664,6 +941,7 @@ const modules = {
664
941
  }
665
942
  }
666
943
  },
944
+
667
945
  /**
668
946
  * When user moves resizeDOM, this function will change css
669
947
  *
@@ -843,6 +1121,28 @@ const modules = {
843
1121
  legendStyle.height = '0';
844
1122
  wrapperStyle.padding = `${title}px 0 0 0`;
845
1123
  },
1124
+
1125
+ /**
1126
+ * Get formatted value by formatter function
1127
+ * Only chartOption > legend > table > use : true
1128
+ * @param formatter
1129
+ * @param decimalPoint
1130
+ * @param value
1131
+ * @returns {string}
1132
+ */
1133
+ getFormattedValue({ formatter, decimalPoint }, value) {
1134
+ let formattedTxt;
1135
+ if (formatter) {
1136
+ formattedTxt = formatter(value);
1137
+ }
1138
+
1139
+ if (!formatter || typeof formattedTxt !== 'string') {
1140
+ formattedTxt = Util.labelSignFormat(value, decimalPoint);
1141
+ }
1142
+
1143
+ return formattedTxt;
1144
+ },
1145
+
846
1146
  };
847
1147
 
848
1148
  export default modules;
@@ -47,6 +47,10 @@ const modules = {
47
47
  radius -= pieOption.pieStroke.lineWidth;
48
48
  }
49
49
 
50
+ if (radius < 0) {
51
+ return;
52
+ }
53
+
50
54
  pie.or = radius;
51
55
  if (ix < pieDataSet.length - 1) {
52
56
  pie.ir = outerRadius - (((outerRadius - innerRadius) / pieDataSet.length) * (ix + 1));
@@ -140,6 +144,10 @@ const modules = {
140
144
  radius -= pieOption.pieStroke.lineWidth;
141
145
  }
142
146
 
147
+ if (radius < 0) {
148
+ return;
149
+ }
150
+
143
151
  pie.or = radius;
144
152
  if (ix < pieDataSet.length - 1) {
145
153
  pie.ir = outerRadius - (((outerRadius - innerRadius) / pieDataSet.length) * (ix + 1));