evui 3.3.36 → 3.3.39
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/LICENSE +21 -21
- package/README.md +40 -40
- package/dist/evui.common.js +1907 -1832
- package/dist/evui.common.js.map +1 -1
- package/dist/evui.umd.js +1907 -1832
- 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/dist/img/{EVUI.7f3588fb.svg → EVUI.b82ee81a.svg} +292 -292
- package/dist/img/{icon_mysql.7ea26d5d.svg → icon_mysql.1085fdc9.svg} +78 -78
- package/dist/img/{icon_oracle.9009b108.svg → icon_oracle.0572d3ee.svg} +13 -13
- package/dist/img/{icon_postgresql.f8fffba9.svg → icon_postgresql.ee12bde8.svg} +58 -58
- package/package.json +61 -61
- package/src/common/emitter.js +20 -20
- package/src/common/utils.debounce.js +223 -223
- package/src/common/utils.js +134 -134
- package/src/common/utils.table.js +78 -78
- package/src/common/utils.throttle.js +83 -83
- package/src/common/utils.tree.js +18 -18
- package/src/components/button/Button.vue +198 -198
- package/src/components/button/index.js +7 -7
- package/src/components/buttonGroup/ButtonGroup.vue +11 -11
- package/src/components/buttonGroup/index.js +7 -7
- package/src/components/calendar/Calendar.vue +661 -661
- package/src/components/calendar/index.js +7 -7
- package/src/components/calendar/uses.js +1272 -1272
- package/src/components/chart/Chart.vue +189 -192
- package/src/components/chart/chart.core.js +870 -870
- package/src/components/chart/element/element.bar.js +524 -524
- package/src/components/chart/element/element.bar.time.js +156 -156
- package/src/components/chart/element/element.heatmap.js +533 -533
- package/src/components/chart/element/element.line.js +339 -339
- package/src/components/chart/element/element.pie.js +197 -197
- package/src/components/chart/element/element.scatter.js +184 -184
- package/src/components/chart/element/element.tip.js +550 -542
- package/src/components/chart/helpers/helpers.canvas.js +265 -265
- package/src/components/chart/helpers/helpers.constant.js +206 -206
- package/src/components/chart/helpers/helpers.util.js +346 -338
- package/src/components/chart/index.js +9 -9
- package/src/components/chart/model/index.js +4 -4
- package/src/components/chart/model/model.series.js +93 -93
- package/src/components/chart/model/model.store.js +977 -967
- package/src/components/chart/plugins/plugins.interaction.js +769 -769
- package/src/components/chart/plugins/plugins.legend.gradient.js +602 -602
- package/src/components/chart/plugins/plugins.legend.js +1155 -1151
- package/src/components/chart/plugins/plugins.pie.js +254 -254
- package/src/components/chart/plugins/plugins.title.js +56 -56
- package/src/components/chart/plugins/plugins.tooltip.js +692 -692
- package/src/components/chart/scale/scale.js +848 -848
- package/src/components/chart/scale/scale.linear.js +38 -38
- package/src/components/chart/scale/scale.logarithmic.js +128 -128
- package/src/components/chart/scale/scale.step.js +336 -336
- package/src/components/chart/scale/scale.time.category.js +277 -277
- package/src/components/chart/scale/scale.time.js +48 -48
- package/src/components/chart/style/chart.scss +312 -312
- package/src/components/chart/uses.js +264 -252
- package/src/components/checkbox/Checkbox.vue +200 -200
- package/src/components/checkbox/index.js +7 -7
- package/src/components/checkboxGroup/CheckboxGroup.vue +44 -44
- package/src/components/checkboxGroup/index.js +7 -7
- package/src/components/contextMenu/ContextMenu.vue +80 -80
- package/src/components/contextMenu/MenuList.vue +149 -149
- package/src/components/contextMenu/index.js +7 -7
- package/src/components/contextMenu/uses.js +203 -203
- package/src/components/datePicker/DatePicker.vue +437 -437
- package/src/components/datePicker/index.js +7 -7
- package/src/components/datePicker/uses.js +419 -419
- package/src/components/grid/Grid.vue +827 -827
- package/src/components/grid/grid.filter.window.vue +493 -493
- package/src/components/grid/grid.pagination.vue +75 -75
- package/src/components/grid/grid.summary.vue +265 -265
- package/src/components/grid/grid.toolbar.vue +26 -26
- package/src/components/grid/index.js +11 -11
- package/src/components/grid/style/grid.scss +263 -263
- package/src/components/grid/uses.js +1002 -1007
- package/src/components/icon/Icon.vue +49 -49
- package/src/components/icon/index.js +8 -8
- package/src/components/inputNumber/InputNumber.vue +212 -212
- package/src/components/inputNumber/index.js +7 -7
- package/src/components/inputNumber/uses.js +217 -217
- package/src/components/loading/Loading.vue +125 -125
- package/src/components/loading/index.js +7 -7
- package/src/components/menu/Menu.vue +68 -68
- package/src/components/menu/MenuItem.vue +187 -187
- package/src/components/menu/index.js +7 -7
- package/src/components/message/Message.vue +223 -223
- package/src/components/message/index.js +31 -31
- package/src/components/messageBox/MessageBox.vue +358 -358
- package/src/components/messageBox/index.js +22 -22
- package/src/components/notification/Notification.vue +316 -316
- package/src/components/notification/index.js +49 -49
- package/src/components/pagination/Pagination.vue +271 -271
- package/src/components/pagination/index.js +7 -7
- package/src/components/pagination/pageButton.vue +30 -30
- package/src/components/progress/Progress.vue +139 -139
- package/src/components/progress/index.js +7 -7
- package/src/components/radio/Radio.vue +159 -159
- package/src/components/radio/index.js +7 -7
- package/src/components/radioGroup/RadioGroup.vue +41 -41
- package/src/components/radioGroup/index.js +7 -7
- package/src/components/scheduler/Scheduler.vue +149 -149
- package/src/components/scheduler/index.js +7 -7
- package/src/components/scheduler/uses.js +183 -183
- package/src/components/select/Select.vue +440 -440
- package/src/components/select/index.js +7 -7
- package/src/components/select/uses.js +270 -270
- package/src/components/slider/Slider.vue +505 -505
- package/src/components/slider/index.js +7 -7
- package/src/components/slider/uses.js +390 -390
- package/src/components/tabPanel/TabPanel.vue +74 -74
- package/src/components/tabPanel/index.js +7 -7
- package/src/components/tabs/Tabs.vue +517 -517
- package/src/components/tabs/index.js +7 -7
- package/src/components/textField/TextField.vue +375 -375
- package/src/components/textField/index.js +7 -7
- package/src/components/timePicker/TimePicker.vue +352 -352
- package/src/components/timePicker/index.js +7 -7
- package/src/components/toggle/Toggle.vue +115 -115
- package/src/components/toggle/index.js +7 -7
- package/src/components/tree/Tree.vue +313 -313
- package/src/components/tree/TreeNode.vue +293 -293
- package/src/components/tree/index.js +7 -7
- package/src/components/treeGrid/TreeGrid.vue +758 -758
- package/src/components/treeGrid/TreeGridNode.vue +275 -275
- package/src/components/treeGrid/index.js +9 -9
- package/src/components/treeGrid/style/treeGrid.scss +261 -261
- package/src/components/treeGrid/treeGrid.toolbar.vue +26 -26
- package/src/components/treeGrid/uses.js +867 -867
- package/src/components/window/Window.vue +329 -329
- package/src/components/window/index.js +7 -7
- package/src/components/window/uses.js +899 -899
- package/src/directives/clickoutside.js +90 -90
- package/src/main.js +116 -116
- package/src/style/components/input.scss +108 -108
- package/src/style/functions.scss +3 -3
- package/src/style/index.scss +6 -6
- package/src/style/lib/fonts/EVUI.svg +292 -292
- package/src/style/lib/icon.css +888 -888
- package/src/style/mixins.scss +94 -94
- package/src/style/themes.scss +67 -67
- package/src/style/variables.scss +22 -22
|
@@ -1,336 +1,336 @@
|
|
|
1
|
-
import { defaultsDeep } from 'lodash-es';
|
|
2
|
-
import { PLOT_BAND_OPTION, PLOT_LINE_OPTION } from '@/components/chart/helpers/helpers.constant';
|
|
3
|
-
import Scale from './scale';
|
|
4
|
-
import Util from '../helpers/helpers.util';
|
|
5
|
-
|
|
6
|
-
class StepScale extends Scale {
|
|
7
|
-
constructor(type, opt, ctx, labels, options) {
|
|
8
|
-
super(type, opt, ctx, options);
|
|
9
|
-
this.labels = labels;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Calculate min/max value, label and size information for step scale
|
|
14
|
-
* @param {object} minMax min/max information (unused on step scale)
|
|
15
|
-
* @param {object} chartRect chart size information
|
|
16
|
-
*
|
|
17
|
-
* @returns {object} min/max value and label
|
|
18
|
-
*/
|
|
19
|
-
calculateScaleRange(minMax, chartRect) {
|
|
20
|
-
const stepMinMax = this.labelStyle.alignToGridLine
|
|
21
|
-
? minMax : Util.getStringMinMax(this.labels);
|
|
22
|
-
const maxValue = stepMinMax.max;
|
|
23
|
-
const minValue = stepMinMax.min;
|
|
24
|
-
const maxWidth = chartRect.chartWidth / (this.labels.length + 2);
|
|
25
|
-
|
|
26
|
-
return {
|
|
27
|
-
min: minValue,
|
|
28
|
-
max: maxValue,
|
|
29
|
-
minLabel: this.getLabelFormat(minValue, maxWidth),
|
|
30
|
-
maxLabel: this.getLabelFormat(maxValue, maxWidth),
|
|
31
|
-
size: Util.calcTextSize(
|
|
32
|
-
this.getLabelFormat(maxValue, maxWidth),
|
|
33
|
-
Util.getLabelStyle(this.labelStyle),
|
|
34
|
-
),
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* With range information, calculate how many labels in axis
|
|
40
|
-
* @param {object} range min/max information
|
|
41
|
-
*
|
|
42
|
-
* @returns {object} steps, interval, min/max graph value
|
|
43
|
-
*/
|
|
44
|
-
calculateSteps(range) {
|
|
45
|
-
let numberOfSteps = this.labels.length;
|
|
46
|
-
let interval = 1;
|
|
47
|
-
|
|
48
|
-
const isNumbersArray = this.labels.every(label => !isNaN(label));
|
|
49
|
-
if (this.labelStyle.alignToGridLine && isNumbersArray) {
|
|
50
|
-
const { maxSteps } = range;
|
|
51
|
-
|
|
52
|
-
if (maxSteps > 2) {
|
|
53
|
-
while (numberOfSteps > maxSteps * 2) {
|
|
54
|
-
interval *= 2;
|
|
55
|
-
numberOfSteps = Math.round(numberOfSteps / interval);
|
|
56
|
-
}
|
|
57
|
-
} else {
|
|
58
|
-
interval = this.labels.length;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return {
|
|
63
|
-
steps: numberOfSteps,
|
|
64
|
-
interval,
|
|
65
|
-
graphMin: range.minValue,
|
|
66
|
-
graphMax: range.maxValue,
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Draw axis
|
|
72
|
-
* @param {object} chartRect min/max information
|
|
73
|
-
* @param {object} labelOffset label offset information
|
|
74
|
-
* @param {object} stepInfo label steps information
|
|
75
|
-
*
|
|
76
|
-
* @returns {undefined}
|
|
77
|
-
*/
|
|
78
|
-
draw(chartRect, labelOffset, stepInfo, hitInfo, selectLabelInfo) {
|
|
79
|
-
const ctx = this.ctx;
|
|
80
|
-
const labels = this.labels;
|
|
81
|
-
const aPos = {
|
|
82
|
-
x1: chartRect.x1 + labelOffset.left,
|
|
83
|
-
x2: chartRect.x2 - labelOffset.right,
|
|
84
|
-
y1: chartRect.y1 + labelOffset.top,
|
|
85
|
-
y2: chartRect.y2 - labelOffset.bottom,
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
const oriSteps = this.labels.length;
|
|
89
|
-
const steps = stepInfo.steps;
|
|
90
|
-
const count = stepInfo.interval;
|
|
91
|
-
|
|
92
|
-
const startPoint = aPos[this.units.rectStart];
|
|
93
|
-
const endPoint = aPos[this.units.rectEnd];
|
|
94
|
-
const offsetPoint = aPos[this.units.rectOffset(this.position)];
|
|
95
|
-
const offsetCounterPoint = aPos[this.units.rectOffsetCounter(this.position)];
|
|
96
|
-
const maxWidth = chartRect.chartWidth / (this.labels.length + 2);
|
|
97
|
-
|
|
98
|
-
this.drawAxisTitle(chartRect, labelOffset);
|
|
99
|
-
|
|
100
|
-
if (this.labelStyle?.show) {
|
|
101
|
-
// label font 설정
|
|
102
|
-
ctx.font = Util.getLabelStyle(this.labelStyle);
|
|
103
|
-
|
|
104
|
-
if (this.type === 'x') {
|
|
105
|
-
ctx.textAlign = 'center';
|
|
106
|
-
ctx.textBaseline = this.position === 'top' ? 'bottom' : 'top';
|
|
107
|
-
} else {
|
|
108
|
-
ctx.textAlign = this.position === 'left' ? 'right' : 'left';
|
|
109
|
-
ctx.textBaseline = 'middle';
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
ctx.fillStyle = this.labelStyle.color;
|
|
113
|
-
ctx.lineWidth = 1;
|
|
114
|
-
const aliasPixel = Util.aliasPixel(ctx.lineWidth);
|
|
115
|
-
|
|
116
|
-
ctx.beginPath();
|
|
117
|
-
ctx.strokeStyle = this.axisLineColor;
|
|
118
|
-
if (this.type === 'x') {
|
|
119
|
-
ctx.moveTo(startPoint, offsetPoint + aliasPixel);
|
|
120
|
-
ctx.lineTo(endPoint, offsetPoint + aliasPixel);
|
|
121
|
-
} else {
|
|
122
|
-
ctx.moveTo(offsetPoint + aliasPixel, startPoint);
|
|
123
|
-
ctx.lineTo(offsetPoint + aliasPixel, endPoint);
|
|
124
|
-
}
|
|
125
|
-
ctx.stroke();
|
|
126
|
-
|
|
127
|
-
if (steps === 0) {
|
|
128
|
-
return;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
const labelGap = (endPoint - startPoint) / labels.length;
|
|
132
|
-
const alignToGridLine = this.labelStyle.alignToGridLine;
|
|
133
|
-
let labelCenter = null;
|
|
134
|
-
let linePosition = null;
|
|
135
|
-
|
|
136
|
-
ctx.beginPath();
|
|
137
|
-
ctx.strokeStyle = this.gridLineColor;
|
|
138
|
-
|
|
139
|
-
let labelText;
|
|
140
|
-
let labelPoint;
|
|
141
|
-
let index;
|
|
142
|
-
|
|
143
|
-
for (index = 0; index < oriSteps; index += count) {
|
|
144
|
-
const item = this.labels[index];
|
|
145
|
-
labelCenter = Math.round(startPoint + (labelGap * index));
|
|
146
|
-
linePosition = labelCenter + aliasPixel;
|
|
147
|
-
labelText = this.getLabelFormat(item, maxWidth);
|
|
148
|
-
|
|
149
|
-
const isBlurredLabel = this.options?.selectLabel?.use
|
|
150
|
-
&& this.options?.selectLabel?.useLabelOpacity
|
|
151
|
-
&& (this.options.horizontal === (this.type === 'y'))
|
|
152
|
-
&& selectLabelInfo?.dataIndex?.length
|
|
153
|
-
&& !selectLabelInfo?.dataIndex?.includes(index);
|
|
154
|
-
|
|
155
|
-
const labelColor = this.labelStyle.color;
|
|
156
|
-
let defaultOpacity = 1;
|
|
157
|
-
|
|
158
|
-
if (Util.getColorStringType(labelColor) === 'RGBA') {
|
|
159
|
-
defaultOpacity = Util.getOpacity(labelColor);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
ctx.fillStyle = Util.colorStringToRgba(labelColor, isBlurredLabel ? 0.1 : defaultOpacity);
|
|
163
|
-
|
|
164
|
-
if (this.type === 'x') {
|
|
165
|
-
labelPoint = this.position === 'top' ? offsetPoint - 10 : offsetPoint + 10;
|
|
166
|
-
const xPoint = alignToGridLine ? labelCenter : labelCenter + (labelGap / 2);
|
|
167
|
-
ctx.fillText(labelText, xPoint, labelPoint);
|
|
168
|
-
|
|
169
|
-
if (!isBlurredLabel
|
|
170
|
-
&& this.options?.selectItem?.showLabelTip
|
|
171
|
-
&& hitInfo?.label
|
|
172
|
-
&& !this.options?.horizontal) {
|
|
173
|
-
const selectedLabel = hitInfo.label;
|
|
174
|
-
if (selectedLabel === labelText) {
|
|
175
|
-
const height = Math.round(ctx.measureText(this.labelStyle?.fontSize).width);
|
|
176
|
-
Util.showLabelTip({
|
|
177
|
-
ctx: this.ctx,
|
|
178
|
-
width: Math.round(ctx.measureText(selectedLabel).width) + 10,
|
|
179
|
-
height,
|
|
180
|
-
x: labelCenter + (labelGap / 2),
|
|
181
|
-
y: labelPoint + (height - 2),
|
|
182
|
-
borderRadius: 2,
|
|
183
|
-
arrowSize: 3,
|
|
184
|
-
text: labelText,
|
|
185
|
-
backgroundColor: this.options?.selectItem?.labelTipStyle?.backgroundColor,
|
|
186
|
-
textColor: this.options?.selectItem?.labelTipStyle?.textColor,
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
if (index > 0 && this.showGrid) {
|
|
192
|
-
ctx.moveTo(linePosition, offsetPoint);
|
|
193
|
-
ctx.lineTo(linePosition, offsetCounterPoint);
|
|
194
|
-
}
|
|
195
|
-
} else {
|
|
196
|
-
labelPoint = this.position === 'left' ? offsetPoint - 10 : offsetPoint + 10;
|
|
197
|
-
const yPoint = alignToGridLine ? labelCenter : labelCenter + (labelGap / 2);
|
|
198
|
-
ctx.fillText(labelText, labelPoint, yPoint);
|
|
199
|
-
|
|
200
|
-
if (index > 0 && this.showGrid) {
|
|
201
|
-
ctx.moveTo(offsetPoint, linePosition);
|
|
202
|
-
ctx.lineTo(offsetCounterPoint, linePosition);
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
ctx.stroke();
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
if (alignToGridLine && (index === this.labels.length)) {
|
|
209
|
-
let labelLastText = +labels[labels.length - 1] + (+labels[1] - +labels[0]);
|
|
210
|
-
if (isNaN(labelLastText)) {
|
|
211
|
-
labelLastText = 'Max';
|
|
212
|
-
}
|
|
213
|
-
labelCenter = Math.round(startPoint + (labelGap * labels.length));
|
|
214
|
-
linePosition = labelCenter + aliasPixel;
|
|
215
|
-
|
|
216
|
-
if (this.type === 'x') {
|
|
217
|
-
ctx.fillText(labelLastText, labelCenter, labelPoint);
|
|
218
|
-
if (this.showGrid) {
|
|
219
|
-
ctx.moveTo(linePosition, offsetPoint);
|
|
220
|
-
ctx.lineTo(linePosition, offsetCounterPoint);
|
|
221
|
-
}
|
|
222
|
-
} else {
|
|
223
|
-
ctx.fillText(labelLastText, labelPoint, labelCenter);
|
|
224
|
-
if (this.showGrid) {
|
|
225
|
-
ctx.moveTo(offsetPoint, linePosition);
|
|
226
|
-
ctx.lineTo(offsetCounterPoint, linePosition);
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
ctx.stroke();
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
ctx.closePath();
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
// draw plot lines and plot bands
|
|
236
|
-
if (this.plotBands?.length || this.plotLines?.length) {
|
|
237
|
-
const padding = Util.aliasPixel(ctx.lineWidth) + 1;
|
|
238
|
-
const minX = aPos.x1 + padding;
|
|
239
|
-
const maxX = aPos.x2;
|
|
240
|
-
const minY = aPos.y1 + padding;
|
|
241
|
-
const maxY = aPos.y2;
|
|
242
|
-
const labelGap = (endPoint - startPoint) / (this.labelStyle.show ? labels.length : 1);
|
|
243
|
-
|
|
244
|
-
this.plotBands?.forEach((plotBand) => {
|
|
245
|
-
if (!plotBand.from && !plotBand.to) {
|
|
246
|
-
return;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
const mergedPlotBandOpt = defaultsDeep({}, plotBand, PLOT_BAND_OPTION);
|
|
250
|
-
const { from = 0, to = labels.length, label: labelOpt } = mergedPlotBandOpt;
|
|
251
|
-
const fromPos = Math.round(startPoint + (labelGap * from));
|
|
252
|
-
const toPos = Math.round(startPoint + (labelGap * to));
|
|
253
|
-
|
|
254
|
-
this.setPlotBandStyle(mergedPlotBandOpt);
|
|
255
|
-
|
|
256
|
-
if (this.type === 'x') {
|
|
257
|
-
this.drawXPlotBand(fromPos, toPos, minX, maxX, minY, maxY);
|
|
258
|
-
} else {
|
|
259
|
-
this.drawYPlotBand(fromPos, toPos, minX, maxX, minY, maxY);
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
if (labelOpt.show) {
|
|
263
|
-
const labelOptions = this.getNormalizedLabelOptions(chartRect, labelOpt);
|
|
264
|
-
const textXY = this.getPlotBandLabelPosition(fromPos, toPos, labelOptions, maxX, minY);
|
|
265
|
-
this.drawPlotLabel(labelOptions, textXY);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
ctx.restore();
|
|
269
|
-
});
|
|
270
|
-
|
|
271
|
-
this.plotLines?.forEach((plotLine) => {
|
|
272
|
-
if (!plotLine.value) {
|
|
273
|
-
return;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
const mergedPlotLineOpt = defaultsDeep({}, plotLine, PLOT_LINE_OPTION);
|
|
277
|
-
const { value, label: labelOpt } = mergedPlotLineOpt;
|
|
278
|
-
const dataPos = Math.round(startPoint + (labelGap * value)) + (labelGap / 2);
|
|
279
|
-
|
|
280
|
-
this.setPlotLineStyle(mergedPlotLineOpt);
|
|
281
|
-
|
|
282
|
-
if (this.type === 'x') {
|
|
283
|
-
this.drawXPlotLine(dataPos, minX, maxX, minY, maxY);
|
|
284
|
-
} else {
|
|
285
|
-
this.drawYPlotLine(dataPos, minX, maxX, minY, maxY);
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
if (labelOpt.show) {
|
|
289
|
-
const labelOptions = this.getNormalizedLabelOptions(chartRect, labelOpt);
|
|
290
|
-
const textXY = this.getPlotLineLabelPosition(dataPos, labelOptions, maxX, minY);
|
|
291
|
-
this.drawPlotLabel(labelOptions, textXY);
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
ctx.restore();
|
|
295
|
-
});
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
/**
|
|
300
|
-
* Transforming label by designated format
|
|
301
|
-
* @param {string} value label value
|
|
302
|
-
* @param {number} maxWidth max width for each label
|
|
303
|
-
*
|
|
304
|
-
* @returns {string} formatted label
|
|
305
|
-
*/
|
|
306
|
-
getLabelFormat(value, maxWidth) {
|
|
307
|
-
if (this.formatter) {
|
|
308
|
-
const formattedLabel = this.formatter(value);
|
|
309
|
-
|
|
310
|
-
if (typeof formattedLabel === 'string') {
|
|
311
|
-
return formattedLabel;
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
return this.labelStyle.fitWidth ? this.fittingString(value, maxWidth) : value;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
/**
|
|
319
|
-
* Transforming ellipsis label by designated format and specific width
|
|
320
|
-
* @param {string} value label value
|
|
321
|
-
* @param {number} maxWidth max width for each label
|
|
322
|
-
*
|
|
323
|
-
* @returns {string} formatted label
|
|
324
|
-
*/
|
|
325
|
-
fittingString(value, maxWidth) {
|
|
326
|
-
const ctx = this.ctx;
|
|
327
|
-
|
|
328
|
-
ctx.save();
|
|
329
|
-
ctx.font = Util.getLabelStyle(this.labelStyle);
|
|
330
|
-
const dir = this.labelStyle.fitDir;
|
|
331
|
-
|
|
332
|
-
return Util.truncateLabelWithEllipsis(value, maxWidth, ctx, dir);
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
export default StepScale;
|
|
1
|
+
import { defaultsDeep } from 'lodash-es';
|
|
2
|
+
import { PLOT_BAND_OPTION, PLOT_LINE_OPTION } from '@/components/chart/helpers/helpers.constant';
|
|
3
|
+
import Scale from './scale';
|
|
4
|
+
import Util from '../helpers/helpers.util';
|
|
5
|
+
|
|
6
|
+
class StepScale extends Scale {
|
|
7
|
+
constructor(type, opt, ctx, labels, options) {
|
|
8
|
+
super(type, opt, ctx, options);
|
|
9
|
+
this.labels = labels;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Calculate min/max value, label and size information for step scale
|
|
14
|
+
* @param {object} minMax min/max information (unused on step scale)
|
|
15
|
+
* @param {object} chartRect chart size information
|
|
16
|
+
*
|
|
17
|
+
* @returns {object} min/max value and label
|
|
18
|
+
*/
|
|
19
|
+
calculateScaleRange(minMax, chartRect) {
|
|
20
|
+
const stepMinMax = this.labelStyle.alignToGridLine
|
|
21
|
+
? minMax : Util.getStringMinMax(this.labels);
|
|
22
|
+
const maxValue = stepMinMax.max;
|
|
23
|
+
const minValue = stepMinMax.min;
|
|
24
|
+
const maxWidth = chartRect.chartWidth / (this.labels.length + 2);
|
|
25
|
+
|
|
26
|
+
return {
|
|
27
|
+
min: minValue,
|
|
28
|
+
max: maxValue,
|
|
29
|
+
minLabel: this.getLabelFormat(minValue, maxWidth),
|
|
30
|
+
maxLabel: this.getLabelFormat(maxValue, maxWidth),
|
|
31
|
+
size: Util.calcTextSize(
|
|
32
|
+
this.getLabelFormat(maxValue, maxWidth),
|
|
33
|
+
Util.getLabelStyle(this.labelStyle),
|
|
34
|
+
),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* With range information, calculate how many labels in axis
|
|
40
|
+
* @param {object} range min/max information
|
|
41
|
+
*
|
|
42
|
+
* @returns {object} steps, interval, min/max graph value
|
|
43
|
+
*/
|
|
44
|
+
calculateSteps(range) {
|
|
45
|
+
let numberOfSteps = this.labels.length;
|
|
46
|
+
let interval = 1;
|
|
47
|
+
|
|
48
|
+
const isNumbersArray = this.labels.every(label => !isNaN(label));
|
|
49
|
+
if (this.labelStyle.alignToGridLine && isNumbersArray) {
|
|
50
|
+
const { maxSteps } = range;
|
|
51
|
+
|
|
52
|
+
if (maxSteps > 2) {
|
|
53
|
+
while (numberOfSteps > maxSteps * 2) {
|
|
54
|
+
interval *= 2;
|
|
55
|
+
numberOfSteps = Math.round(numberOfSteps / interval);
|
|
56
|
+
}
|
|
57
|
+
} else {
|
|
58
|
+
interval = this.labels.length;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
steps: numberOfSteps,
|
|
64
|
+
interval,
|
|
65
|
+
graphMin: range.minValue,
|
|
66
|
+
graphMax: range.maxValue,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Draw axis
|
|
72
|
+
* @param {object} chartRect min/max information
|
|
73
|
+
* @param {object} labelOffset label offset information
|
|
74
|
+
* @param {object} stepInfo label steps information
|
|
75
|
+
*
|
|
76
|
+
* @returns {undefined}
|
|
77
|
+
*/
|
|
78
|
+
draw(chartRect, labelOffset, stepInfo, hitInfo, selectLabelInfo) {
|
|
79
|
+
const ctx = this.ctx;
|
|
80
|
+
const labels = this.labels;
|
|
81
|
+
const aPos = {
|
|
82
|
+
x1: chartRect.x1 + labelOffset.left,
|
|
83
|
+
x2: chartRect.x2 - labelOffset.right,
|
|
84
|
+
y1: chartRect.y1 + labelOffset.top,
|
|
85
|
+
y2: chartRect.y2 - labelOffset.bottom,
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const oriSteps = this.labels.length;
|
|
89
|
+
const steps = stepInfo.steps;
|
|
90
|
+
const count = stepInfo.interval;
|
|
91
|
+
|
|
92
|
+
const startPoint = aPos[this.units.rectStart];
|
|
93
|
+
const endPoint = aPos[this.units.rectEnd];
|
|
94
|
+
const offsetPoint = aPos[this.units.rectOffset(this.position)];
|
|
95
|
+
const offsetCounterPoint = aPos[this.units.rectOffsetCounter(this.position)];
|
|
96
|
+
const maxWidth = chartRect.chartWidth / (this.labels.length + 2);
|
|
97
|
+
|
|
98
|
+
this.drawAxisTitle(chartRect, labelOffset);
|
|
99
|
+
|
|
100
|
+
if (this.labelStyle?.show) {
|
|
101
|
+
// label font 설정
|
|
102
|
+
ctx.font = Util.getLabelStyle(this.labelStyle);
|
|
103
|
+
|
|
104
|
+
if (this.type === 'x') {
|
|
105
|
+
ctx.textAlign = 'center';
|
|
106
|
+
ctx.textBaseline = this.position === 'top' ? 'bottom' : 'top';
|
|
107
|
+
} else {
|
|
108
|
+
ctx.textAlign = this.position === 'left' ? 'right' : 'left';
|
|
109
|
+
ctx.textBaseline = 'middle';
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
ctx.fillStyle = this.labelStyle.color;
|
|
113
|
+
ctx.lineWidth = 1;
|
|
114
|
+
const aliasPixel = Util.aliasPixel(ctx.lineWidth);
|
|
115
|
+
|
|
116
|
+
ctx.beginPath();
|
|
117
|
+
ctx.strokeStyle = this.axisLineColor;
|
|
118
|
+
if (this.type === 'x') {
|
|
119
|
+
ctx.moveTo(startPoint, offsetPoint + aliasPixel);
|
|
120
|
+
ctx.lineTo(endPoint, offsetPoint + aliasPixel);
|
|
121
|
+
} else {
|
|
122
|
+
ctx.moveTo(offsetPoint + aliasPixel, startPoint);
|
|
123
|
+
ctx.lineTo(offsetPoint + aliasPixel, endPoint);
|
|
124
|
+
}
|
|
125
|
+
ctx.stroke();
|
|
126
|
+
|
|
127
|
+
if (steps === 0) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const labelGap = (endPoint - startPoint) / labels.length;
|
|
132
|
+
const alignToGridLine = this.labelStyle.alignToGridLine;
|
|
133
|
+
let labelCenter = null;
|
|
134
|
+
let linePosition = null;
|
|
135
|
+
|
|
136
|
+
ctx.beginPath();
|
|
137
|
+
ctx.strokeStyle = this.gridLineColor;
|
|
138
|
+
|
|
139
|
+
let labelText;
|
|
140
|
+
let labelPoint;
|
|
141
|
+
let index;
|
|
142
|
+
|
|
143
|
+
for (index = 0; index < oriSteps; index += count) {
|
|
144
|
+
const item = this.labels[index];
|
|
145
|
+
labelCenter = Math.round(startPoint + (labelGap * index));
|
|
146
|
+
linePosition = labelCenter + aliasPixel;
|
|
147
|
+
labelText = this.getLabelFormat(item, maxWidth);
|
|
148
|
+
|
|
149
|
+
const isBlurredLabel = this.options?.selectLabel?.use
|
|
150
|
+
&& this.options?.selectLabel?.useLabelOpacity
|
|
151
|
+
&& (this.options.horizontal === (this.type === 'y'))
|
|
152
|
+
&& selectLabelInfo?.dataIndex?.length
|
|
153
|
+
&& !selectLabelInfo?.dataIndex?.includes(index);
|
|
154
|
+
|
|
155
|
+
const labelColor = this.labelStyle.color;
|
|
156
|
+
let defaultOpacity = 1;
|
|
157
|
+
|
|
158
|
+
if (Util.getColorStringType(labelColor) === 'RGBA') {
|
|
159
|
+
defaultOpacity = Util.getOpacity(labelColor);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
ctx.fillStyle = Util.colorStringToRgba(labelColor, isBlurredLabel ? 0.1 : defaultOpacity);
|
|
163
|
+
|
|
164
|
+
if (this.type === 'x') {
|
|
165
|
+
labelPoint = this.position === 'top' ? offsetPoint - 10 : offsetPoint + 10;
|
|
166
|
+
const xPoint = alignToGridLine ? labelCenter : labelCenter + (labelGap / 2);
|
|
167
|
+
ctx.fillText(labelText, xPoint, labelPoint);
|
|
168
|
+
|
|
169
|
+
if (!isBlurredLabel
|
|
170
|
+
&& this.options?.selectItem?.showLabelTip
|
|
171
|
+
&& hitInfo?.label
|
|
172
|
+
&& !this.options?.horizontal) {
|
|
173
|
+
const selectedLabel = hitInfo.label;
|
|
174
|
+
if (selectedLabel === labelText) {
|
|
175
|
+
const height = Math.round(ctx.measureText(this.labelStyle?.fontSize).width);
|
|
176
|
+
Util.showLabelTip({
|
|
177
|
+
ctx: this.ctx,
|
|
178
|
+
width: Math.round(ctx.measureText(selectedLabel).width) + 10,
|
|
179
|
+
height,
|
|
180
|
+
x: labelCenter + (labelGap / 2),
|
|
181
|
+
y: labelPoint + (height - 2),
|
|
182
|
+
borderRadius: 2,
|
|
183
|
+
arrowSize: 3,
|
|
184
|
+
text: labelText,
|
|
185
|
+
backgroundColor: this.options?.selectItem?.labelTipStyle?.backgroundColor,
|
|
186
|
+
textColor: this.options?.selectItem?.labelTipStyle?.textColor,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (index > 0 && this.showGrid) {
|
|
192
|
+
ctx.moveTo(linePosition, offsetPoint);
|
|
193
|
+
ctx.lineTo(linePosition, offsetCounterPoint);
|
|
194
|
+
}
|
|
195
|
+
} else {
|
|
196
|
+
labelPoint = this.position === 'left' ? offsetPoint - 10 : offsetPoint + 10;
|
|
197
|
+
const yPoint = alignToGridLine ? labelCenter : labelCenter + (labelGap / 2);
|
|
198
|
+
ctx.fillText(labelText, labelPoint, yPoint);
|
|
199
|
+
|
|
200
|
+
if (index > 0 && this.showGrid) {
|
|
201
|
+
ctx.moveTo(offsetPoint, linePosition);
|
|
202
|
+
ctx.lineTo(offsetCounterPoint, linePosition);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
ctx.stroke();
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (alignToGridLine && (index === this.labels.length)) {
|
|
209
|
+
let labelLastText = +labels[labels.length - 1] + (+labels[1] - +labels[0]);
|
|
210
|
+
if (isNaN(labelLastText)) {
|
|
211
|
+
labelLastText = 'Max';
|
|
212
|
+
}
|
|
213
|
+
labelCenter = Math.round(startPoint + (labelGap * labels.length));
|
|
214
|
+
linePosition = labelCenter + aliasPixel;
|
|
215
|
+
|
|
216
|
+
if (this.type === 'x') {
|
|
217
|
+
ctx.fillText(labelLastText, labelCenter, labelPoint);
|
|
218
|
+
if (this.showGrid) {
|
|
219
|
+
ctx.moveTo(linePosition, offsetPoint);
|
|
220
|
+
ctx.lineTo(linePosition, offsetCounterPoint);
|
|
221
|
+
}
|
|
222
|
+
} else {
|
|
223
|
+
ctx.fillText(labelLastText, labelPoint, labelCenter);
|
|
224
|
+
if (this.showGrid) {
|
|
225
|
+
ctx.moveTo(offsetPoint, linePosition);
|
|
226
|
+
ctx.lineTo(offsetCounterPoint, linePosition);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
ctx.stroke();
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
ctx.closePath();
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// draw plot lines and plot bands
|
|
236
|
+
if (this.plotBands?.length || this.plotLines?.length) {
|
|
237
|
+
const padding = Util.aliasPixel(ctx.lineWidth) + 1;
|
|
238
|
+
const minX = aPos.x1 + padding;
|
|
239
|
+
const maxX = aPos.x2;
|
|
240
|
+
const minY = aPos.y1 + padding;
|
|
241
|
+
const maxY = aPos.y2;
|
|
242
|
+
const labelGap = (endPoint - startPoint) / (this.labelStyle.show ? labels.length : 1);
|
|
243
|
+
|
|
244
|
+
this.plotBands?.forEach((plotBand) => {
|
|
245
|
+
if (!plotBand.from && !plotBand.to) {
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const mergedPlotBandOpt = defaultsDeep({}, plotBand, PLOT_BAND_OPTION);
|
|
250
|
+
const { from = 0, to = labels.length, label: labelOpt } = mergedPlotBandOpt;
|
|
251
|
+
const fromPos = Math.round(startPoint + (labelGap * from));
|
|
252
|
+
const toPos = Math.round(startPoint + (labelGap * to));
|
|
253
|
+
|
|
254
|
+
this.setPlotBandStyle(mergedPlotBandOpt);
|
|
255
|
+
|
|
256
|
+
if (this.type === 'x') {
|
|
257
|
+
this.drawXPlotBand(fromPos, toPos, minX, maxX, minY, maxY);
|
|
258
|
+
} else {
|
|
259
|
+
this.drawYPlotBand(fromPos, toPos, minX, maxX, minY, maxY);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (labelOpt.show) {
|
|
263
|
+
const labelOptions = this.getNormalizedLabelOptions(chartRect, labelOpt);
|
|
264
|
+
const textXY = this.getPlotBandLabelPosition(fromPos, toPos, labelOptions, maxX, minY);
|
|
265
|
+
this.drawPlotLabel(labelOptions, textXY);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
ctx.restore();
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
this.plotLines?.forEach((plotLine) => {
|
|
272
|
+
if (!plotLine.value) {
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const mergedPlotLineOpt = defaultsDeep({}, plotLine, PLOT_LINE_OPTION);
|
|
277
|
+
const { value, label: labelOpt } = mergedPlotLineOpt;
|
|
278
|
+
const dataPos = Math.round(startPoint + (labelGap * value)) + (labelGap / 2);
|
|
279
|
+
|
|
280
|
+
this.setPlotLineStyle(mergedPlotLineOpt);
|
|
281
|
+
|
|
282
|
+
if (this.type === 'x') {
|
|
283
|
+
this.drawXPlotLine(dataPos, minX, maxX, minY, maxY);
|
|
284
|
+
} else {
|
|
285
|
+
this.drawYPlotLine(dataPos, minX, maxX, minY, maxY);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (labelOpt.show) {
|
|
289
|
+
const labelOptions = this.getNormalizedLabelOptions(chartRect, labelOpt);
|
|
290
|
+
const textXY = this.getPlotLineLabelPosition(dataPos, labelOptions, maxX, minY);
|
|
291
|
+
this.drawPlotLabel(labelOptions, textXY);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
ctx.restore();
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Transforming label by designated format
|
|
301
|
+
* @param {string} value label value
|
|
302
|
+
* @param {number} maxWidth max width for each label
|
|
303
|
+
*
|
|
304
|
+
* @returns {string} formatted label
|
|
305
|
+
*/
|
|
306
|
+
getLabelFormat(value, maxWidth) {
|
|
307
|
+
if (this.formatter) {
|
|
308
|
+
const formattedLabel = this.formatter(value);
|
|
309
|
+
|
|
310
|
+
if (typeof formattedLabel === 'string') {
|
|
311
|
+
return formattedLabel;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
return this.labelStyle.fitWidth ? this.fittingString(value, maxWidth) : value;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Transforming ellipsis label by designated format and specific width
|
|
320
|
+
* @param {string} value label value
|
|
321
|
+
* @param {number} maxWidth max width for each label
|
|
322
|
+
*
|
|
323
|
+
* @returns {string} formatted label
|
|
324
|
+
*/
|
|
325
|
+
fittingString(value, maxWidth) {
|
|
326
|
+
const ctx = this.ctx;
|
|
327
|
+
|
|
328
|
+
ctx.save();
|
|
329
|
+
ctx.font = Util.getLabelStyle(this.labelStyle);
|
|
330
|
+
const dir = this.labelStyle.fitDir;
|
|
331
|
+
|
|
332
|
+
return Util.truncateLabelWithEllipsis(value, maxWidth, ctx, dir);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
export default StepScale;
|