evui 3.3.7 → 3.3.10

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 (33) hide show
  1. package/dist/evui.common.js +2973 -989
  2. package/dist/evui.common.js.map +1 -1
  3. package/dist/evui.umd.js +2973 -989
  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 +16 -4
  9. package/src/components/chart/chart.core.js +39 -14
  10. package/src/components/chart/element/element.bar.js +9 -3
  11. package/src/components/chart/element/element.heatmap.js +213 -0
  12. package/src/components/chart/element/element.pie.js +104 -13
  13. package/src/components/chart/element/element.tip.js +125 -4
  14. package/src/components/chart/helpers/helpers.constant.js +22 -0
  15. package/src/components/chart/helpers/helpers.util.js +8 -0
  16. package/src/components/chart/model/model.series.js +4 -0
  17. package/src/components/chart/model/model.store.js +207 -30
  18. package/src/components/chart/plugins/plugins.interaction.js +91 -12
  19. package/src/components/chart/plugins/plugins.legend.js +212 -42
  20. package/src/components/chart/plugins/plugins.pie.js +54 -46
  21. package/src/components/chart/plugins/plugins.tooltip.js +87 -1
  22. package/src/components/chart/scale/scale.js +12 -2
  23. package/src/components/chart/scale/scale.step.js +12 -5
  24. package/src/components/chart/scale/scale.time.category.js +12 -2
  25. package/src/components/chart/uses.js +28 -3
  26. package/src/components/grid/Grid.vue +201 -108
  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/uses.js +105 -24
  30. package/src/components/pagination/Pagination.vue +271 -0
  31. package/src/components/pagination/index.js +7 -0
  32. package/src/components/pagination/pageButton.vue +31 -0
  33. package/src/main.js +3 -0
@@ -3,13 +3,16 @@ const modules = {
3
3
  /**
4
4
  * Draw series data
5
5
  *
6
+ * @params hitInfo
7
+ *
6
8
  * @returns {undefined}
7
9
  */
8
- drawPie() {
10
+ drawPie(hitInfo) {
9
11
  const ctx = this.bufferCtx;
10
12
  const chartRect = this.chartRect;
11
13
  const pieDataSet = this.pieDataSet;
12
14
  const pieOption = this.options;
15
+ const padding = this.options.padding;
13
16
  const isDoughnut = !!pieOption.doughnutHoleSize;
14
17
 
15
18
  let slice;
@@ -22,8 +25,10 @@ const modules = {
22
25
  const centerX = chartRect.width / 2;
23
26
  const centerY = chartRect.height / 2;
24
27
 
25
- const innerRadius = Math.min(centerX, centerY) * pieOption.doughnutHoleSize;
26
- const outerRadius = Math.min(centerX, centerY);
28
+ const chartWidth = centerX - (padding.left + padding.right);
29
+ const chartHeight = centerY - (padding.bottom + padding.top);
30
+ const innerRadius = Math.min(chartWidth, chartHeight) * pieOption.doughnutHoleSize;
31
+ const outerRadius = Math.min(chartWidth, chartHeight);
27
32
 
28
33
  for (let ix = 0; ix < pieDataSet.length; ix++) {
29
34
  const pie = pieDataSet[ix];
@@ -55,55 +60,59 @@ const modules = {
55
60
  series = this.seriesList[slice.id];
56
61
 
57
62
  if (value) {
63
+ const strokeOptions = { ...pieOption.pieStroke };
64
+ if (pie.data.length === 1 && pieOption.pieStroke.use) {
65
+ strokeOptions.use = false;
66
+
67
+ ctx.lineWidth = pieOption.pieStroke.lineWidth;
68
+ ctx.strokeStyle = pieOption.pieStroke.color;
69
+ ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI);
70
+ ctx.stroke();
71
+ }
72
+
73
+ series.isSelect = hitInfo?.sId === slice.id;
58
74
  series.type = isDoughnut ? 'doughnut' : 'pie';
59
75
  series.centerX = centerX;
60
76
  series.centerY = centerY;
61
77
  series.radius = radius;
78
+ series.doughnutHoleSize = radius * (pieOption.doughnutHoleSize ?? 0);
62
79
  series.startAngle = startAngle;
63
80
  series.endAngle = endAngle;
64
81
  series.data = { o: value };
65
82
 
66
- series.draw(ctx);
83
+ series.draw(ctx, strokeOptions);
67
84
  startAngle += sliceAngle;
68
85
  }
69
86
  }
70
87
  }
71
-
72
- ctx.beginPath();
73
- if (pieOption?.pieStroke?.use) {
74
- ctx.lineWidth = pieOption.pieStroke.lineWidth;
75
- ctx.strokeStyle = pieOption.pieStroke.color;
76
- ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI);
77
- ctx.stroke();
78
- } else {
79
- ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI);
80
- }
81
-
82
- ctx.closePath();
83
88
  }
