evui 3.3.55 → 3.3.57
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/dist/evui.common.js +1202 -107
- package/dist/evui.common.js.map +1 -1
- package/dist/evui.umd.js +1202 -107
- 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/package.json +1 -1
- package/src/common/utils.js +4 -0
- package/src/components/chart/chart.core.js +47 -10
- package/src/components/chart/element/element.bar.js +39 -7
- package/src/components/chart/element/element.heatmap.js +55 -26
- package/src/components/chart/element/element.tip.js +31 -2
- package/src/components/chart/helpers/helpers.constant.js +11 -0
- package/src/components/chart/helpers/helpers.util.js +11 -0
- package/src/components/chart/model/model.store.js +20 -2
- package/src/components/chart/plugins/plugins.interaction.js +31 -9
- package/src/components/chart/plugins/plugins.scrollbar.js +629 -0
- package/src/components/chart/plugins/plugins.tooltip.js +71 -3
- package/src/components/chart/scale/scale.js +8 -6
- package/src/components/chart/scale/scale.step.js +52 -18
- package/src/components/chart/scale/scale.time.category.js +10 -8
- package/src/components/chart/style/chart.scss +81 -1
|
@@ -0,0 +1,629 @@
|
|
|
1
|
+
import { defaultsDeep, isEqual, throttle } from 'lodash-es';
|
|
2
|
+
import { truthyNumber } from '@/common/utils';
|
|
3
|
+
import { AXIS_OPTION } from '../helpers/helpers.constant';
|
|
4
|
+
import { checkNullAndUndefined } from '../../../common/utils';
|
|
5
|
+
|
|
6
|
+
const module = {
|
|
7
|
+
/**
|
|
8
|
+
* init scrollbar information
|
|
9
|
+
*/
|
|
10
|
+
initScrollbar() {
|
|
11
|
+
if (this.options.axesX?.[0]?.scrollbar?.use) {
|
|
12
|
+
this.initScrollbarInfo(this.options.axesX, 'x');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (this.options.axesY?.[0]?.scrollbar?.use) {
|
|
16
|
+
this.initScrollbarInfo(this.options.axesY, 'y');
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* init scrollbar information with axis information
|
|
22
|
+
* @param axisOpt axis option
|
|
23
|
+
* @param dir axis direction (x | y)
|
|
24
|
+
*/
|
|
25
|
+
initScrollbarInfo(axisOpt, dir) {
|
|
26
|
+
const scrollbarOpt = this.scrollbar[dir];
|
|
27
|
+
|
|
28
|
+
if (!scrollbarOpt.isInit) {
|
|
29
|
+
const merged = defaultsDeep({}, axisOpt?.[0]?.scrollbar, AXIS_OPTION.scrollbar);
|
|
30
|
+
Object.keys(merged).forEach((key) => {
|
|
31
|
+
scrollbarOpt[key] = merged[key];
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
scrollbarOpt.type = axisOpt?.[0]?.type;
|
|
35
|
+
scrollbarOpt.range = axisOpt?.[0]?.range || null;
|
|
36
|
+
|
|
37
|
+
this.createScrollbarLayout(dir);
|
|
38
|
+
this.createScrollbar(dir);
|
|
39
|
+
this.createScrollEvent(dir);
|
|
40
|
+
scrollbarOpt.isInit = true;
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
checkValidRange(dir) {
|
|
45
|
+
const scrollbarOpt = this.scrollbar[dir];
|
|
46
|
+
const axesType = scrollbarOpt.type;
|
|
47
|
+
|
|
48
|
+
if (scrollbarOpt.range?.length) {
|
|
49
|
+
const [min, max] = scrollbarOpt.range;
|
|
50
|
+
|
|
51
|
+
if (!(truthyNumber(min) && truthyNumber(max))) {
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (axesType === 'step') {
|
|
56
|
+
const labels = this.options.type === 'heatMap' ? this.data.labels[dir] : this.data.labels;
|
|
57
|
+
if (min < 0 || max > labels.length - 1) {
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
} else {
|
|
61
|
+
const minMax = this.minMax[dir]?.[0];
|
|
62
|
+
if (+min < +minMax.min || +max > +minMax.max) {
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return false;
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* update scrollbar information
|
|
73
|
+
*/
|
|
74
|
+
updateScrollbar(updateData) {
|
|
75
|
+
this.updateScrollbarInfo('x', updateData);
|
|
76
|
+
this.updateScrollbarInfo('y', updateData);
|
|
77
|
+
},
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Updated scrollbar information with updated axis information
|
|
81
|
+
* @param dir axis direction (x | y)
|
|
82
|
+
* @param updateData is update data
|
|
83
|
+
*/
|
|
84
|
+
updateScrollbarInfo(dir, updateData) {
|
|
85
|
+
const { axesX, axesY } = this.options;
|
|
86
|
+
const newOpt = dir === 'x' ? axesX : axesY;
|
|
87
|
+
if (!this.scrollbar[dir].isInit && newOpt?.[0]?.scrollbar?.use && newOpt?.[0]?.range) {
|
|
88
|
+
this.initScrollbarInfo(newOpt, dir);
|
|
89
|
+
return;
|
|
90
|
+
} else if (!newOpt?.[0].scrollbar?.use || checkNullAndUndefined(newOpt?.[0]?.range)) {
|
|
91
|
+
this.destroyScrollbar(dir);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const axisOpt = dir === 'x' ? this.axesX : this.axesY;
|
|
96
|
+
const isUpdateAxesRange = !isEqual(newOpt?.[0]?.range, axisOpt?.[0]?.range);
|
|
97
|
+
if (isUpdateAxesRange || updateData) {
|
|
98
|
+
this.scrollbar[dir].range = newOpt?.[0]?.range || null;
|
|
99
|
+
}
|
|
100
|
+
this.scrollbar[dir].use = !!newOpt?.[0].scrollbar?.use;
|
|
101
|
+
},
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* update scrollbar position
|
|
105
|
+
*/
|
|
106
|
+
updateScrollbarPosition() {
|
|
107
|
+
if (this.scrollbar.x?.use && this.scrollbar.x?.isInit) {
|
|
108
|
+
if (this.checkValidRange('x')) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
this.setScrollbarPosition('x');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (this.scrollbar.y?.use && this.scrollbar.y?.isInit) {
|
|
115
|
+
if (this.checkValidRange('y')) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
this.setScrollbarPosition('y');
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* create scrollbar layout
|
|
124
|
+
* @param dir axis direction ('x' | 'y')
|
|
125
|
+
*/
|
|
126
|
+
createScrollbarLayout(dir) {
|
|
127
|
+
const scrollbarOpt = this.scrollbar[dir];
|
|
128
|
+
scrollbarOpt.dom = document.createElement('div');
|
|
129
|
+
scrollbarOpt.dom.className = 'ev-chart-scrollbar';
|
|
130
|
+
scrollbarOpt.dom.dataset.type = 'scrollbar';
|
|
131
|
+
|
|
132
|
+
const containerDOM = document.createElement('div');
|
|
133
|
+
containerDOM.className = 'ev-chart-scrollbar-container';
|
|
134
|
+
containerDOM.dataset.type = dir;
|
|
135
|
+
|
|
136
|
+
scrollbarOpt.dom.appendChild(containerDOM);
|
|
137
|
+
this.wrapperDOM.appendChild(scrollbarOpt.dom);
|
|
138
|
+
},
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* create scrollbar
|
|
142
|
+
* @param dir axis direction ('x' | 'y')
|
|
143
|
+
*/
|
|
144
|
+
createScrollbar(dir) {
|
|
145
|
+
const scrollbarOpt = this.scrollbar[dir];
|
|
146
|
+
const containerDOM = scrollbarOpt.dom.children[0];
|
|
147
|
+
this.createScrollbarTrack(containerDOM);
|
|
148
|
+
this.createScrollbarThumb(containerDOM);
|
|
149
|
+
|
|
150
|
+
if (scrollbarOpt.showButton) {
|
|
151
|
+
this.createScrollbarButton(containerDOM);
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* create scrollbar track
|
|
157
|
+
* @param containerDOM
|
|
158
|
+
*/
|
|
159
|
+
createScrollbarTrack(containerDOM) {
|
|
160
|
+
const trackDOM = document.createElement('div');
|
|
161
|
+
trackDOM.className = 'ev-chart-scrollbar-track';
|
|
162
|
+
trackDOM.dataset.type = 'track';
|
|
163
|
+
containerDOM.appendChild(trackDOM);
|
|
164
|
+
},
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* create scrollbar thumb
|
|
168
|
+
* @param containerDOM
|
|
169
|
+
*/
|
|
170
|
+
createScrollbarThumb(containerDOM) {
|
|
171
|
+
const thumbDOM = document.createElement('div');
|
|
172
|
+
thumbDOM.className = 'ev-chart-scrollbar-thumb';
|
|
173
|
+
thumbDOM.dataset.type = 'thumb';
|
|
174
|
+
containerDOM.appendChild(thumbDOM);
|
|
175
|
+
},
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* create scrollbar up, down button
|
|
179
|
+
* @param containerDOM
|
|
180
|
+
*/
|
|
181
|
+
createScrollbarButton(containerDOM) {
|
|
182
|
+
const upBtnDOM = document.createElement('div');
|
|
183
|
+
upBtnDOM.className = 'ev-chart-scrollbar-button ev-chart-scrollbar-button-up';
|
|
184
|
+
upBtnDOM.dataset.type = 'button';
|
|
185
|
+
const iconUpBtn = document.createElement('i');
|
|
186
|
+
iconUpBtn.className = 'ev-icon ev-icon-triangle-up ev-chart-scrollbar-button-icon';
|
|
187
|
+
iconUpBtn.dataset.type = 'button-icon';
|
|
188
|
+
upBtnDOM.appendChild(iconUpBtn);
|
|
189
|
+
|
|
190
|
+
const downBtnDOM = document.createElement('div');
|
|
191
|
+
downBtnDOM.className = 'ev-chart-scrollbar-button ev-chart-scrollbar-button-down';
|
|
192
|
+
downBtnDOM.dataset.type = 'button';
|
|
193
|
+
const iconDownBtn = document.createElement('i');
|
|
194
|
+
iconDownBtn.className = 'ev-icon ev-icon-triangle-down ev-chart-scrollbar-button-icon';
|
|
195
|
+
iconDownBtn.dataset.type = 'button-icon';
|
|
196
|
+
downBtnDOM.appendChild(iconDownBtn);
|
|
197
|
+
|
|
198
|
+
containerDOM.appendChild(upBtnDOM);
|
|
199
|
+
containerDOM.appendChild(downBtnDOM);
|
|
200
|
+
},
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* set scrollbar position
|
|
204
|
+
* @param dir axis direction ('x' | 'y')
|
|
205
|
+
*/
|
|
206
|
+
setScrollbarPosition(dir) {
|
|
207
|
+
const scrollbarOpt = this.scrollbar[dir];
|
|
208
|
+
if (!scrollbarOpt.use || !scrollbarOpt.range) {
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const scrollbarDOM = scrollbarOpt.dom;
|
|
213
|
+
const chartRect = this.chartRect;
|
|
214
|
+
const labelOffset = this.labelOffset;
|
|
215
|
+
const aPos = {
|
|
216
|
+
x1: chartRect.x1 + labelOffset.left,
|
|
217
|
+
x2: chartRect.x2 - labelOffset.right,
|
|
218
|
+
y1: chartRect.y1 + labelOffset.top,
|
|
219
|
+
y2: chartRect.y2 - labelOffset.bottom,
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
const titleHeight = this.options.title?.show ? this.options.title?.height : 0;
|
|
223
|
+
const isXScroll = dir === 'x';
|
|
224
|
+
const scrollHeight = isXScroll ? scrollbarOpt.height : scrollbarOpt.width;
|
|
225
|
+
const fullSize = isXScroll ? (aPos.x2 - aPos.x1) : (aPos.y2 - aPos.y1);
|
|
226
|
+
const buttonSize = scrollbarOpt.showButton ? scrollHeight : 0;
|
|
227
|
+
const trackSize = fullSize - (buttonSize * 2);
|
|
228
|
+
const thumbSize = this.getScrollbarThumbSize(dir, trackSize);
|
|
229
|
+
|
|
230
|
+
let scrollbarStyle = 'display: block;';
|
|
231
|
+
let scrollbarTrackStyle;
|
|
232
|
+
let scrollbarThumbStyle;
|
|
233
|
+
let upBtnStyle;
|
|
234
|
+
let downBtnStyle;
|
|
235
|
+
let commonBtnStyle = `width:${buttonSize}px;height:${buttonSize}px;`;
|
|
236
|
+
if (isXScroll) {
|
|
237
|
+
scrollbarStyle = `top: ${chartRect.y2 + titleHeight + labelOffset.top}px;`;
|
|
238
|
+
scrollbarStyle += `left: ${aPos.x1}px;`;
|
|
239
|
+
scrollbarStyle += `width: ${fullSize}px;`;
|
|
240
|
+
scrollbarStyle += ` height: ${scrollHeight}px;`;
|
|
241
|
+
|
|
242
|
+
scrollbarTrackStyle = 'top: 0;';
|
|
243
|
+
scrollbarTrackStyle += `left: ${buttonSize}px;`;
|
|
244
|
+
scrollbarTrackStyle += `width: ${trackSize}px;`;
|
|
245
|
+
scrollbarTrackStyle += 'height: 100%;';
|
|
246
|
+
|
|
247
|
+
scrollbarThumbStyle = `width: ${thumbSize.size}px;`;
|
|
248
|
+
scrollbarThumbStyle += 'height: 100%;';
|
|
249
|
+
scrollbarThumbStyle += `left: ${thumbSize.position + buttonSize}px`;
|
|
250
|
+
|
|
251
|
+
commonBtnStyle += 'transform:rotate(90deg);top: 0;';
|
|
252
|
+
|
|
253
|
+
upBtnStyle = `${commonBtnStyle}right:0;`;
|
|
254
|
+
downBtnStyle = `${commonBtnStyle}left:0;`;
|
|
255
|
+
} else {
|
|
256
|
+
scrollbarStyle = `top: ${aPos.y1 + titleHeight}px;`;
|
|
257
|
+
scrollbarStyle += `left: ${aPos.x2 + 10}px;`;
|
|
258
|
+
scrollbarStyle += `width: ${scrollHeight}px;`;
|
|
259
|
+
scrollbarStyle += `height: ${fullSize}px;`;
|
|
260
|
+
|
|
261
|
+
scrollbarTrackStyle = `top: ${buttonSize}px;`;
|
|
262
|
+
scrollbarTrackStyle += 'left: 0;';
|
|
263
|
+
scrollbarTrackStyle += 'width: 100%;';
|
|
264
|
+
scrollbarTrackStyle += `height: ${trackSize}px;`;
|
|
265
|
+
|
|
266
|
+
scrollbarThumbStyle = 'width: 100%;';
|
|
267
|
+
scrollbarThumbStyle += `height: ${thumbSize.size}px;`;
|
|
268
|
+
scrollbarThumbStyle += `bottom: ${thumbSize.position + buttonSize}px`;
|
|
269
|
+
|
|
270
|
+
commonBtnStyle += 'left:0;';
|
|
271
|
+
upBtnStyle = `${commonBtnStyle}top: 0;`;
|
|
272
|
+
downBtnStyle = `${commonBtnStyle}bottom: 0;`;
|
|
273
|
+
}
|
|
274
|
+
scrollbarDOM.style.cssText = scrollbarStyle;
|
|
275
|
+
|
|
276
|
+
const scrollbarTrackDOM = scrollbarDOM.getElementsByClassName('ev-chart-scrollbar-track');
|
|
277
|
+
scrollbarTrackDOM[0].style.cssText = scrollbarTrackStyle;
|
|
278
|
+
scrollbarTrackDOM[0].style.backgroundColor = scrollbarOpt.background;
|
|
279
|
+
|
|
280
|
+
const scrollbarThumbDOM = scrollbarDOM.getElementsByClassName('ev-chart-scrollbar-thumb');
|
|
281
|
+
scrollbarThumbDOM[0].style.cssText = scrollbarThumbStyle;
|
|
282
|
+
scrollbarThumbDOM[0].style.backgroundColor = scrollbarOpt.thumbStyle.background;
|
|
283
|
+
scrollbarThumbDOM[0].style.borderRadius = `${scrollbarOpt.thumbStyle.radius}px`;
|
|
284
|
+
|
|
285
|
+
if (scrollbarOpt.showButton) {
|
|
286
|
+
const upBtnDOM = scrollbarDOM.getElementsByClassName('ev-chart-scrollbar-button-up');
|
|
287
|
+
const endPosition = Math.floor(trackSize - thumbSize.size);
|
|
288
|
+
const upBtnOpacity = Math.floor(thumbSize.position) > endPosition ? 0.5 : 1;
|
|
289
|
+
upBtnDOM[0].style.cssText = `background-color: ${scrollbarOpt.background};${upBtnStyle}`;
|
|
290
|
+
upBtnDOM[0].style.opacity = upBtnOpacity;
|
|
291
|
+
upBtnDOM[0].children[0].style.display = 'block';
|
|
292
|
+
const downBtnDOM = scrollbarDOM.getElementsByClassName('ev-chart-scrollbar-button-down');
|
|
293
|
+
downBtnDOM[0].style.cssText = `background-color: ${scrollbarOpt.background};${downBtnStyle}`;
|
|
294
|
+
downBtnDOM[0].style.opacity = Math.floor(thumbSize.position) < 0 ? 0.5 : 1;
|
|
295
|
+
downBtnDOM[0].children[0].style.display = 'block';
|
|
296
|
+
}
|
|
297
|
+
},
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* get scrollbar thumb size
|
|
301
|
+
* @param dir axis direction ('x' | 'y')
|
|
302
|
+
* @param trackSize scrollbar track size
|
|
303
|
+
*/
|
|
304
|
+
getScrollbarThumbSize(dir, trackSize) {
|
|
305
|
+
const scrollbarOpt = this.scrollbar[dir];
|
|
306
|
+
const [min, max] = scrollbarOpt.range;
|
|
307
|
+
const axesType = scrollbarOpt.type;
|
|
308
|
+
|
|
309
|
+
let thumbSize;
|
|
310
|
+
let steps;
|
|
311
|
+
let interval = 1;
|
|
312
|
+
let startValue = 0;
|
|
313
|
+
let thumbPosition = 0;
|
|
314
|
+
if (axesType === 'step') {
|
|
315
|
+
const labels = this.options.type === 'heatMap' ? this.data.labels[dir] : this.data.labels;
|
|
316
|
+
const range = (max - min) + 1;
|
|
317
|
+
steps = labels.length;
|
|
318
|
+
|
|
319
|
+
const intervalSize = trackSize / steps;
|
|
320
|
+
thumbSize = intervalSize * range;
|
|
321
|
+
thumbPosition = intervalSize * min;
|
|
322
|
+
} else {
|
|
323
|
+
const axisOpt = dir === 'x' ? this.axesX : this.axesY;
|
|
324
|
+
const minMax = this.minMax[dir]?.[0];
|
|
325
|
+
const graphRange = (+minMax.max) - (+minMax.min);
|
|
326
|
+
const range = (+max) - (+min);
|
|
327
|
+
if (axesType === 'time') {
|
|
328
|
+
interval = axisOpt?.[0]?.getInterval({
|
|
329
|
+
minValue: minMax.min,
|
|
330
|
+
maxValue: minMax.max,
|
|
331
|
+
maxSteps: this.labelRange[dir]?.[0]?.max,
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
steps = Math.ceil(graphRange / interval) + 1;
|
|
335
|
+
startValue = +minMax.min;
|
|
336
|
+
|
|
337
|
+
const intervalSize = trackSize / steps;
|
|
338
|
+
const count = (range / interval) + 1;
|
|
339
|
+
const point = (+min - startValue);
|
|
340
|
+
thumbSize = intervalSize * count;
|
|
341
|
+
thumbPosition = intervalSize * (point / interval);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
scrollbarOpt.startValue = startValue;
|
|
345
|
+
scrollbarOpt.steps = steps;
|
|
346
|
+
scrollbarOpt.interval = interval;
|
|
347
|
+
|
|
348
|
+
return {
|
|
349
|
+
size: thumbSize,
|
|
350
|
+
position: thumbPosition,
|
|
351
|
+
};
|
|
352
|
+
},
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* get scrollbar containerDOM
|
|
356
|
+
* @param targetDOM event target dom
|
|
357
|
+
* @returns {HTMLElement|Element|*}
|
|
358
|
+
*/
|
|
359
|
+
getScrollbarContainerDOM(targetDOM) {
|
|
360
|
+
const childTypes = ['track', 'thumb', 'button'];
|
|
361
|
+
|
|
362
|
+
const type = targetDOM.dataset.type;
|
|
363
|
+
if (childTypes.includes(type)) {
|
|
364
|
+
return targetDOM.parentElement;
|
|
365
|
+
} else if (type === 'button-icon') {
|
|
366
|
+
return targetDOM.parentElement.parentElement;
|
|
367
|
+
} else if (type === 'scrollbar') {
|
|
368
|
+
return targetDOM.getElementsByClassName('ev-chart-scrollbar-container')[0];
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
return targetDOM;
|
|
372
|
+
},
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* update scrollbar option range
|
|
376
|
+
* @param dir axis direction ('x' | 'y')
|
|
377
|
+
* @param isUp
|
|
378
|
+
*/
|
|
379
|
+
updateScrollbarRange(dir, isUp) {
|
|
380
|
+
const scrollbarOpt = this.scrollbar[dir];
|
|
381
|
+
const { startValue, range, interval, steps } = scrollbarOpt;
|
|
382
|
+
const endValue = startValue + (interval * steps);
|
|
383
|
+
const axisOpt = dir === 'x' ? this.axesX[0] : this.axesY[0];
|
|
384
|
+
const [min, max] = range ?? [];
|
|
385
|
+
|
|
386
|
+
if (!truthyNumber(min) || !truthyNumber(max)) {
|
|
387
|
+
scrollbarOpt.range = axisOpt?.range || null;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
let minValue;
|
|
391
|
+
let maxValue;
|
|
392
|
+
let isOutOfRange = false;
|
|
393
|
+
if (isUp) {
|
|
394
|
+
minValue = min + interval;
|
|
395
|
+
maxValue = max + interval;
|
|
396
|
+
isOutOfRange = maxValue >= endValue;
|
|
397
|
+
} else {
|
|
398
|
+
minValue = min - interval;
|
|
399
|
+
maxValue = max - interval;
|
|
400
|
+
isOutOfRange = minValue < startValue;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
if (!isOutOfRange) {
|
|
404
|
+
scrollbarOpt.range = [minValue, maxValue];
|
|
405
|
+
|
|
406
|
+
this.update({
|
|
407
|
+
updateSeries: false,
|
|
408
|
+
updateSelTip: { update: false, keepDomain: false },
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
},
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* create scroll event
|
|
415
|
+
*/
|
|
416
|
+
createScrollEvent() {
|
|
417
|
+
this.onScrollbarClick = (e) => {
|
|
418
|
+
e.preventDefault();
|
|
419
|
+
|
|
420
|
+
const type = e.target.dataset.type;
|
|
421
|
+
const containerDOM = this.getScrollbarContainerDOM(e.target);
|
|
422
|
+
const buttonTypes = ['button', 'button-icon'];
|
|
423
|
+
const dir = containerDOM.dataset.type;
|
|
424
|
+
|
|
425
|
+
let isUp;
|
|
426
|
+
if (buttonTypes.includes(type)) {
|
|
427
|
+
let buttonDOM;
|
|
428
|
+
if (type === 'button') {
|
|
429
|
+
buttonDOM = e.target;
|
|
430
|
+
} else if (type === 'button-icon') {
|
|
431
|
+
buttonDOM = e.target.parentElement;
|
|
432
|
+
}
|
|
433
|
+
isUp = buttonDOM.className.includes('up');
|
|
434
|
+
} else if (type === 'track') {
|
|
435
|
+
const thumbDOM = containerDOM.getElementsByClassName('ev-chart-scrollbar-thumb');
|
|
436
|
+
const { x, y } = thumbDOM[0].getBoundingClientRect();
|
|
437
|
+
const isXScroll = dir === 'x';
|
|
438
|
+
const clickPoint = isXScroll ? e.clientX : -e.clientY;
|
|
439
|
+
const thumbPosition = isXScroll ? x : -y;
|
|
440
|
+
isUp = (clickPoint > thumbPosition);
|
|
441
|
+
} else {
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
this.updateScrollbarRange(dir, isUp);
|
|
445
|
+
};
|
|
446
|
+
|
|
447
|
+
this.onScrollbarDown = (e) => {
|
|
448
|
+
e.preventDefault();
|
|
449
|
+
|
|
450
|
+
if (e.target.dataset.type !== 'thumb') {
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
const containerDOM = this.getScrollbarContainerDOM(e.target);
|
|
455
|
+
const dir = containerDOM.dataset.type;
|
|
456
|
+
const thumbDOM = containerDOM.getElementsByClassName('ev-chart-scrollbar-thumb');
|
|
457
|
+
const { x, y, height } = thumbDOM[0].getBoundingClientRect();
|
|
458
|
+
const scrollbarOpt = this.scrollbar[dir];
|
|
459
|
+
scrollbarOpt.scrolling = true;
|
|
460
|
+
if (dir === 'x') {
|
|
461
|
+
scrollbarOpt.pointInThumb = e.clientX - x;
|
|
462
|
+
} else {
|
|
463
|
+
scrollbarOpt.pointInThumb = y + height - e.clientY;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
const scrollbarDOM = scrollbarOpt.dom;
|
|
467
|
+
scrollbarDOM.addEventListener('mousemove', this.onScrollbarMove);
|
|
468
|
+
scrollbarDOM.addEventListener('mouseup', this.onScrollbarUp);
|
|
469
|
+
};
|
|
470
|
+
|
|
471
|
+
const onScrollbarMove = (e) => {
|
|
472
|
+
this.scrolling(e);
|
|
473
|
+
};
|
|
474
|
+
|
|
475
|
+
this.onScrollbarMove = throttle(onScrollbarMove, 5);
|
|
476
|
+
|
|
477
|
+
this.onScrollbarUp = (e) => {
|
|
478
|
+
e.preventDefault();
|
|
479
|
+
|
|
480
|
+
this.stopScrolling(e);
|
|
481
|
+
};
|
|
482
|
+
|
|
483
|
+
this.onScrollbarLeave = (e) => {
|
|
484
|
+
e.preventDefault();
|
|
485
|
+
|
|
486
|
+
this.scrolling(e);
|
|
487
|
+
this.stopScrolling(e);
|
|
488
|
+
};
|
|
489
|
+
|
|
490
|
+
this.onScrollbarWheel = (e) => {
|
|
491
|
+
e.preventDefault();
|
|
492
|
+
|
|
493
|
+
this.updateScrollbarRange('y', e.deltaY < 0);
|
|
494
|
+
};
|
|
495
|
+
|
|
496
|
+
if (this.scrollbar.x.use && !this.scrollbar.x.isInit) {
|
|
497
|
+
const scrollbarXDOM = this.scrollbar.x.dom;
|
|
498
|
+
scrollbarXDOM.addEventListener('click', this.onScrollbarClick);
|
|
499
|
+
scrollbarXDOM.addEventListener('mousedown', this.onScrollbarDown);
|
|
500
|
+
scrollbarXDOM.addEventListener('mouseleave', this.onScrollbarLeave);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
if (this.scrollbar.y.use && !this.scrollbar.y.isInit) {
|
|
504
|
+
const scrollbarYDOM = this.scrollbar.y.dom;
|
|
505
|
+
scrollbarYDOM.addEventListener('click', this.onScrollbarClick);
|
|
506
|
+
scrollbarYDOM.addEventListener('mousedown', this.onScrollbarDown);
|
|
507
|
+
scrollbarYDOM.addEventListener('mouseleave', this.onScrollbarLeave);
|
|
508
|
+
this.overlayCanvas?.addEventListener('wheel', this.onScrollbarWheel);
|
|
509
|
+
}
|
|
510
|
+
},
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* Update scroll information by move event
|
|
514
|
+
* @param e Event
|
|
515
|
+
*/
|
|
516
|
+
scrolling(e) {
|
|
517
|
+
const containerDOM = this.getScrollbarContainerDOM(e.target);
|
|
518
|
+
const dir = containerDOM.dataset.type;
|
|
519
|
+
if (!this.scrollbar[dir].scrolling) {
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
const {
|
|
524
|
+
steps, range, pointInThumb,
|
|
525
|
+
startValue, interval,
|
|
526
|
+
} = this.scrollbar[dir];
|
|
527
|
+
|
|
528
|
+
const trackDOM = containerDOM.getElementsByClassName('ev-chart-scrollbar-track');
|
|
529
|
+
const { x, y, width, height } = trackDOM[0].getBoundingClientRect();
|
|
530
|
+
|
|
531
|
+
const isXScroll = dir === 'x';
|
|
532
|
+
const sp = isXScroll ? x : y;
|
|
533
|
+
const trackSize = isXScroll ? width : height;
|
|
534
|
+
const intervalSize = trackSize / steps;
|
|
535
|
+
const endValue = (startValue + ((steps - 1) * interval));
|
|
536
|
+
|
|
537
|
+
let movePoint = isXScroll ? e.clientX : e.clientY;
|
|
538
|
+
if (movePoint < sp) {
|
|
539
|
+
movePoint = sp;
|
|
540
|
+
} else if (movePoint > sp + trackSize) {
|
|
541
|
+
movePoint = sp + trackSize;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
let move;
|
|
545
|
+
if (isXScroll) {
|
|
546
|
+
move = movePoint - sp - pointInThumb;
|
|
547
|
+
} else {
|
|
548
|
+
move = (sp + trackSize) - movePoint - pointInThumb;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
if (move <= 0) {
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
let movedMin;
|
|
556
|
+
let movedMax;
|
|
557
|
+
const currValue = (Math.round(Math.abs(move) / intervalSize) * interval);
|
|
558
|
+
const [min, max] = range;
|
|
559
|
+
if (move > 0) {
|
|
560
|
+
const incrementValue = startValue + (currValue - +min);
|
|
561
|
+
movedMin = +min + incrementValue;
|
|
562
|
+
movedMax = movedMin + (+max - +min);
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
if (movedMin < startValue || movedMax > endValue) {
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
this.scrollbar[dir].range = [movedMin, movedMax];
|
|
570
|
+
this.update({
|
|
571
|
+
updateSeries: false,
|
|
572
|
+
updateSelTip: { update: false, keepDomain: false },
|
|
573
|
+
});
|
|
574
|
+
},
|
|
575
|
+
|
|
576
|
+
/**
|
|
577
|
+
* init scrolling event
|
|
578
|
+
* @param e
|
|
579
|
+
*/
|
|
580
|
+
stopScrolling(e) {
|
|
581
|
+
const containerDOM = this.getScrollbarContainerDOM(e.target);
|
|
582
|
+
const dir = containerDOM.dataset.type;
|
|
583
|
+
const scrollbarOpt = this.scrollbar[dir];
|
|
584
|
+
|
|
585
|
+
if (scrollbarOpt.scrolling) {
|
|
586
|
+
scrollbarOpt.scrolling = false;
|
|
587
|
+
|
|
588
|
+
const scrollbarDOM = scrollbarOpt.dom;
|
|
589
|
+
scrollbarDOM.removeEventListener('mousemove', this.onScrollbarMove, false);
|
|
590
|
+
scrollbarDOM.removeEventListener('mouseup', this.onScrollbarUp, false);
|
|
591
|
+
}
|
|
592
|
+
},
|
|
593
|
+
|
|
594
|
+
/**
|
|
595
|
+
* hide scrollbar dom
|
|
596
|
+
* @param dir axis direction ('x' | 'y')
|
|
597
|
+
*/
|
|
598
|
+
hideScrollbar(dir) {
|
|
599
|
+
const scrollbarDOM = this.scrollbar[dir].dom;
|
|
600
|
+
|
|
601
|
+
if (!scrollbarDOM) {
|
|
602
|
+
return;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
const scrollbarStyle = scrollbarDOM?.style;
|
|
606
|
+
scrollbarStyle.display = 'none';
|
|
607
|
+
scrollbarStyle.width = '0';
|
|
608
|
+
scrollbarStyle.height = '0';
|
|
609
|
+
},
|
|
610
|
+
|
|
611
|
+
/**
|
|
612
|
+
* destroy scrollbar dom
|
|
613
|
+
* @param dir axis direction ('x' | 'y')
|
|
614
|
+
*/
|
|
615
|
+
destroyScrollbar(dir) {
|
|
616
|
+
const scrollbarXDOM = this.scrollbar[dir].dom;
|
|
617
|
+
|
|
618
|
+
if (scrollbarXDOM) {
|
|
619
|
+
scrollbarXDOM.remove();
|
|
620
|
+
this.scrollbar[dir] = { isInit: false };
|
|
621
|
+
|
|
622
|
+
if (dir === 'y') {
|
|
623
|
+
this.overlayCanvas?.removeEventListener('wheel', this.onScrollbarWheel, false);
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
},
|
|
627
|
+
};
|
|
628
|
+
|
|
629
|
+
export default module;
|
|
@@ -34,9 +34,11 @@ const modules = {
|
|
|
34
34
|
this.tooltipDOM.style.display = 'none';
|
|
35
35
|
this.setFontFamily();
|
|
36
36
|
|
|
37
|
-
this.
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
if (!this.options.tooltip?.formatter?.dom) {
|
|
38
|
+
this.tooltipBodyDOM.appendChild(this.tooltipCanvas);
|
|
39
|
+
this.tooltipDOM.appendChild(this.tooltipHeaderDOM);
|
|
40
|
+
this.tooltipDOM.appendChild(this.tooltipBodyDOM);
|
|
41
|
+
}
|
|
40
42
|
|
|
41
43
|
document.body.appendChild(this.tooltipDOM);
|
|
42
44
|
|
|
@@ -563,6 +565,72 @@ const modules = {
|
|
|
563
565
|
ctx.restore();
|
|
564
566
|
},
|
|
565
567
|
|
|
568
|
+
setCustomTooltipLayoutPosition(hitInfo, e) {
|
|
569
|
+
const mouseX = e.pageX;
|
|
570
|
+
const mouseY = e.pageY;
|
|
571
|
+
|
|
572
|
+
const customTooltipEl = document.getElementsByClassName('ev-chart-tooltip-custom')?.[0];
|
|
573
|
+
if (!customTooltipEl) {
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
const contentsWidth = customTooltipEl.offsetWidth;
|
|
578
|
+
const contentsHeight = customTooltipEl.offsetHeight;
|
|
579
|
+
|
|
580
|
+
this.tooltipDOM.style.height = 'auto';
|
|
581
|
+
this.tooltipBodyDOM.style.height = `${contentsHeight + 6}px`;
|
|
582
|
+
|
|
583
|
+
const bodyWidth = document.body.clientWidth;
|
|
584
|
+
const bodyHeight = document.body.clientHeight;
|
|
585
|
+
const distanceMouseAndTooltip = 20;
|
|
586
|
+
const maximumPosX = bodyWidth - contentsWidth - distanceMouseAndTooltip;
|
|
587
|
+
const maximumPosY = bodyHeight - (TITLE_HEIGHT + contentsHeight) - distanceMouseAndTooltip;
|
|
588
|
+
const expectedPosX = mouseX + distanceMouseAndTooltip;
|
|
589
|
+
const expectedPosY = mouseY + distanceMouseAndTooltip;
|
|
590
|
+
const reversedPosX = mouseX - contentsWidth - distanceMouseAndTooltip;
|
|
591
|
+
const reversedPosY = mouseY - (TITLE_HEIGHT + contentsHeight) - distanceMouseAndTooltip;
|
|
592
|
+
this.tooltipDOM.style.left = expectedPosX > maximumPosX
|
|
593
|
+
? `${reversedPosX}px`
|
|
594
|
+
: `${expectedPosX}px`;
|
|
595
|
+
this.tooltipDOM.style.top = expectedPosY > maximumPosY
|
|
596
|
+
? `${reversedPosY}px`
|
|
597
|
+
: `${expectedPosY}px`;
|
|
598
|
+
|
|
599
|
+
this.tooltipDOM.style.display = 'block';
|
|
600
|
+
},
|
|
601
|
+
|
|
602
|
+
/**
|
|
603
|
+
* Draw User Custom Tooltip (tooltip > formatter > html)
|
|
604
|
+
* call "formatter > html" and append to tooltip DOM
|
|
605
|
+
* @param hitInfoItems
|
|
606
|
+
*/
|
|
607
|
+
drawCustomTooltip(hitInfoItems) {
|
|
608
|
+
const opt = this.options?.tooltip;
|
|
609
|
+
if (opt.formatter?.html) {
|
|
610
|
+
this.tooltipDOM.innerHTML = '';
|
|
611
|
+
|
|
612
|
+
const seriesList = [];
|
|
613
|
+
Object.keys(hitInfoItems).forEach((sId) => {
|
|
614
|
+
seriesList.push({
|
|
615
|
+
sId,
|
|
616
|
+
data: hitInfoItems[sId].data,
|
|
617
|
+
color: hitInfoItems[sId].color,
|
|
618
|
+
name: hitInfoItems[sId].name,
|
|
619
|
+
});
|
|
620
|
+
});
|
|
621
|
+
|
|
622
|
+
const userCustomTooltipBody = Util.htmlToElement(opt?.formatter?.html((seriesList)));
|
|
623
|
+
if (userCustomTooltipBody) {
|
|
624
|
+
this.tooltipDOM.appendChild(userCustomTooltipBody);
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
this.tooltipDOM.style.overflowY = 'hidden';
|
|
628
|
+
this.tooltipDOM.style.backgroundColor = opt.backgroundColor;
|
|
629
|
+
this.tooltipDOM.style.border = `1px solid ${opt.borderColor}`;
|
|
630
|
+
this.tooltipDOM.style.color = opt.fontColor;
|
|
631
|
+
}
|
|
632
|
+
},
|
|
633
|
+
|
|
566
634
|
/**
|
|
567
635
|
* set style properties on tooltip DOM
|
|
568
636
|
* @param tooltipOptions
|