evui 3.4.110 → 3.4.111
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 +181 -61
- package/dist/evui.common.js.map +1 -1
- package/dist/evui.umd.js +181 -61
- 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/components/chart/chart.core.js +4 -2
- package/src/components/chart/element/element.line.js +42 -41
- package/src/components/chart/helpers/helpers.canvas.js +4 -4
- package/src/components/chart/helpers/helpers.constant.js +1 -0
- package/src/components/chart/model/index.js +46 -0
- package/src/components/chart/model/model.store.js +42 -16
- package/src/components/chart/plugins/plugins.interaction.js +1 -1
package/package.json
CHANGED
|
@@ -570,8 +570,9 @@ class EvChart {
|
|
|
570
570
|
|
|
571
571
|
/**
|
|
572
572
|
* Get chart DOM size and set canvas size
|
|
573
|
+
* @typedef {import('./model/index').ChartDOMSize} ChartDOMSize
|
|
573
574
|
*
|
|
574
|
-
* @returns {
|
|
575
|
+
* @returns {ChartDOMSize} chart size information
|
|
575
576
|
*/
|
|
576
577
|
getChartDOMRect() {
|
|
577
578
|
const rect = this.chartDOM?.getBoundingClientRect();
|
|
@@ -586,8 +587,9 @@ class EvChart {
|
|
|
586
587
|
|
|
587
588
|
/**
|
|
588
589
|
* Calculate chart size
|
|
590
|
+
* @typedef {import('./model/index').ChartRect} ChartRect
|
|
589
591
|
*
|
|
590
|
-
* @returns {
|
|
592
|
+
* @returns {ChartRect} chart size information
|
|
591
593
|
*/
|
|
592
594
|
getChartRect() {
|
|
593
595
|
const { width, height } = this.getChartDOMRect();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { defaultsDeep } from 'lodash-es';
|
|
1
|
+
import { defaultsDeep, isNil, isUndefined } from 'lodash-es';
|
|
2
2
|
import { COLOR, LINE_OPTION } from '../helpers/helpers.constant';
|
|
3
3
|
import Util from '../helpers/helpers.util';
|
|
4
4
|
import Canvas from '../helpers/helpers.canvas';
|
|
@@ -26,6 +26,7 @@ class Line {
|
|
|
26
26
|
normal: { opacity: 1, lineWidth: 1 },
|
|
27
27
|
highlight: { opacity: 1, lineWidth: 2 },
|
|
28
28
|
};
|
|
29
|
+
/** @type {import('../model/index').ChartSeriesDataPoint[]} */
|
|
29
30
|
this.data = [];
|
|
30
31
|
this.beforeMouseXp = 0;
|
|
31
32
|
this.beforeMouseYp = 0;
|
|
@@ -33,12 +34,23 @@ class Line {
|
|
|
33
34
|
this.size = {
|
|
34
35
|
comboOffset: 0,
|
|
35
36
|
};
|
|
36
|
-
this.usePassingValue =
|
|
37
|
+
this.usePassingValue = !isUndefined(this.passingValue) && this.interpolation === 'linear';
|
|
37
38
|
}
|
|
38
39
|
|
|
40
|
+
/**
|
|
41
|
+
* @typedef {Object} LineDrawParam
|
|
42
|
+
* @property {CanvasRenderingContext2D} ctx - 캔버스 렌더링 컨텍스트
|
|
43
|
+
* @property {object} chartRect - 차트 영역 정보
|
|
44
|
+
* @property {object} labelOffset - 라벨 오프셋 정보
|
|
45
|
+
* @property {object} axesSteps - 축 스텝 정보
|
|
46
|
+
* @property {object} [selectLabel] - 선택된 라벨 정보
|
|
47
|
+
* @property {object} [selectSeries] - 선택된 시리즈 정보
|
|
48
|
+
* @property {object} [legendHitInfo] - 범례 히트 정보
|
|
49
|
+
* @property {boolean} [isBrush] - 브러시 사용 여부
|
|
50
|
+
*/
|
|
39
51
|
/**
|
|
40
52
|
* Draw series data
|
|
41
|
-
* @param {
|
|
53
|
+
* @param {LineDrawParam} param object for drawing series data
|
|
42
54
|
*
|
|
43
55
|
* @returns {undefined}
|
|
44
56
|
*/
|
|
@@ -91,8 +103,6 @@ class Line {
|
|
|
91
103
|
|
|
92
104
|
const endPoint = chartRect.y2 - labelOffset.bottom;
|
|
93
105
|
|
|
94
|
-
let x;
|
|
95
|
-
let y;
|
|
96
106
|
let barAreaByCombo = 0;
|
|
97
107
|
|
|
98
108
|
const minmaxX = axesSteps.x[this.xAxisIndex];
|
|
@@ -114,51 +124,39 @@ class Line {
|
|
|
114
124
|
const getYPos = val => Canvas.calculateY(val, minmaxY.graphMin, minmaxY.graphMax, yArea, ysp);
|
|
115
125
|
|
|
116
126
|
// draw line
|
|
117
|
-
let
|
|
118
|
-
this.data.
|
|
119
|
-
x = getXPos(curr.x);
|
|
120
|
-
y = getYPos(curr.y);
|
|
127
|
+
let prevValid;
|
|
128
|
+
this.data.forEach((curr) => {
|
|
129
|
+
let x = getXPos(curr.x);
|
|
130
|
+
let y = getYPos(curr.y);
|
|
131
|
+
|
|
132
|
+
if (this.isExistGrp && this.usePassingValue && curr.o === this.passingValue) {
|
|
133
|
+
y = getYPos(curr.b ?? 0);
|
|
134
|
+
}
|
|
121
135
|
|
|
122
136
|
if (x !== null) {
|
|
123
137
|
x += Util.aliasPixel(x);
|
|
124
138
|
}
|
|
125
139
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
y = getYPos(prev.y);
|
|
140
|
+
curr.xp = x;
|
|
141
|
+
curr.yp = y;
|
|
129
142
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
if (this.isExistGrp && !needCutoff) {
|
|
135
|
-
y = getYPos(curr.b ?? 0);
|
|
136
|
-
ctx.lineTo(x, y);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
curr.xp = x;
|
|
140
|
-
curr.yp = y;
|
|
141
|
-
|
|
142
|
-
return curr;
|
|
143
|
+
if (this.usePassingValue && curr.o === this.passingValue) {
|
|
144
|
+
if (!this.isExistGrp) {
|
|
145
|
+
return;
|
|
143
146
|
}
|
|
144
147
|
}
|
|
145
148
|
|
|
146
|
-
|
|
147
|
-
||
|
|
148
|
-
||
|
|
149
|
-
||
|
|
150
|
-
if (isNullValue || needCutoff) {
|
|
149
|
+
if ((isNil(prevValid?.y) && this.usePassingValue && this.passingValue !== prevValid?.o)
|
|
150
|
+
|| (!this.usePassingValue && isNil(curr.o) && this.interpolation !== 'zero')
|
|
151
|
+
|| (!this.usePassingValue && isNil(prevValid?.y))
|
|
152
|
+
|| (isNil(curr.o) && curr.y == null && this.passingValue !== curr.o)) {
|
|
151
153
|
ctx.moveTo(x, y);
|
|
152
|
-
needCutoff = false;
|
|
153
154
|
} else {
|
|
154
155
|
ctx.lineTo(x, y);
|
|
155
156
|
}
|
|
156
157
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
return curr;
|
|
161
|
-
}, this.data[0]);
|
|
158
|
+
prevValid = curr;
|
|
159
|
+
});
|
|
162
160
|
|
|
163
161
|
ctx.stroke();
|
|
164
162
|
if (this.segments) {
|
|
@@ -195,19 +193,22 @@ class Line {
|
|
|
195
193
|
// ex) [10, passing, null, 10, 10, passing, 10] -> [[0, 1], [3, 6]]
|
|
196
194
|
let start = null;
|
|
197
195
|
let end = null;
|
|
198
|
-
const valueArray = this.data.map(item => item?.o);
|
|
196
|
+
const valueArray = this.data.map(item => (item?.o));
|
|
197
|
+
/** @type {Array<[number, number]>} */
|
|
199
198
|
const needFillDataIndexList = [];
|
|
200
199
|
for (let i = 0; i < valueArray.length + 1; i++) {
|
|
201
|
-
|
|
200
|
+
const isNoneInterpolation = this.interpolation === 'none' || (this.usePassingValue && this.passingValue !== null);
|
|
201
|
+
|
|
202
|
+
if (isNoneInterpolation ? isNil(valueArray[i]) : isUndefined(valueArray[i])) {
|
|
202
203
|
if (start !== null && end !== null) {
|
|
203
204
|
const temp = valueArray.slice(start, i);
|
|
204
205
|
const lastNormalValueIndex = temp.findLastIndex(
|
|
205
|
-
item =>
|
|
206
|
+
item => !isNil(item) && item !== this.passingValue);
|
|
206
207
|
needFillDataIndexList.push([start, start + lastNormalValueIndex]);
|
|
207
208
|
start = null;
|
|
208
209
|
end = null;
|
|
209
210
|
}
|
|
210
|
-
} else if (valueArray[i] === this.passingValue) {
|
|
211
|
+
} else if (this.usePassingValue && valueArray[i] === this.passingValue) {
|
|
211
212
|
end = i;
|
|
212
213
|
} else {
|
|
213
214
|
start = start === null ? i : start;
|
|
@@ -231,7 +232,7 @@ class Line {
|
|
|
231
232
|
|
|
232
233
|
if (ix === startIndex) {
|
|
233
234
|
ctx.moveTo(currData.xp, currData.yp);
|
|
234
|
-
} else if (this.isExistGrp || this.passingValue !== currData.o) {
|
|
235
|
+
} else if (this.isExistGrp || this.passingValue !== currData.o || (this.interpolation === 'zero' && isNil(currData.o))) {
|
|
235
236
|
ctx.lineTo(currData.xp, currData.yp);
|
|
236
237
|
}
|
|
237
238
|
|
|
@@ -3,13 +3,13 @@ import Util from './helpers.util';
|
|
|
3
3
|
export default {
|
|
4
4
|
/**
|
|
5
5
|
* Calculate X position
|
|
6
|
-
* @param {
|
|
6
|
+
* @param {number|null|undefined} value graph value
|
|
7
7
|
* @param {number} min min value
|
|
8
8
|
* @param {number} max max value
|
|
9
9
|
* @param {number} area height for axis
|
|
10
10
|
* @param {number} startPoint startPoint
|
|
11
11
|
*
|
|
12
|
-
* @returns {
|
|
12
|
+
* @returns {number|null} position
|
|
13
13
|
*/
|
|
14
14
|
calculateX(value, min, max, area, startPoint = 0) {
|
|
15
15
|
if (value === null || value === undefined) {
|
|
@@ -45,13 +45,13 @@ export default {
|
|
|
45
45
|
|
|
46
46
|
/**
|
|
47
47
|
* Calculate Y position
|
|
48
|
-
* @param {
|
|
48
|
+
* @param {number|null|undefined} value graph value
|
|
49
49
|
* @param {number} min min value
|
|
50
50
|
* @param {number} max max value
|
|
51
51
|
* @param {number} area height for axis
|
|
52
52
|
* @param {number} startPoint startPoint
|
|
53
53
|
*
|
|
54
|
-
* @returns {
|
|
54
|
+
* @returns {number|null} position
|
|
55
55
|
*/
|
|
56
56
|
calculateY(value, min, max, area, startPoint = 0) {
|
|
57
57
|
let calcY;
|
|
@@ -2,3 +2,49 @@ import Store from './model.store';
|
|
|
2
2
|
import Series from './model.series';
|
|
3
3
|
|
|
4
4
|
export default { Store, Series };
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @typedef {Object} ChartDOMSize
|
|
9
|
+
* @property {number} width - 차트 DOM의 너비
|
|
10
|
+
* @property {number} height - 차트 DOM의 높이
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @typedef {Object} ChartRect
|
|
15
|
+
* @property {number} x1 - 차트 영역의 시작 X 좌표
|
|
16
|
+
* @property {number} x2 - 차트 영역의 끝 X 좌표
|
|
17
|
+
* @property {number} y1 - 차트 영역의 시작 Y 좌표
|
|
18
|
+
* @property {number} y2 - 차트 영역의 끝 Y 좌표
|
|
19
|
+
* @property {number} chartWidth - 실제 차트 그리기 영역의 너비
|
|
20
|
+
* @property {number} chartHeight - 실제 차트 그리기 영역의 높이
|
|
21
|
+
* @property {number} width - 전체 차트 컨테이너의 너비
|
|
22
|
+
* @property {number} height - 전체 차트 컨테이너의 높이
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @typedef {Object} MouseLabelValue
|
|
28
|
+
* @property {string|number} labelVal - 마우스 위치에 해당하는 라벨 값
|
|
29
|
+
* @property {number} labelIdx - 라벨 인덱스 (없으면 -1)
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @typedef {Object} ChartSeriesDataPoint
|
|
35
|
+
* @property {number|null} x - x축 값 또는 라벨
|
|
36
|
+
* @property {number|null} y - y축 값 또는 데이터 값
|
|
37
|
+
* @property {number|null} o - 원본 데이터 값
|
|
38
|
+
* @property {number|null} b - 스택형 차트의 베이스 값
|
|
39
|
+
* @property {number|null} xp - x좌표 위치(픽셀 등)
|
|
40
|
+
* @property {number|null} yp - y좌표 위치(픽셀 등)
|
|
41
|
+
* @property {number|null} w - 너비
|
|
42
|
+
* @property {number|null} h - 높이
|
|
43
|
+
* @property {string|null} dataColor - 데이터 색상
|
|
44
|
+
* @property {string|null} dataTextColor - 텍스트 색상
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @typedef {'none' | 'linear' | 'zero'} InterpolationType
|
|
50
|
+
*/
|
|
@@ -50,9 +50,13 @@ const modules = {
|
|
|
50
50
|
|
|
51
51
|
if (series && sData) {
|
|
52
52
|
if (series.isExistGrp && series.stackIndex && !series.isOverlapping) {
|
|
53
|
-
series.data = this.addSeriesStackDS(
|
|
53
|
+
series.data = this.addSeriesStackDS(
|
|
54
|
+
sData, label, series.bsIds, series.stackIndex, series.interpolation,
|
|
55
|
+
);
|
|
54
56
|
} else {
|
|
55
|
-
series.data = this.addSeriesDS(
|
|
57
|
+
series.data = this.addSeriesDS(
|
|
58
|
+
sData, label, series.isExistGrp, series.interpolation,
|
|
59
|
+
);
|
|
56
60
|
}
|
|
57
61
|
series.minMax = this.getSeriesMinMax(series.data);
|
|
58
62
|
}
|
|
@@ -385,10 +389,13 @@ const modules = {
|
|
|
385
389
|
* @param {object} label chart label
|
|
386
390
|
* @param {array} bsIds stacked base data ID List
|
|
387
391
|
* @param {number} sIdx series ordered index
|
|
392
|
+
* @param {import('./index').InterpolationType} interpolation interpolation type
|
|
388
393
|
*
|
|
389
|
-
* @
|
|
394
|
+
* @typedef {import('./index').ChartSeriesDataPoint} ChartSeriesDataPoint
|
|
395
|
+
*
|
|
396
|
+
* @returns {ChartSeriesDataPoint[]} data for each series
|
|
390
397
|
*/
|
|
391
|
-
addSeriesStackDS(data, label, bsIds, sIdx = 0) {
|
|
398
|
+
addSeriesStackDS(data, label, bsIds, sIdx = 0, interpolation = 'none') {
|
|
392
399
|
const isHorizontal = this.options.horizontal;
|
|
393
400
|
const sdata = [];
|
|
394
401
|
|
|
@@ -429,15 +436,14 @@ const modules = {
|
|
|
429
436
|
if (oData != null) {
|
|
430
437
|
gdata = bdata + oData;
|
|
431
438
|
} else {
|
|
432
|
-
gdata =
|
|
433
|
-
bdata = 0;
|
|
439
|
+
gdata = odata;
|
|
434
440
|
}
|
|
435
441
|
} else {
|
|
436
442
|
bdata = 0;
|
|
437
443
|
gdata = oData;
|
|
438
444
|
}
|
|
439
445
|
|
|
440
|
-
sdata.push(this.addData(gdata, ldata, odata, bdata));
|
|
446
|
+
sdata.push(this.addData(gdata, ldata, odata, bdata, interpolation));
|
|
441
447
|
}
|
|
442
448
|
});
|
|
443
449
|
|
|
@@ -449,10 +455,13 @@ const modules = {
|
|
|
449
455
|
* @param {object} data chart series info
|
|
450
456
|
* @param {object} label chart label
|
|
451
457
|
* @param {boolean} isBase is Base(bottommost) series at stack chart
|
|
458
|
+
* @param {import('./index').InterpolationType} interpolation interpolation type
|
|
459
|
+
*
|
|
460
|
+
* @typedef {import('./index').ChartSeriesDataPoint} ChartSeriesDataPoint
|
|
452
461
|
*
|
|
453
|
-
* @returns {
|
|
462
|
+
* @returns {ChartSeriesDataPoint[]} data for each series
|
|
454
463
|
*/
|
|
455
|
-
addSeriesDS(data, label, isBase) {
|
|
464
|
+
addSeriesDS(data, label, isBase, interpolation = 'none') {
|
|
456
465
|
const isHorizontal = this.options.horizontal;
|
|
457
466
|
const sdata = [];
|
|
458
467
|
const passingValue = this.seriesList[Object.keys(this.seriesList)[0]]?.passingValue;
|
|
@@ -470,7 +479,13 @@ const modules = {
|
|
|
470
479
|
const isPassingValueWithStack = isBase
|
|
471
480
|
&& !Util.isNullOrUndefined(passingValue)
|
|
472
481
|
&& gdata === passingValue;
|
|
473
|
-
sdata.push(this.addData(
|
|
482
|
+
sdata.push(this.addData(
|
|
483
|
+
isPassingValueWithStack ? 0 : gdata,
|
|
484
|
+
ldata,
|
|
485
|
+
gdata,
|
|
486
|
+
null,
|
|
487
|
+
interpolation,
|
|
488
|
+
));
|
|
474
489
|
}
|
|
475
490
|
});
|
|
476
491
|
|
|
@@ -520,10 +535,13 @@ const modules = {
|
|
|
520
535
|
* @param {object} ldata label data (x-axis value for vertical chart)
|
|
521
536
|
* @param {object} odata original data (without stacked value)
|
|
522
537
|
* @param {object} bdata base data (stacked value)
|
|
523
|
-
|
|
524
|
-
*
|
|
538
|
+
* @param {import('./index').InterpolationType} interpolation interpolation type
|
|
539
|
+
*
|
|
540
|
+
* @typedef {import('./index').ChartSeriesDataPoint} ChartSeriesDataPoint
|
|
541
|
+
*
|
|
542
|
+
* @returns {ChartSeriesDataPoint} data for each graph point
|
|
525
543
|
*/
|
|
526
|
-
addData(gdata, ldata, odata = null, bdata = null) {
|
|
544
|
+
addData(gdata, ldata, odata = null, bdata = null, interpolation = 'none') {
|
|
527
545
|
let data;
|
|
528
546
|
let gdataValue = null;
|
|
529
547
|
let odataValue = null;
|
|
@@ -536,7 +554,7 @@ const modules = {
|
|
|
536
554
|
gdataColor = gdata.color;
|
|
537
555
|
dataTextColor = gdata.textColor;
|
|
538
556
|
} else {
|
|
539
|
-
gdataValue = gdata ?? null;
|
|
557
|
+
gdataValue = interpolation === 'zero' && !gdata ? bdata ?? 0 : gdata ?? null;
|
|
540
558
|
}
|
|
541
559
|
|
|
542
560
|
if (odata !== null && typeof odata === 'object') {
|
|
@@ -1008,12 +1026,17 @@ const modules = {
|
|
|
1008
1026
|
|
|
1009
1027
|
return result;
|
|
1010
1028
|
},
|
|
1029
|
+
/**
|
|
1030
|
+
* @typedef {Object} LabelInfoResult
|
|
1031
|
+
* @property {number} labelIndex - 선택된 라벨의 인덱스
|
|
1032
|
+
* @property {object} hitInfo - 해당 위치에서의 히트 정보 (getItemByPosition 반환값)
|
|
1033
|
+
*/
|
|
1011
1034
|
/**
|
|
1012
1035
|
* Find label info by position x and y
|
|
1013
1036
|
* @param {array} offset position x and y
|
|
1014
1037
|
* @param {string | null} targetAxis target Axis Location ('xAxis', 'yAxis' , null)
|
|
1015
1038
|
*
|
|
1016
|
-
* @returns {
|
|
1039
|
+
* @returns {LabelInfoResult} clicked label information
|
|
1017
1040
|
*/
|
|
1018
1041
|
getLabelInfoByPosition(offset, targetAxis) {
|
|
1019
1042
|
const [x, y] = offset;
|
|
@@ -1097,11 +1120,14 @@ const modules = {
|
|
|
1097
1120
|
|
|
1098
1121
|
/**
|
|
1099
1122
|
* Get current mouse target label value in label array or calculated using mouse position
|
|
1123
|
+
*
|
|
1124
|
+
* @typedef {import('./index').MouseLabelValue} MouseLabelValue
|
|
1125
|
+
*
|
|
1100
1126
|
* @param {string} targetAxis target Axis Location ('xAxis', 'yAxis')
|
|
1101
1127
|
* @param {array} offset return value from getMousePosition()
|
|
1102
1128
|
* @param {number} labelIndex
|
|
1103
1129
|
*
|
|
1104
|
-
* @returns {
|
|
1130
|
+
* @returns {MouseLabelValue} current mouse target label value
|
|
1105
1131
|
*/
|
|
1106
1132
|
getCurMouseLabelVal(targetAxis, offset, labelIndex) {
|
|
1107
1133
|
const { type: chartType, horizontal } = this.options;
|