@easyv/charts 1.8.23 → 1.8.25
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/lib/components/Axis.js +8 -5
- package/lib/components/Band.js +7 -3
- package/lib/components/CartesianChart.js +24 -6
- package/lib/components/Chart.js +17 -7
- package/lib/components/Label.js +11 -3
- package/lib/components/Legend.js +68 -62
- package/lib/components/PieChart.js +2 -0
- package/lib/components/pieTooltip.js +19 -21
- package/package.json +1 -1
- package/src/components/Axis.tsx +72 -63
- package/src/components/Band.tsx +153 -113
- package/src/components/CartesianChart.js +287 -211
- package/src/components/Chart.js +94 -60
- package/src/components/Label.js +85 -39
- package/src/components/Legend.js +222 -135
- package/src/components/PieChart.js +2 -0
- package/src/components/PieTooltip.jsx +279 -198
package/src/components/Chart.js
CHANGED
|
@@ -1,18 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 总入口,通过外面传进来的type来确定渲染哪种图表,饼环图表为“pie”,否则为轴类图表
|
|
3
3
|
*/
|
|
4
|
-
import React, {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
import React, {
|
|
5
|
+
memo,
|
|
6
|
+
useMemo,
|
|
7
|
+
useRef,
|
|
8
|
+
createRef,
|
|
9
|
+
useState,
|
|
10
|
+
useEffect,
|
|
11
|
+
useCallback,
|
|
12
|
+
} from "react";
|
|
13
|
+
import { chartContext } from "../context";
|
|
14
|
+
import { PieChart, CartesianChart } from ".";
|
|
15
|
+
import { group } from "d3v7";
|
|
8
16
|
|
|
9
|
-
const getCallbackData = (action,callbacks, data) => {
|
|
10
|
-
const callbackData={};
|
|
17
|
+
const getCallbackData = (action, callbacks, data) => {
|
|
18
|
+
const callbackData = {};
|
|
11
19
|
if (callbacks && Array.isArray(callbacks) && callbacks.length && data) {
|
|
12
|
-
callbacks.forEach(({ origin, target, actions:_action }) => {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
20
|
+
callbacks.forEach(({ origin, target, actions: _action }) => {
|
|
21
|
+
if (action === _action) {
|
|
22
|
+
callbackData[target] = origin ? data[origin] : data;
|
|
23
|
+
}
|
|
16
24
|
});
|
|
17
25
|
}
|
|
18
26
|
return callbackData;
|
|
@@ -30,7 +38,7 @@ const Chart = memo(
|
|
|
30
38
|
},
|
|
31
39
|
interaction,
|
|
32
40
|
},
|
|
33
|
-
data:originData,
|
|
41
|
+
data: originData,
|
|
34
42
|
onRelative,
|
|
35
43
|
emit,
|
|
36
44
|
emitEvent,
|
|
@@ -46,13 +54,14 @@ const Chart = memo(
|
|
|
46
54
|
const chartWidth = width - marginLeft - marginRight;
|
|
47
55
|
const chartHeight = height - marginTop - marginBottom;
|
|
48
56
|
const [active, setActive] = useState(true);
|
|
49
|
-
const scaleRef = useRef([1,1]);
|
|
57
|
+
const scaleRef = useRef([1, 1]);
|
|
58
|
+
const screenPosRef = useRef({ left: 0, top: 0 });
|
|
50
59
|
const triggerOnRelative = useCallback(
|
|
51
|
-
(action,data) => {
|
|
60
|
+
(action, data) => {
|
|
52
61
|
if (!interaction) return;
|
|
53
62
|
const { callbacks, remoteControls } = interaction;
|
|
54
63
|
const callbackData = getCallbackData(action, callbacks, data);
|
|
55
|
-
if (
|
|
64
|
+
if (Object.keys(callbackData).length > 0) {
|
|
56
65
|
onRelative && onRelative(id, callbackData);
|
|
57
66
|
remoteControls &&
|
|
58
67
|
emitEvent &&
|
|
@@ -61,30 +70,31 @@ const Chart = memo(
|
|
|
61
70
|
if (
|
|
62
71
|
control.screen &&
|
|
63
72
|
control.type &&
|
|
64
|
-
control.type ===
|
|
73
|
+
control.type === "callback"
|
|
65
74
|
) {
|
|
66
75
|
emitEvent({
|
|
67
76
|
screen: control.screen,
|
|
68
|
-
type:
|
|
77
|
+
type: "callback",
|
|
69
78
|
callbackData,
|
|
70
79
|
});
|
|
71
80
|
}
|
|
72
81
|
});
|
|
73
82
|
}
|
|
74
83
|
},
|
|
75
|
-
[
|
|
84
|
+
[JSON.stringify(interaction)]
|
|
76
85
|
);
|
|
77
86
|
|
|
78
87
|
const onEmit = useCallback(
|
|
79
|
-
(type =
|
|
88
|
+
(type = "click", data) => emit && emit(type, data),
|
|
80
89
|
[emit]
|
|
81
90
|
);
|
|
82
91
|
|
|
83
92
|
const context = useMemo(
|
|
84
93
|
() => ({
|
|
85
94
|
id,
|
|
86
|
-
isIOS:isIOS.current,
|
|
87
|
-
scale:scaleRef, //大屏的缩放比
|
|
95
|
+
isIOS: isIOS.current, //是否为IOS设备
|
|
96
|
+
scale: scaleRef, //大屏的缩放比
|
|
97
|
+
screenPos: screenPosRef, //大屏的偏移位置
|
|
88
98
|
width: chartWidth,
|
|
89
99
|
height: chartHeight,
|
|
90
100
|
triggerOnRelative,
|
|
@@ -93,62 +103,86 @@ const Chart = memo(
|
|
|
93
103
|
}),
|
|
94
104
|
[id, chartWidth, chartHeight, triggerOnRelative, svg, onEmit]
|
|
95
105
|
);
|
|
96
|
-
|
|
97
|
-
useEffect(()=>{
|
|
98
|
-
let isAnimation = window.screenConfig
|
|
99
|
-
|
|
100
|
-
|
|
106
|
+
|
|
107
|
+
useEffect(() => {
|
|
108
|
+
let isAnimation = window.screenConfig
|
|
109
|
+
? window.screenConfig.isAnimation
|
|
110
|
+
: true; //大屏的全局设置是否允许开启动画,false为不允许
|
|
111
|
+
if (!isAnimation) setActive(false);
|
|
112
|
+
const activeHandler = (e) => {
|
|
101
113
|
const { dynamicData = true } = e;
|
|
102
114
|
isAnimation && setActive(dynamicData);
|
|
103
|
-
}
|
|
115
|
+
};
|
|
104
116
|
getScreenScale();
|
|
105
|
-
document.addEventListener(`switchActive_${id}`,activeHandler);
|
|
106
|
-
document.addEventListener("resize",getScreenScale);
|
|
107
|
-
return ()=>{
|
|
108
|
-
document.removeEventListener(`switchActive_${id}`,activeHandler);
|
|
109
|
-
document.removeEventListener("resize",getScreenScale);
|
|
110
|
-
}
|
|
111
|
-
},[]);
|
|
112
|
-
|
|
117
|
+
document.addEventListener(`switchActive_${id}`, activeHandler);
|
|
118
|
+
document.addEventListener("resize", getScreenScale);
|
|
119
|
+
return () => {
|
|
120
|
+
document.removeEventListener(`switchActive_${id}`, activeHandler);
|
|
121
|
+
document.removeEventListener("resize", getScreenScale);
|
|
122
|
+
};
|
|
123
|
+
}, []);
|
|
124
|
+
|
|
113
125
|
let data = checkData(originData);
|
|
114
|
-
|
|
126
|
+
|
|
115
127
|
return (
|
|
116
128
|
<chartContext.Provider value={context}>
|
|
117
|
-
{type ==
|
|
118
|
-
<PieChart
|
|
129
|
+
{type == "pie" ? (
|
|
130
|
+
<PieChart
|
|
131
|
+
id={id}
|
|
132
|
+
config={config}
|
|
133
|
+
data={data}
|
|
134
|
+
active={active}
|
|
135
|
+
{...props}
|
|
136
|
+
/>
|
|
119
137
|
) : (
|
|
120
|
-
<CartesianChart
|
|
121
|
-
|
|
138
|
+
<CartesianChart
|
|
139
|
+
id={id}
|
|
140
|
+
config={config}
|
|
141
|
+
data={data}
|
|
142
|
+
active={active}
|
|
143
|
+
{...props}
|
|
144
|
+
/>
|
|
145
|
+
)}
|
|
122
146
|
</chartContext.Provider>
|
|
123
|
-
|
|
124
147
|
);
|
|
125
148
|
//获取大屏缩放系数
|
|
126
|
-
function getScreenScale(){
|
|
127
|
-
setTimeout(()=>{
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
149
|
+
function getScreenScale() {
|
|
150
|
+
setTimeout(() => {
|
|
151
|
+
//获取大屏缩放系数
|
|
152
|
+
let dom =
|
|
153
|
+
document.getElementById("bigscreen-container") ||
|
|
154
|
+
document.getElementById("m-simulator");
|
|
155
|
+
if (dom) {
|
|
156
|
+
const transform = dom.style.transform;
|
|
157
|
+
const scale = transform
|
|
158
|
+
? transform.match(/^scale\((.+)\)$/)[1]
|
|
159
|
+
: "1,1";
|
|
160
|
+
const arr = scale.split(",");
|
|
161
|
+
scaleRef.current = [
|
|
162
|
+
1 / arr[0],
|
|
163
|
+
1 / (arr.length === 1 ? arr[0] : arr[1]),
|
|
164
|
+
]; //这里做一次除法,后面就可以用乘法计算值了
|
|
165
|
+
screenPosRef.current = {
|
|
166
|
+
left: parseFloat(dom.style.left),
|
|
167
|
+
top: parseFloat(dom.style.top),
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
}, 100);
|
|
137
171
|
}
|
|
138
172
|
//预检数据格式是否规范
|
|
139
|
-
function checkData(data){
|
|
140
|
-
try{
|
|
141
|
-
const hasS = data.some(d=>d.s);
|
|
142
|
-
if(!hasS){
|
|
143
|
-
return data.map(d=>{
|
|
173
|
+
function checkData(data) {
|
|
174
|
+
try {
|
|
175
|
+
const hasS = data.some((d) => d.s);
|
|
176
|
+
if (!hasS) {
|
|
177
|
+
return data.map((d) => {
|
|
144
178
|
return {
|
|
145
179
|
...d,
|
|
146
|
-
s:"系列一"
|
|
147
|
-
}
|
|
148
|
-
})
|
|
180
|
+
s: "系列一",
|
|
181
|
+
};
|
|
182
|
+
});
|
|
149
183
|
}
|
|
150
184
|
return data;
|
|
151
|
-
}catch(e){}
|
|
185
|
+
} catch (e) {}
|
|
152
186
|
return [];
|
|
153
187
|
}
|
|
154
188
|
}
|
package/src/components/Label.js
CHANGED
|
@@ -3,7 +3,12 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { memo, useContext } from "react";
|
|
5
5
|
import { min, max } from "d3v7";
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
getTranslate2d,
|
|
8
|
+
getSeriesInfo,
|
|
9
|
+
getFontStyle,
|
|
10
|
+
formatFont,
|
|
11
|
+
} from "../utils";
|
|
7
12
|
import { chartContext } from "../context";
|
|
8
13
|
|
|
9
14
|
const getHighlightData = (data, extent) => {
|
|
@@ -31,8 +36,8 @@ export default memo(
|
|
|
31
36
|
config: {
|
|
32
37
|
seriesIntervalWidth: paddingInner = 0,
|
|
33
38
|
paddingInner: paddingOuter = 0,
|
|
34
|
-
showType:seriesType =
|
|
35
|
-
highlight: { show: showHighlight, extent, ...highlightStyle }={}
|
|
39
|
+
showType: seriesType = "bar",
|
|
40
|
+
highlight: { show: showHighlight, extent, ...highlightStyle } = {}, //配置项不存在的处理
|
|
36
41
|
...other
|
|
37
42
|
},
|
|
38
43
|
config,
|
|
@@ -42,25 +47,25 @@ export default memo(
|
|
|
42
47
|
data,
|
|
43
48
|
xAxis: { scaler: xScaler, step, direction },
|
|
44
49
|
yAxis: { scaler: yScaler, isClipAxis, clipValue },
|
|
45
|
-
|
|
50
|
+
triggerEvents,
|
|
46
51
|
}) => {
|
|
47
52
|
let selectConfig = other;
|
|
48
|
-
if(selectStyle){
|
|
49
|
-
const { show, showType, icon, numlabel:label } = selectStyle;
|
|
50
|
-
if(show && seriesType==showType){
|
|
51
|
-
if(showType=="bar"){
|
|
53
|
+
if (selectStyle) {
|
|
54
|
+
const { show, showType, icon, numlabel: label } = selectStyle;
|
|
55
|
+
if (show && seriesType == showType) {
|
|
56
|
+
if (showType == "bar") {
|
|
52
57
|
selectConfig = { label };
|
|
53
|
-
}else{
|
|
58
|
+
} else {
|
|
54
59
|
selectConfig = { icon, label };
|
|
55
60
|
}
|
|
56
61
|
}
|
|
57
62
|
}
|
|
58
63
|
let highlightConfig = other;
|
|
59
|
-
if(highlightStyle){
|
|
60
|
-
highlightConfig = { ...other, label:highlightStyle.numlabel };
|
|
64
|
+
if (highlightStyle) {
|
|
65
|
+
highlightConfig = { ...other, label: highlightStyle.numlabel };
|
|
61
66
|
}
|
|
62
67
|
const lineType = config.hasOwnProperty("line"); // 堆叠处理
|
|
63
|
-
|
|
68
|
+
|
|
64
69
|
if (!data.length) return null;
|
|
65
70
|
const { width, height } = useContext(chartContext);
|
|
66
71
|
|
|
@@ -72,19 +77,27 @@ export default memo(
|
|
|
72
77
|
});
|
|
73
78
|
const _data = showHighlight ? getHighlightData(data, extent) : data;
|
|
74
79
|
const isVertical = direction === "vertical";
|
|
75
|
-
|
|
80
|
+
|
|
76
81
|
return (
|
|
77
82
|
<g className="__easyv-label">
|
|
78
83
|
{_data.map(
|
|
79
84
|
(
|
|
80
|
-
{
|
|
85
|
+
{
|
|
86
|
+
flag,
|
|
87
|
+
index,
|
|
88
|
+
bound: [start, end],
|
|
89
|
+
data,
|
|
90
|
+
data: { x, y, showY, s },
|
|
91
|
+
},
|
|
81
92
|
i
|
|
82
93
|
) => {
|
|
83
94
|
let y1, y2;
|
|
84
|
-
const { icon, label } =
|
|
95
|
+
const { icon, label } =
|
|
96
|
+
x == curXLabel ? selectConfig : flag ? highlightConfig : other;
|
|
85
97
|
const showIcon = icon && icon.show;
|
|
86
98
|
const showLabel = label && label.show;
|
|
87
|
-
const { position:_position="outerStart", reverse=true } =
|
|
99
|
+
const { position: _position = "outerStart", reverse = true } =
|
|
100
|
+
label || {};
|
|
88
101
|
if (isClipAxis) {
|
|
89
102
|
if (end > +clipValue) {
|
|
90
103
|
y1 = yScaler[1](start);
|
|
@@ -108,7 +121,9 @@ export default memo(
|
|
|
108
121
|
xScaler(x) - step / 2 + seriesStart + index * seriesStep;
|
|
109
122
|
|
|
110
123
|
if (isNaN(positionX)) return null;
|
|
111
|
-
const position =isXRepeat
|
|
124
|
+
const position = isXRepeat
|
|
125
|
+
? positionX + (config.line ? step : seriesWidth) / 2
|
|
126
|
+
: xScaler(x);
|
|
112
127
|
const labelPosition = isVertical
|
|
113
128
|
? getVerticalLabel({
|
|
114
129
|
position: _position,
|
|
@@ -116,7 +131,7 @@ export default memo(
|
|
|
116
131
|
y1,
|
|
117
132
|
y2,
|
|
118
133
|
width,
|
|
119
|
-
reverse
|
|
134
|
+
reverse,
|
|
120
135
|
})
|
|
121
136
|
: getHorizontalLabel({
|
|
122
137
|
position: _position,
|
|
@@ -124,7 +139,7 @@ export default memo(
|
|
|
124
139
|
y1,
|
|
125
140
|
y2,
|
|
126
141
|
height,
|
|
127
|
-
reverse
|
|
142
|
+
reverse,
|
|
128
143
|
});
|
|
129
144
|
const attr = isVertical
|
|
130
145
|
? {
|
|
@@ -140,14 +155,23 @@ export default memo(
|
|
|
140
155
|
return (
|
|
141
156
|
<g
|
|
142
157
|
key={i}
|
|
143
|
-
onClick={e=>
|
|
158
|
+
onClick={(e) => triggerEvents(e, "setCurrent")}
|
|
159
|
+
onMouseMove={(e) => triggerEvents(e, "mouseenter")}
|
|
160
|
+
onMouseLeave={(e) => triggerEvents(e, "mouseleave")}
|
|
144
161
|
style={{ cursor: "pointer" }}
|
|
145
162
|
data-data={JSON.stringify(data)}
|
|
146
163
|
>
|
|
147
164
|
{showIcon && !isNaN(attr.y) && (
|
|
148
165
|
<Icon cx={attr.x} cy={y2} config={icon} />
|
|
149
166
|
)}
|
|
150
|
-
{showLabel &&
|
|
167
|
+
{showLabel && (
|
|
168
|
+
<Label
|
|
169
|
+
value={showY}
|
|
170
|
+
config={label}
|
|
171
|
+
reverse={reverse}
|
|
172
|
+
{...attr}
|
|
173
|
+
/>
|
|
174
|
+
)}
|
|
151
175
|
</g>
|
|
152
176
|
);
|
|
153
177
|
}
|
|
@@ -164,13 +188,15 @@ const Label = ({
|
|
|
164
188
|
config: {
|
|
165
189
|
font,
|
|
166
190
|
translate: { x: translateX = 0, y: translateY = 0 },
|
|
167
|
-
suffix:{
|
|
168
|
-
content,
|
|
169
|
-
|
|
191
|
+
suffix: {
|
|
192
|
+
content,
|
|
193
|
+
font: suffixFont,
|
|
194
|
+
translate: { x: suffixX, y: suffixY },
|
|
195
|
+
},
|
|
170
196
|
},
|
|
171
197
|
textAnchor = "middle",
|
|
172
198
|
dominantBaseline = "middle",
|
|
173
|
-
reverse
|
|
199
|
+
reverse,
|
|
174
200
|
}) => {
|
|
175
201
|
return (
|
|
176
202
|
<text
|
|
@@ -182,12 +208,18 @@ const Label = ({
|
|
|
182
208
|
})}
|
|
183
209
|
textAnchor={textAnchor}
|
|
184
210
|
dominantBaseline={dominantBaseline}
|
|
185
|
-
style={{...formatFont(font,"svg")}}
|
|
211
|
+
style={{ ...formatFont(font, "svg") }}
|
|
186
212
|
>
|
|
187
213
|
<tspan>{value}</tspan>
|
|
188
|
-
<tspan
|
|
189
|
-
|
|
190
|
-
|
|
214
|
+
<tspan
|
|
215
|
+
dx={suffixX}
|
|
216
|
+
dy={suffixY}
|
|
217
|
+
style={{
|
|
218
|
+
...getFontStyle(suffixFont, "svg"),
|
|
219
|
+
}}
|
|
220
|
+
>
|
|
221
|
+
{content}
|
|
222
|
+
</tspan>
|
|
191
223
|
</text>
|
|
192
224
|
);
|
|
193
225
|
};
|
|
@@ -227,13 +259,20 @@ const Circle = ({ cx, cy, color, radius }) => (
|
|
|
227
259
|
<circle cx={cx} cy={cy} fill={color} r={radius} stroke="none" />
|
|
228
260
|
);
|
|
229
261
|
|
|
230
|
-
const getVerticalLabel = ({
|
|
231
|
-
|
|
262
|
+
const getVerticalLabel = ({
|
|
263
|
+
position = "outerStart",
|
|
264
|
+
width,
|
|
265
|
+
y,
|
|
266
|
+
y1,
|
|
267
|
+
y2,
|
|
268
|
+
reverse = true,
|
|
269
|
+
}) => {
|
|
270
|
+
const needReverse = reverse && y < 0;
|
|
232
271
|
switch (position) {
|
|
233
272
|
case "start":
|
|
234
273
|
return {
|
|
235
274
|
x: y2,
|
|
236
|
-
textAnchor: needReverse?"end":"start",
|
|
275
|
+
textAnchor: needReverse ? "end" : "start",
|
|
237
276
|
};
|
|
238
277
|
case "middle":
|
|
239
278
|
return {
|
|
@@ -243,12 +282,12 @@ const getVerticalLabel = ({ position = "outerStart", width, y, y1, y2, reverse =
|
|
|
243
282
|
case "end":
|
|
244
283
|
return {
|
|
245
284
|
x: y1,
|
|
246
|
-
textAnchor: needReverse?"start":"end",
|
|
285
|
+
textAnchor: needReverse ? "start" : "end",
|
|
247
286
|
};
|
|
248
287
|
case "outerStart":
|
|
249
288
|
return {
|
|
250
289
|
x: y1,
|
|
251
|
-
textAnchor: needReverse?"end":"start",
|
|
290
|
+
textAnchor: needReverse ? "end" : "start",
|
|
252
291
|
};
|
|
253
292
|
case "chartStart":
|
|
254
293
|
return {
|
|
@@ -257,13 +296,20 @@ const getVerticalLabel = ({ position = "outerStart", width, y, y1, y2, reverse =
|
|
|
257
296
|
};
|
|
258
297
|
}
|
|
259
298
|
};
|
|
260
|
-
const getHorizontalLabel = ({
|
|
261
|
-
|
|
299
|
+
const getHorizontalLabel = ({
|
|
300
|
+
position = "outerStart",
|
|
301
|
+
height,
|
|
302
|
+
y,
|
|
303
|
+
y1,
|
|
304
|
+
y2,
|
|
305
|
+
reverse = true,
|
|
306
|
+
}) => {
|
|
307
|
+
const needReverse = reverse && y < 0;
|
|
262
308
|
switch (position) {
|
|
263
309
|
case "start":
|
|
264
310
|
return {
|
|
265
311
|
y: y1,
|
|
266
|
-
dominantBaseline: needReverse?"text-before-edge":"text-after-edge",
|
|
312
|
+
dominantBaseline: needReverse ? "text-before-edge" : "text-after-edge",
|
|
267
313
|
};
|
|
268
314
|
case "middle":
|
|
269
315
|
return {
|
|
@@ -273,12 +319,12 @@ const getHorizontalLabel = ({ position = "outerStart", height, y, y1, y2, revers
|
|
|
273
319
|
case "end":
|
|
274
320
|
return {
|
|
275
321
|
y: y2,
|
|
276
|
-
dominantBaseline: needReverse?"text-after-edge":"text-before-edge",
|
|
322
|
+
dominantBaseline: needReverse ? "text-after-edge" : "text-before-edge",
|
|
277
323
|
};
|
|
278
324
|
case "outerStart":
|
|
279
325
|
return {
|
|
280
326
|
y: y2,
|
|
281
|
-
dominantBaseline: needReverse?"text-before-edge":"text-after-edge",
|
|
327
|
+
dominantBaseline: needReverse ? "text-before-edge" : "text-after-edge",
|
|
282
328
|
};
|
|
283
329
|
case "chartStart":
|
|
284
330
|
return {
|