84
89
  },
85
90
 
86
91
  /**
87
92
  * Draw series data
88
93
  *
94
+ * @params hitInfo
95
+ *
89
96
  * @returns {undefined}
90
97
  */
91
- drawSunburst() {
98
+ drawSunburst(hitInfo) {
92
99
  const ctx = this.bufferCtx;
93
- const chartRect = this.chartRect;
100
+ const { width, height } = this.chartRect;
94
101
  const pieDataSet = this.pieDataSet;
95
102
  const pieOption = this.options;
103
+ const padding = this.options.padding;
96
104
 
97
105
  this.calculateAngle();
98
106
 
99
107
  let slice;
100
108
  let series;
101
109
 
102
- const centerX = chartRect.width / 2;
103
- const centerY = chartRect.height / 2;
104
-
105
- const innerRadius = Math.min(centerX, centerY) * pieOption.doughnutHoleSize;
106
- const outerRadius = Math.min(centerX, centerY);
110
+ const centerX = width / 2;
111
+ const centerY = height / 2;
112
+ const chartWidth = centerX - (padding.left + padding.right);
113
+ const chartHeight = centerY - (padding.bottom + padding.top);
114
+ const innerRadius = Math.min(chartWidth, chartHeight) * pieOption.doughnutHoleSize;
115
+ const outerRadius = Math.min(chartWidth, chartHeight);
107
116
 
108
117
  for (let ix = 0; ix < pieDataSet.length; ix++) {
109
118
  const pie = pieDataSet[ix];
@@ -143,31 +152,30 @@ const modules = {
143
152
  series = this.seriesList[slice.id];
144
153
 
145
154
  if (slice.value) {
155
+ const strokeOptions = { ...pieOption.pieStroke };
156
+ if (pie.data.length === 1 && pieOption.pieStroke.use) {
157
+ strokeOptions.use = false;
158
+
159
+ ctx.lineWidth = pieOption.pieStroke.lineWidth;
160
+ ctx.strokeStyle = pieOption.pieStroke.color;
161
+ ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI);
162
+ ctx.stroke();
163
+ }
164
+
165
+ series.isSelect = hitInfo?.sId === slice.id;
146
166
  series.type = 'sunburst';
147
167
  series.centerX = centerX;
148
168
  series.centerY = centerY;
149
169
  series.radius = radius;
170
+ series.doughnutHoleSize = radius * (pieOption.doughnutHoleSize ?? 0);
150
171
  series.startAngle = slice.sa;
151
172
  series.endAngle = slice.ea;
152
173
  series.data = { o: slice.value };
153
174
 
154
- series.draw(ctx);
175
+ series.draw(ctx, strokeOptions);
155
176
  }
156
177
  }
157
178
  }
158
-
159
- ctx.beginPath();
160
-
161
- if (pieOption?.pieStroke?.use) {
162
- ctx.lineWidth = pieOption.pieStroke.lineWidth;
163
- ctx.strokeStyle = pieOption.pieStroke.color;
164
- ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI);
165
- ctx.stroke();
166
- } else {
167
- ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI);
168
- }
169
-
170
- ctx.closePath();
171
179
  }
172
180
  },
173
181
 
