@easyv/charts 1.4.35 → 1.4.36
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 +7 -7
- package/lib/components/Band.js +28 -26
- package/lib/components/CartesianChart.js +208 -175
- package/lib/components/Control.js +78 -30
- package/lib/components/Indicator.js +30 -34
- package/lib/components/Label.js +1 -41
- package/lib/hooks/useAxes.js +43 -12
- package/lib/hooks/useCarouselAxisX.js +15 -16
- package/package.json +1 -1
- package/src/components/Axis.tsx +6 -7
- package/src/components/Band.tsx +27 -34
- package/src/components/CartesianChart.js +186 -196
- package/src/components/Control.jsx +87 -43
- package/src/components/Indicator.js +17 -20
- package/src/components/Label.js +1 -34
- package/src/components/Tooltip.js +0 -1
- package/src/hooks/useAxes.js +34 -16
- package/src/hooks/useCarouselAxisX.js +14 -18
|
@@ -8,10 +8,9 @@ import React, {
|
|
|
8
8
|
useRef,
|
|
9
9
|
useContext,
|
|
10
10
|
useCallback,
|
|
11
|
-
useEffect
|
|
12
|
-
forwardRef,
|
|
11
|
+
useEffect
|
|
13
12
|
} from "react";
|
|
14
|
-
import { useAxes, useTooltip, useCarouselAxisX,useAiData } from "../hooks";
|
|
13
|
+
import { useAxes, useTooltip, useCarouselAxisX, useAiData } from "../hooks";
|
|
15
14
|
import { chartContext } from "../context";
|
|
16
15
|
import {
|
|
17
16
|
ChartContainer,
|
|
@@ -30,7 +29,6 @@ import {
|
|
|
30
29
|
BaseLine,
|
|
31
30
|
Control,
|
|
32
31
|
} from ".";
|
|
33
|
-
import { getMousePos } from "../utils";
|
|
34
32
|
|
|
35
33
|
const Chart = memo(
|
|
36
34
|
({
|
|
@@ -58,7 +56,6 @@ const Chart = memo(
|
|
|
58
56
|
config: { auto, manual, indicator = {} } = {},
|
|
59
57
|
} = {},
|
|
60
58
|
brush,
|
|
61
|
-
isControlChart = false,
|
|
62
59
|
control = null,
|
|
63
60
|
},
|
|
64
61
|
style,
|
|
@@ -74,25 +71,49 @@ const Chart = memo(
|
|
|
74
71
|
height: chartHeight,
|
|
75
72
|
triggerOnRelative,
|
|
76
73
|
onEmit,
|
|
77
|
-
} =
|
|
74
|
+
} = context;
|
|
75
|
+
const xLineRange = chartWidth;
|
|
76
|
+
let yLineRange = chartHeight;
|
|
77
|
+
//获取控制条相关的参数
|
|
78
|
+
let isControl = false;
|
|
79
|
+
let controlWidth = 0;
|
|
80
|
+
let controlBarWidth = 0;
|
|
81
|
+
let dragPercent = 1;
|
|
82
|
+
let controlHeight = 0;
|
|
83
|
+
if(control){
|
|
84
|
+
const { height, margin:{ left, right }, drag:{ width:dragWidth } } = control;
|
|
85
|
+
isControl = true;
|
|
86
|
+
controlHeight = height;
|
|
87
|
+
controlWidth = width-left-right;
|
|
88
|
+
dragPercent = dragWidth/100;
|
|
89
|
+
controlBarWidth = controlWidth*dragPercent;
|
|
90
|
+
}
|
|
91
|
+
const [controlInfo, setControlInfo] = useState({ isC:isControl, cWidth:controlWidth, cHeight:controlHeight, cBarWidth:controlBarWidth, cPercent:dragPercent });
|
|
92
|
+
const { cWidth, cHeight, cBarWidth, cPercent } = controlInfo;
|
|
93
|
+
yLineRange -= cHeight;
|
|
94
|
+
useEffect(()=>{
|
|
95
|
+
setControlInfo({
|
|
96
|
+
isC:isControl,
|
|
97
|
+
cWidth:controlWidth,
|
|
98
|
+
cHeight:controlHeight,
|
|
99
|
+
cBarWidth:controlBarWidth,
|
|
100
|
+
cPercent:dragPercent
|
|
101
|
+
});
|
|
102
|
+
},[JSON.stringify(control)]);
|
|
103
|
+
|
|
78
104
|
const svg = useRef();
|
|
79
105
|
const axes = useAxes({
|
|
80
106
|
axes: axesConfig,
|
|
81
107
|
context,
|
|
82
|
-
|
|
83
|
-
control,
|
|
108
|
+
controlInfo
|
|
84
109
|
});
|
|
85
110
|
const aiData = aiFormatter?aiFormatter(originData, axes, series):useAiData(originData, axes, series);
|
|
86
111
|
const axisX = useCarouselAxisX(
|
|
87
112
|
axes.get("x"),
|
|
88
113
|
animation,
|
|
89
114
|
isHover,
|
|
90
|
-
|
|
91
|
-
control
|
|
115
|
+
controlInfo
|
|
92
116
|
);
|
|
93
|
-
const xLineRange = width - marginLeft - marginRight;
|
|
94
|
-
const yLineRange = height - marginTop - marginBottom;
|
|
95
|
-
|
|
96
117
|
useEffect(()=>{
|
|
97
118
|
if(aiData.length){
|
|
98
119
|
if(!window.aiData){
|
|
@@ -118,7 +139,7 @@ const Chart = memo(
|
|
|
118
139
|
marginLeft,
|
|
119
140
|
marginTop,
|
|
120
141
|
width: chartWidth,
|
|
121
|
-
height:
|
|
142
|
+
height: yLineRange,
|
|
122
143
|
axisX,
|
|
123
144
|
isHover,
|
|
124
145
|
config: tooltipConfig,
|
|
@@ -137,12 +158,12 @@ const Chart = memo(
|
|
|
137
158
|
|
|
138
159
|
const isVertical = axisX.direction === "vertical";
|
|
139
160
|
|
|
140
|
-
const indicatorWidth = (indicator.width * axisX.step) / 100;
|
|
161
|
+
const indicatorWidth = (indicator.width * (control?axisX.controlStep:axisX.step)) / 100;
|
|
141
162
|
const position = axisX.scaler(tickName) - indicatorWidth / 2;
|
|
142
163
|
const indicatorAttr = isVertical
|
|
143
164
|
? { width: chartWidth, height: indicatorWidth, y: position }
|
|
144
165
|
: {
|
|
145
|
-
height:
|
|
166
|
+
height: yLineRange,
|
|
146
167
|
width: indicatorWidth,
|
|
147
168
|
x: position,
|
|
148
169
|
};
|
|
@@ -165,148 +186,130 @@ const Chart = memo(
|
|
|
165
186
|
const seriesEl = useRef(null);
|
|
166
187
|
const axisElList = useRef([]);
|
|
167
188
|
const curControlPercent = useRef(0);
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
let movementX = 0;
|
|
172
|
-
let rawTranslateX = 0;
|
|
173
|
-
let percent = 0;
|
|
174
|
-
const controlWidth = (xLineRange * control.drag.width) / 100;
|
|
175
|
-
const range = (num) => {
|
|
176
|
-
let _num = num;
|
|
177
|
-
const min = 0;
|
|
178
|
-
const max = xLineRange - controlWidth;
|
|
179
|
-
_num = Math.max(_num, min);
|
|
180
|
-
_num = Math.min(_num, max);
|
|
181
|
-
return _num;
|
|
182
|
-
};
|
|
183
|
-
const setControlTranslate = (x) => {
|
|
184
|
-
const moveLen = range(x);
|
|
185
|
-
controlEl.current.style.transform = `translateX(${moveLen}px)`;
|
|
186
|
-
//计算出当前位移的百分比
|
|
187
|
-
percent = moveLen / (xLineRange - controlWidth);
|
|
188
|
-
curControlPercent.current = percent;
|
|
189
|
-
seriesEl.current.style.transform = `translate(${
|
|
190
|
-
-(axisX.controlEnd - axisX.end) * percent
|
|
191
|
-
}px,${marginTop}px)`;
|
|
192
|
-
axisElList.current[2].style.transform = `translate(${
|
|
193
|
-
-(axisX.controlEnd - axisX.end) * percent
|
|
194
|
-
}px,${0}px)`;
|
|
195
|
-
};
|
|
196
|
-
const mouseDownHandle = (e) => {
|
|
197
|
-
const mouseMoveHandle = (e) => {
|
|
198
|
-
//当前位移的距离
|
|
199
|
-
if (isDragging) {
|
|
200
|
-
movementX += e.movementX;
|
|
201
|
-
setControlTranslate(movementX + rawTranslateX);
|
|
202
|
-
}
|
|
203
|
-
};
|
|
204
|
-
const mouseUpHandle = (e) => {
|
|
205
|
-
rawTranslateX = range(movementX + rawTranslateX);
|
|
206
|
-
movementX = 0;
|
|
207
|
-
isDragging = false;
|
|
208
|
-
document.removeEventListener("mousemove", mouseMoveHandle);
|
|
209
|
-
document.removeEventListener("mouseup", mouseUpHandle);
|
|
210
|
-
};
|
|
211
|
-
document.addEventListener("mousemove", mouseMoveHandle);
|
|
212
|
-
document.addEventListener("mouseup", mouseUpHandle);
|
|
213
|
-
isDragging = true;
|
|
214
|
-
};
|
|
189
|
+
const controlTimer = useRef(); //控制条的动画计时器
|
|
190
|
+
const ctlBarX = useRef(0); //控制条的滑块偏移值
|
|
191
|
+
const isWorking = useRef(false); //控制条是否正在进行各种操作
|
|
215
192
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
193
|
+
const range = (num) => {
|
|
194
|
+
let _num = num;
|
|
195
|
+
const min = 0;
|
|
196
|
+
const max = cWidth - cBarWidth;
|
|
197
|
+
_num = Math.max(_num, min);
|
|
198
|
+
_num = Math.min(_num, max);
|
|
199
|
+
return _num;
|
|
200
|
+
};
|
|
201
|
+
//设置滑块和图表主体的偏移值
|
|
202
|
+
const setControlTranslate = (x, needSave) => {
|
|
203
|
+
const { controlEnd, start } = axisX;
|
|
204
|
+
const moveLen = range(x);
|
|
205
|
+
if(needSave) ctlBarX.current = moveLen;
|
|
206
|
+
controlEl.current.style.transform = `translate(${moveLen}px,0)`;
|
|
207
|
+
//计算出当前位移的百分比
|
|
208
|
+
const percent = moveLen / (cWidth - cBarWidth);
|
|
209
|
+
const translateX = -(controlEnd + start/cPercent - chartWidth) * percent;
|
|
210
|
+
curControlPercent.current = percent;
|
|
211
|
+
seriesEl.current.style.transform = `translate(${translateX}px,${marginTop}px)`;
|
|
212
|
+
axisElList.current[2].style.transform = `translate(${translateX}px,${0}px)`;
|
|
213
|
+
};
|
|
214
|
+
//设置控制条是否正在进行拖拽/缩放操作
|
|
215
|
+
const setWorking=(bool)=>{
|
|
216
|
+
isWorking.current = bool;
|
|
217
|
+
}
|
|
218
|
+
useEffect(() => {
|
|
219
|
+
if (controlEl.current && control) {
|
|
220
|
+
let isEnter = false; //控制条轮播动画是否处于暂停状态
|
|
227
221
|
const { show, duration, interval, hover } = animation;
|
|
228
|
-
const
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
timeGap = timestamp - initTime;
|
|
249
|
-
if (timeGap < (interval + duration) * 1000) {
|
|
250
|
-
if (timeGap < duration * 1000) {
|
|
251
|
-
const p = timeGap / (duration * 1000);
|
|
252
|
-
let nextIndex = index + 1;
|
|
253
|
-
let v;
|
|
254
|
-
if (nextIndex < animatePos.length) {
|
|
255
|
-
v =
|
|
256
|
-
p * (animatePos[nextIndex] - animatePos[index]) +
|
|
257
|
-
animatePos[index];
|
|
258
|
-
} else {
|
|
259
|
-
nextIndex = 0;
|
|
260
|
-
v = (1 - p) * animatePos[index];
|
|
222
|
+
const startAnimate=()=>{
|
|
223
|
+
const loopInterval = interval*1000, tranDuration = duration*1000;
|
|
224
|
+
let loopTime, timeGap, toRight=true;
|
|
225
|
+
const transition=(timeStamp)=>{
|
|
226
|
+
if(!loopTime)loopTime=timeStamp;
|
|
227
|
+
if(!isEnter && !isWorking.current){
|
|
228
|
+
if(timeStamp-loopTime<tranDuration){
|
|
229
|
+
const percent = Math.min(1,(timeStamp-loopTime)/tranDuration);
|
|
230
|
+
if(toRight){
|
|
231
|
+
setControlTranslate(cBarWidth*percent+ctlBarX.current);
|
|
232
|
+
}else{
|
|
233
|
+
setControlTranslate(ctlBarX.current*(1-percent));
|
|
234
|
+
}
|
|
235
|
+
controlTimer.current = requestAnimationFrame(transition);
|
|
236
|
+
}else{
|
|
237
|
+
loopTime = timeStamp;
|
|
238
|
+
if(toRight){
|
|
239
|
+
setControlTranslate(cBarWidth+ctlBarX.current, true);
|
|
240
|
+
}else{
|
|
241
|
+
setControlTranslate(0,true);
|
|
261
242
|
}
|
|
262
|
-
|
|
243
|
+
controlTimer.current = requestAnimationFrame(loop);
|
|
263
244
|
}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
initTime = 0;
|
|
268
|
-
animationId = window.requestAnimationFrame(animation);
|
|
245
|
+
}else{
|
|
246
|
+
loopTime = timeStamp-timeGap;
|
|
247
|
+
controlTimer.current = requestAnimationFrame(transition);
|
|
269
248
|
}
|
|
270
|
-
|
|
271
|
-
|
|
249
|
+
timeGap = timeStamp - loopTime;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const loop=(timeStamp)=>{
|
|
253
|
+
if(!loopTime)loopTime=timeStamp;
|
|
254
|
+
if(!isEnter && !isWorking.current){
|
|
255
|
+
if(timeStamp-loopTime<loopInterval){
|
|
256
|
+
controlTimer.current = requestAnimationFrame(loop);
|
|
257
|
+
}else{
|
|
258
|
+
loopTime = timeStamp;
|
|
259
|
+
if(ctlBarX.current==cWidth - cBarWidth) toRight=false;
|
|
260
|
+
else toRight=true;
|
|
261
|
+
controlTimer.current = requestAnimationFrame(transition);
|
|
262
|
+
}
|
|
263
|
+
}else{
|
|
264
|
+
loopTime = timeStamp-timeGap;
|
|
265
|
+
controlTimer.current = requestAnimationFrame(loop);
|
|
266
|
+
}
|
|
267
|
+
timeGap = timeStamp - loopTime;
|
|
268
|
+
}
|
|
269
|
+
controlTimer.current = requestAnimationFrame(loop);
|
|
270
|
+
}
|
|
271
|
+
const mouseenter = () => {
|
|
272
|
+
isEnter = true;
|
|
273
|
+
};
|
|
274
|
+
const mouseleave = () => {
|
|
275
|
+
isEnter = false;
|
|
276
|
+
};
|
|
277
|
+
if(hover){
|
|
278
|
+
svg.current.addEventListener("mouseenter",mouseenter);
|
|
279
|
+
svg.current.addEventListener("mouseleave",mouseleave);
|
|
280
|
+
controlEl.current.addEventListener("mouseenter",mouseenter);
|
|
281
|
+
controlEl.current.addEventListener("mouseleave",mouseleave);
|
|
282
|
+
}
|
|
283
|
+
if(show){
|
|
284
|
+
startAnimate();
|
|
272
285
|
}
|
|
273
|
-
controlEl.current.addEventListener("mousedown", mouseDownHandle);
|
|
274
|
-
|
|
275
286
|
return () => {
|
|
276
|
-
|
|
277
|
-
svg.current.removeEventListener(
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
);
|
|
281
|
-
svg.current.removeEventListener(
|
|
282
|
-
"mouseleave",
|
|
283
|
-
setAnimationHoverStopFalse
|
|
284
|
-
);
|
|
285
|
-
|
|
286
|
-
window.cancelAnimationFrame(animationId);
|
|
287
|
+
svg.current.removeEventListener("mouseenter",mouseenter);
|
|
288
|
+
svg.current.removeEventListener("mouseleave",mouseleave);
|
|
289
|
+
controlEl.current.removeEventListener("mouseenter",mouseenter);
|
|
290
|
+
controlEl.current.removeEventListener("mouseleave",mouseleave);
|
|
291
|
+
cancelAnimationFrame(controlTimer.current);
|
|
287
292
|
};
|
|
288
293
|
}
|
|
289
294
|
}, [JSON.stringify(animation), control]);
|
|
290
|
-
|
|
291
|
-
const
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
})
|
|
309
|
-
);
|
|
295
|
+
//初始化控制图提示框状态的函数
|
|
296
|
+
const initCtlTip = ()=>{
|
|
297
|
+
return {
|
|
298
|
+
show:false,
|
|
299
|
+
xName:"",
|
|
300
|
+
x:undefined,
|
|
301
|
+
indicatorList:axisX.ticks.map((tick) => {
|
|
302
|
+
return {
|
|
303
|
+
tick: tick,
|
|
304
|
+
isShow: false,
|
|
305
|
+
};
|
|
306
|
+
})
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
const [ctlTip, setCtlTip] = useState(initCtlTip);
|
|
310
|
+
const { show:showCtl, xName:ctlXName, x:ctlX, indicatorList:ctlIndicatorList } = ctlTip;
|
|
311
|
+
const controlChartTooltipData = ctlXName && originData.filter((d) => d.x === ctlXName);
|
|
312
|
+
|
|
310
313
|
return (
|
|
311
314
|
<>
|
|
312
315
|
<ChartContainer
|
|
@@ -334,7 +337,7 @@ const Chart = memo(
|
|
|
334
337
|
>
|
|
335
338
|
<svg width="100%" height="100%">
|
|
336
339
|
<Background
|
|
337
|
-
length={isVertical ? chartWidth :
|
|
340
|
+
length={isVertical ? chartWidth : yLineRange}
|
|
338
341
|
axis={axisX}
|
|
339
342
|
config={background}
|
|
340
343
|
bandLength={bandLength}
|
|
@@ -344,7 +347,6 @@ const Chart = memo(
|
|
|
344
347
|
)}
|
|
345
348
|
{[...axes.values()].reverse().map((item, index) => {
|
|
346
349
|
const config = item.axisType == "x" ? axisX : item;
|
|
347
|
-
|
|
348
350
|
return (
|
|
349
351
|
<Axis
|
|
350
352
|
ref={(d) => {
|
|
@@ -353,30 +355,13 @@ const Chart = memo(
|
|
|
353
355
|
triggerClick={onInteraction}
|
|
354
356
|
xLineRange={xLineRange}
|
|
355
357
|
yLineRange={yLineRange}
|
|
356
|
-
|
|
357
|
-
controlConfig={control}
|
|
358
|
+
controlInfo={controlInfo}
|
|
358
359
|
{...config}
|
|
359
360
|
key={index}
|
|
360
361
|
/>
|
|
361
362
|
);
|
|
362
363
|
})}
|
|
363
|
-
{
|
|
364
|
-
{isControlChart && control && (
|
|
365
|
-
<Control
|
|
366
|
-
ref={controlEl}
|
|
367
|
-
props={{
|
|
368
|
-
control,
|
|
369
|
-
axes,
|
|
370
|
-
series,
|
|
371
|
-
xLineRange,
|
|
372
|
-
yLineRange,
|
|
373
|
-
marginTop,
|
|
374
|
-
axisX,
|
|
375
|
-
bandLength,
|
|
376
|
-
}}
|
|
377
|
-
></Control>
|
|
378
|
-
)}
|
|
379
|
-
{showTooltip && !isControlChart && (
|
|
364
|
+
{showTooltip && !control && (
|
|
380
365
|
<Indicator {...indicator} {...indicatorAttr} />
|
|
381
366
|
)}
|
|
382
367
|
|
|
@@ -408,33 +393,27 @@ const Chart = memo(
|
|
|
408
393
|
>
|
|
409
394
|
{/* 控制图指示器部分 */}
|
|
410
395
|
<g>
|
|
411
|
-
{
|
|
412
|
-
|
|
396
|
+
{control &&
|
|
397
|
+
ctlIndicatorList.map((item, index) => {
|
|
413
398
|
const x = axisX.scaler(item.tick);
|
|
414
399
|
return (
|
|
415
400
|
<Indicator
|
|
416
401
|
key={index}
|
|
417
402
|
{...indicator}
|
|
418
403
|
{...{
|
|
419
|
-
height:
|
|
404
|
+
height: yLineRange,
|
|
420
405
|
width: indicatorWidth,
|
|
421
406
|
x: x - indicatorWidth / 2,
|
|
422
407
|
}}
|
|
423
|
-
isControlChart={
|
|
408
|
+
isControlChart={!!control}
|
|
424
409
|
xName={item.tick}
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
}
|
|
428
|
-
setControlChartTooltipX={setControlChartTooltipX}
|
|
429
|
-
setControlChartTooltipShow={setControlChartTooltipShow}
|
|
430
|
-
controlChartIndicatorList={controlChartIndicatorList}
|
|
431
|
-
setControlChartIndicatorList={
|
|
432
|
-
setControlChartIndicatorList
|
|
433
|
-
}
|
|
410
|
+
setCtlTip={setCtlTip}
|
|
411
|
+
ctlIndicatorList={ctlIndicatorList}
|
|
434
412
|
/>
|
|
435
413
|
);
|
|
436
414
|
})}
|
|
437
415
|
</g>
|
|
416
|
+
{/**绘制图表主体 */}
|
|
438
417
|
{series.map(({ Component, yOrZ, ...config }, index) => {
|
|
439
418
|
const yAxis = axes.get(yOrZ);
|
|
440
419
|
return (
|
|
@@ -447,15 +426,10 @@ const Chart = memo(
|
|
|
447
426
|
xAxis={axisX}
|
|
448
427
|
yAxis={yAxis}
|
|
449
428
|
// 控制图部分,主要是为了,当鼠标悬浮在指示器上时,显示对应的tooltip
|
|
450
|
-
isControlChart={
|
|
451
|
-
setControlChartTooltipXName={setControlChartTooltipXName}
|
|
452
|
-
setControlChartTooltipX={setControlChartTooltipX}
|
|
453
|
-
setControlChartTooltipShow={setControlChartTooltipShow}
|
|
429
|
+
isControlChart={!!control}
|
|
454
430
|
indicatorWidth={indicatorWidth}
|
|
455
431
|
triggerClick={onInteraction}
|
|
456
|
-
|
|
457
|
-
setControlChartIndicatorList
|
|
458
|
-
}
|
|
432
|
+
setCtlTip={setCtlTip}
|
|
459
433
|
/>
|
|
460
434
|
)
|
|
461
435
|
);
|
|
@@ -503,8 +477,27 @@ const Chart = memo(
|
|
|
503
477
|
);
|
|
504
478
|
})}
|
|
505
479
|
</ChartContainer>
|
|
480
|
+
{/* 控制条逻辑 */}
|
|
481
|
+
{control && (
|
|
482
|
+
<Control
|
|
483
|
+
ref={controlEl}
|
|
484
|
+
actions={{
|
|
485
|
+
setX:setControlTranslate,
|
|
486
|
+
setWorking,
|
|
487
|
+
setControlInfo
|
|
488
|
+
}}
|
|
489
|
+
props={{
|
|
490
|
+
control,
|
|
491
|
+
axes,
|
|
492
|
+
series,
|
|
493
|
+
width,
|
|
494
|
+
top:chartHeight+marginTop,
|
|
495
|
+
bandLength,
|
|
496
|
+
}}
|
|
497
|
+
></Control>
|
|
498
|
+
)}
|
|
506
499
|
<Legend {...legend} filterData={filterData} series={series} />
|
|
507
|
-
{showTooltip && !
|
|
500
|
+
{showTooltip && !control && (
|
|
508
501
|
<Tooltip
|
|
509
502
|
isVertical={isVertical}
|
|
510
503
|
{...tooltip}
|
|
@@ -519,18 +512,15 @@ const Chart = memo(
|
|
|
519
512
|
/>
|
|
520
513
|
)}
|
|
521
514
|
|
|
522
|
-
{
|
|
515
|
+
{showCtl && !!control && (
|
|
523
516
|
<Tooltip
|
|
524
517
|
isVertical={isVertical}
|
|
525
518
|
{...tooltip}
|
|
526
519
|
data={controlChartTooltipData}
|
|
527
|
-
x={
|
|
528
|
-
controlChartTooltipX -
|
|
529
|
-
(axisX.controlEnd - axisX.end) * curControlPercent.current
|
|
530
|
-
}
|
|
520
|
+
x={ ctlX -(axisX.controlEnd + axisX.start/cPercent - chartWidth) * curControlPercent.current}
|
|
531
521
|
marginLeft={marginLeft}
|
|
532
522
|
marginTop={marginTop}
|
|
533
|
-
tickName={
|
|
523
|
+
tickName={ctlXName}
|
|
534
524
|
series={series}
|
|
535
525
|
width={width}
|
|
536
526
|
height={height}
|
|
@@ -2,50 +2,94 @@ import React, { forwardRef, memo, useRef } from "react";
|
|
|
2
2
|
import { scaleLinear } from "d3-scale";
|
|
3
3
|
|
|
4
4
|
export default memo(forwardRef((props, ref) => {
|
|
5
|
-
const {
|
|
6
|
-
|
|
5
|
+
const {
|
|
6
|
+
actions:{ setX, setWorking, setControlInfo },
|
|
7
|
+
props: {
|
|
8
|
+
control:{ height, color, drag:{ color:dragColor, width:dragWidth }, margin:{ left, right } }, axes, series, width, top, bandLength
|
|
9
|
+
}
|
|
10
|
+
} = props;
|
|
11
|
+
const barWidth = width-left-right;
|
|
12
|
+
const xAxis = axes.get("x");
|
|
13
|
+
const barRef = useRef();
|
|
14
|
+
|
|
15
|
+
const barStyle={
|
|
16
|
+
position:"absolute",
|
|
17
|
+
top:0,
|
|
18
|
+
width:barWidth*dragWidth/100,
|
|
19
|
+
display:"flex",
|
|
20
|
+
justifyContent:"space-between",
|
|
21
|
+
background:dragColor
|
|
22
|
+
}
|
|
23
|
+
const dragStyle={
|
|
24
|
+
height,
|
|
25
|
+
flex:1,
|
|
26
|
+
cursor:"move"
|
|
27
|
+
}
|
|
28
|
+
const controllerStyle={
|
|
29
|
+
position:"relative",
|
|
30
|
+
width:12,
|
|
31
|
+
height,
|
|
32
|
+
padding:"0 5px",
|
|
33
|
+
cursor:"col-resize",
|
|
34
|
+
background:"rgb(2, 176, 249)",
|
|
35
|
+
WebkitBackgroundClip:"content-box",
|
|
36
|
+
}
|
|
37
|
+
const down=()=>{
|
|
38
|
+
const transform = ref.current.style.transform;
|
|
39
|
+
let movementX = 0;
|
|
40
|
+
let rawTranslateX = parseFloat(transform?transform.match(/\d+\.*\d*/)[0]:0);
|
|
41
|
+
const mouseMoveHandle = (e) => {
|
|
42
|
+
//当前位移的距离
|
|
43
|
+
movementX += e.movementX;
|
|
44
|
+
setX(movementX + rawTranslateX,true);
|
|
45
|
+
};
|
|
46
|
+
const mouseUpHandle = (e) => {
|
|
47
|
+
setWorking(false);
|
|
48
|
+
document.removeEventListener("mousemove", mouseMoveHandle);
|
|
49
|
+
document.removeEventListener("mouseup", mouseUpHandle);
|
|
50
|
+
};
|
|
51
|
+
document.addEventListener("mousemove", mouseMoveHandle);
|
|
52
|
+
document.addEventListener("mouseup", mouseUpHandle);
|
|
53
|
+
setWorking(true);
|
|
54
|
+
}
|
|
7
55
|
return (
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
></rect>
|
|
46
|
-
</svg>
|
|
47
|
-
</foreignObject>
|
|
48
|
-
</>
|
|
56
|
+
<div
|
|
57
|
+
style={{
|
|
58
|
+
width: barWidth,
|
|
59
|
+
height: height,
|
|
60
|
+
backgroundColor: color,
|
|
61
|
+
transform: `translate(${left}px,${top}px)`,
|
|
62
|
+
}}
|
|
63
|
+
>
|
|
64
|
+
<svg width="100%" height="100%">
|
|
65
|
+
{series.map(({ Component, yOrZ, ...config }, index) => {
|
|
66
|
+
const yAxis = axes.get(yOrZ);
|
|
67
|
+
const cloneYAxis = JSON.parse(JSON.stringify(yAxis));
|
|
68
|
+
//todo range
|
|
69
|
+
cloneYAxis.scaler = scaleLinear()
|
|
70
|
+
.domain(yAxis.domain)
|
|
71
|
+
.range([height, 0]);
|
|
72
|
+
return (
|
|
73
|
+
yAxis &&
|
|
74
|
+
Component && (
|
|
75
|
+
<Component
|
|
76
|
+
key={index}
|
|
77
|
+
{...config}
|
|
78
|
+
bandLength={bandLength}
|
|
79
|
+
xAxis={xAxis}
|
|
80
|
+
yAxis={cloneYAxis}
|
|
81
|
+
/>
|
|
82
|
+
)
|
|
83
|
+
);
|
|
84
|
+
})}
|
|
85
|
+
</svg>
|
|
86
|
+
{/* 控制条 */}
|
|
87
|
+
<div ref={ref} style={barStyle}>
|
|
88
|
+
{/* <div style={{...controllerStyle,transform:"translateX(-6px)"}}></div> */}
|
|
89
|
+
<div style={dragStyle} onMouseDown={down} ref={barRef}></div>
|
|
90
|
+
{/* <div style={{...controllerStyle,transform:`translateX(6px)`}}></div> */}
|
|
91
|
+
</div>
|
|
92
|
+
</div>
|
|
49
93
|
);
|
|
50
94
|
}))
|
|
51
95
|
|