@@ -177,11 +185,15 @@ const modules = {
177
185
  */
178
186
  drawDoughnutHole(ctx = this.bufferCtx) {
179
187
  const pieOption = this.options;
188
+ const { width, height } = this.chartRect;
189
+ const padding = this.options.padding;
180
190
 
181
- const centerX = this.chartRect.width / 2;
182
- const centerY = this.chartRect.height / 2;
191
+ const centerX = width / 2;
192
+ const centerY = height / 2;
193
+ const chartWidth = centerX - (padding.left + padding.right);
194
+ const chartHeight = centerY - (padding.bottom + padding.top);
195
+ const radius = Math.min(chartWidth, chartHeight) * pieOption.doughnutHoleSize;
183
196
 
184
- const radius = Math.min(centerX, centerY) * pieOption.doughnutHoleSize;
185
197
  ctx.save();
186
198
  ctx.globalCompositeOperation = 'destination-out';
187
199
  ctx.beginPath();
@@ -195,19 +207,15 @@ const modules = {
195
207
  ctx.restore();
196
208
 
197
209
  // inner stroke
198
- ctx.beginPath();
199
-
200
210
  if (pieOption?.pieStroke?.use) {
211
+ ctx.beginPath();
201
212
  ctx.strokeStyle = pieOption.pieStroke.color;
202
213
  ctx.lineWidth = pieOption.pieStroke.lineWidth;
203
214
  ctx.arc(centerX, centerY, radius, 0, Math.PI * 2);
204
215
  ctx.stroke();
205
- } else {
206
- ctx.arc(centerX, centerY, radius, 0, Math.PI * 2);
216
+ ctx.closePath();
207
217
  }
208
218
 
209
- ctx.closePath();
210
-
211
219
  this.pieDataSet[this.pieDataSet.length - 1].ir = radius;
212
220
  },
213
221
  };
@@ -310,6 +310,13 @@ const modules = {
310
310
  value,
311
311
  name,
312
312
  });
313
+ } else if (this.options.type === 'heatMap') {
314
+ formattedTxt = opt.formatter({
315
+ x: this.options.horizontal ? hitItem.y : hitItem.x,
316
+ y: this.options.horizontal ? hitItem.x : hitItem.y,
317
+ name,
318
+ value,
319
+ });
313
320
  } else {
314
321
  formattedTxt = opt.formatter({
315
322
  x: this.options.horizontal ? value : hitItem.x,
@@ -349,6 +356,85 @@ const modules = {
349
356
  this.tooltipDOM.style.display = 'block';
350
357
  },
351
358
 
359
+ /**
360
+ * Draw tooltip canvas for heatmap
361
+ * @param {object} hitInfo mousemove callback
362
+ * @param {object} context tooltip canvas context
363
+ *
364
+ * @returns {undefined}
365
+ */
366
+ drawToolTipForHeatMap(hitInfo, context) {
367
+ const ctx = context;
368
+ const items = hitInfo.items;
369
+ const sId = hitInfo.hitId;
370
+ const hitItem = items[sId].data;
371
+ const hitAxis = items[sId].axis;
372
+ const hitColor = items[sId].color;
373
+ const boxPadding = { t: 8, b: 8, r: 20, l: 16 };
374
+ const isHorizontal = this.options.horizontal;
375
+ const opt = this.options.tooltip;
376
+
377
+ // draw tooltip Title(axis label) and add style class for wrap line about too much long label.
378
+ if (this.axesX.length && this.axesY.length) {
379
+ this.tooltipHeaderDOM.textContent = this.options.horizontal
380
+ ? `${this.axesY[hitAxis.y].getLabelFormat(hitItem.y)} / ${this.axesX[hitAxis.x].getLabelFormat(hitItem.x)}`
381
+ : `${this.axesX[hitAxis.x].getLabelFormat(hitItem.x)} / ${this.axesY[hitAxis.y].getLabelFormat(hitItem.y)}`;
382
+ }
383
+
384
+ if (opt.textOverflow) {
385
+ this.tooltipHeaderDOM.classList.add(`ev-chart-tooltip-header--${opt.textOverflow}`);
386
+ }
387
+
388
+ // draw tooltip contents (series, value combination)
389
+ ctx.save();
390
+ ctx.scale(this.pixelRatio, this.pixelRatio);
391
+
392
+ if (this.tooltipBodyDOM.style.overflowY === 'auto') {
393
+ boxPadding.r += SCROLL_WIDTH;
394
+ }
395
+
396
+ const itemX = boxPadding.l + 2;
397
+ const itemY = boxPadding.t + TEXT_HEIGHT + 2;
398
+ const itemValue = hitItem.o > -1 ? hitItem.o : 'error';
399
+
400
+ ctx.font = FONT_STYLE;
401
+
402
+ ctx.beginPath();
403
+
404
+ if (typeof hitColor !== 'string') {
405
+ ctx.fillStyle = Canvas.createGradient(
406
+ ctx,
407
+ isHorizontal,
408
+ { x: itemX, y: itemY, w: 12, h: -12 },
409
+ hitColor,
410
+ );
411
+ } else {
412
+ ctx.fillStyle = hitColor;
413
+ }
414
+
415
+ // 1. Draw series color
416
+ ctx.fillRect(itemX - 4, itemY - 12, 12, 12);
417
+ ctx.fillStyle = opt.fontColor;
418
+
419
+ // 2. Draw series name
420
+ ctx.textBaseline = 'Bottom';
421
+ ctx.fillText(itemValue, itemX + COLOR_MARGIN, itemY);
422
+ ctx.closePath();
423
+
424
+ // set tooltipDOM's style
425
+ this.tooltipDOM.style.overflowY = 'hidden';
426
+ this.tooltipDOM.style.backgroundColor = opt.backgroundColor;
427
+ this.tooltipDOM.style.border = `1px solid ${opt.borderColor}`;
428
+ this.tooltipDOM.style.color = opt.fontColor;
429
+
430
+ if (opt.useShadow) {
431
+ const shadowColor = `rgba(0, 0, 0, ${opt.shadowOpacity})`;
432
+ this.tooltipDOM.style.boxShadow = `2px 2px 2px ${shadowColor}`;
433
+ }
434
+
435
+ this.tooltipDOM.style.display = 'block';
436
+ },
437
+
352
438
  /**
353
439
  * Draw graph item highlight
354
440
  * @param {object} hitInfo mousemove callback
@@ -361,7 +447,7 @@ const modules = {
361
447
  const series = this.seriesList[sId];
362
448
  series.itemHighlight(hitInfo.items[sId], ctx);
363
449
 
364
- if (series.type === 'sunburst' || series.type === 'doughnut') {
450
+ if (Util.isDoughnutHole(series.type)) {
365
451
  this.drawDoughnutHole(ctx);
366
452
  }
367
453
  });
@@ -164,7 +164,7 @@ class Scale {
164
164
  *
165
165
  * @returns {undefined}
166
166
  */
167
- draw(chartRect, labelOffset, stepInfo, hitInfo) {
167
+ draw(chartRect, labelOffset, stepInfo, hitInfo, selectLabelInfo) {
168
168
  const ctx = this.ctx;
169
169
  const options = this.options;
170
170
  const aPos = {
@@ -239,12 +239,22 @@ class Scale {
239
239
  linePosition = labelCenter + aliasPixel;
240
240
  labelText = this.getLabelFormat(Math.min(axisMax, ticks[ix]));
241
241
 
242
+ const isBlurredLabel = this.options?.selectLabel?.use
243
+ && this.options?.selectLabel?.useLabelOpacity
244
+ && (this.options.horizontal === (this.type === 'y'))
245
+ && selectLabelInfo?.dataIndex?.length
246
+ && !selectLabelInfo?.dataIndex?.includes(ix);
247
+ ctx.fillStyle = Util.colorStringToRgba(this.labelStyle.color, isBlurredLabel ? 0.1 : 1);
248
+
242
249
  let labelPoint;
243
250
 
244
251
  if (this.type === 'x') {
245
252
  labelPoint = this.position === 'top' ? offsetPoint - 10 : offsetPoint + 10;
246
253
  ctx.fillText(labelText, labelCenter, labelPoint);
247
- if (options?.selectItem?.showLabelTip && hitInfo?.label && !this.options?.horizontal) {
254
+ if (!isBlurredLabel
255
+ && options?.selectItem?.showLabelTip
256
+ && hitInfo?.label
257
+ && !this.options?.horizontal) {
248
258
  const selectedLabel = this.getLabelFormat(
249
259
  Math.min(axisMax, hitInfo.label + (0 * stepValue)),
250
260
  );
@@ -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,21 @@ 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
+ ctx.fillStyle = Util.colorStringToRgba(this.labelStyle.color, isBlurredLabel ? 0.1 : 1);
130
+
124
131
  if (this.type === 'x') {
125
132
  labelPoint = this.position === 'top' ? offsetPoint - 10 : offsetPoint + 10;
126
133
  ctx.fillText(labelText, labelCenter + (labelGap / 2), labelPoint);
127
134
 
128
- if (this.options?.selectItem?.showLabelTip
129
- && hitInfo?.label
130
- && !this.options?.horizontal
131
- ) {
135
+ if (!isBlurredLabel
136
+ && this.options?.selectItem?.showLabelTip
137
+ && hitInfo?.label
138
+ && !this.options?.horizontal) {
132
139
  const selectedLabel = hitInfo.label;
133
140
  if (selectedLabel === labelText) {
134
141
  const height = Math.round(ctx.measureText(this.labelStyle?.fontSize).width);
@@ -110,7 +110,7 @@ class TimeCategoryScale extends Scale {
110
110
  *
111
111
  * @returns {undefined}
112
112
  */
113
- draw(chartRect, labelOffset, stepInfo, hitInfo) {
113
+ draw(chartRect, labelOffset, stepInfo, hitInfo, selectLabelInfo) {
114
114
  const ctx = this.ctx;
115
115
  const labels = this.labels;
116
116
  const aPos = {
@@ -183,12 +183,22 @@ class TimeCategoryScale extends Scale {
183
183
  linePosition = labelCenter + aliasPixel;
184
184
  labelText = this.getLabelFormat(Math.min(axisMax, ticks[ix]));
185
185
 
186
+ const isBlurredLabel = this.options?.selectLabel?.use
187
+ && this.options?.selectLabel?.useLabelOpacity
188
+ && (this.options.horizontal === (this.type === 'y'))
189
+ && selectLabelInfo?.dataIndex?.length
190
+ && !selectLabelInfo?.dataIndex?.includes(ix);
191
+ ctx.fillStyle = Util.colorStringToRgba(this.labelStyle.color, isBlurredLabel ? 0.1 : 1);
192
+
186
193
  let labelPoint;
187
194
 
188
195
  if (this.type === 'x') {
189
196
  labelPoint = this.position === 'top' ? offsetPoint - 10 : offsetPoint + 10;
190
197
  ctx.fillText(labelText, labelCenter, labelPoint);
191
- if (this.options?.selectItem?.showLabelTip && hitInfo?.label && !this.options?.horizontal) {
198
+ if (!isBlurredLabel
199
+ && this.options?.selectItem?.showLabelTip
200
+ && hitInfo?.label
201
+ && !this.options?.horizontal) {
192
202
  const selectedLabel = this.getLabelFormat(
193
203
  Math.min(axisMax, hitInfo.label + (0 * stepValue)),
194
204
  );
@@ -82,6 +82,17 @@ const DEFAULT_OPTIONS = {
82
82
  tipBackground: '#000000',
83
83
  tipTextColor: '#FFFFFF',
84
84
  },
85
+ selectLabel: {
86
+ use: false,
87
+ limit: 1,
88
+ useDeselectOverflow: false,
89
+ showTip: false,
90
+ useSeriesOpacity: true,
91
+ useLabelOpacity: true,
92
+ fixedPosTop: false,
93
+ useApproximateValue: false,
94
+ tipBackground: '#000000',
95
+ },
85
96
  dragSelection: {
86
97
  use: false,
87
98
  keepDisplay: true,
@@ -103,15 +114,25 @@ export const useModel = () => {
103
114
  const getNormalizedOptions = (options) => {
104
115
  const normalizedOptions = defaultsDeep({}, options, DEFAULT_OPTIONS);
105
116
 
106
- if (options.type === 'scatter' && !options?.tooltip) {
117
+ if ((options.type === 'scatter' || options.type === 'heatMap') && !options?.tooltip) {
107
118
  normalizedOptions.tooltip.use = false;
108
119
  }
109
120
 
121
+ if (options.type === 'pie' && !options?.padding) {
122
+ normalizedOptions.padding = {
123
+ top: 2,
124
+ right: 2,
125
+ left: 2,
126
+ bottom: 4,
127
+ };
128
+ }
129
+
110
130
  return normalizedOptions;
111
131
  };
112
132
  const getNormalizedData = data => defaultsDeep(data, DEFAULT_DATA);
113
133
 
114
- const selectInfo = cloneDeep(props.selectedItem);
134
+ const selectItemInfo = cloneDeep(props.selectedItem);
135
+ const selectLabelInfo = cloneDeep(props.selectedLabel);
115
136
 
116
137
  const eventListeners = {
117
138
  click: async (e) => {
@@ -119,6 +140,9 @@ export const useModel = () => {
119
140
  if (e.label) {
120
141
  emit('update:selectedItem', { seriesID: e.seriesId, dataIndex: e.dataIndex });
121
142
  }
143
+ if (e.selected) {
144
+ emit('update:selectedLabel', { dataIndex: e.selected.dataIndex });
145
+ }
122
146
  emit('click', e);
123
147
  },
124
148
  'dbl-click': async (e) => {
@@ -133,7 +157,8 @@ export const useModel = () => {
133
157
 
134
158
  return {
135
159
  eventListeners,
136
- selectInfo,
160
+ selectItemInfo,
161
+ selectLabelInfo,
137
162
  getNormalizedData,
138
163
  getNormalizedOptions,
139
164
  };