@hsu-react/ui 2.5.4 → 2.5.5
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/es/components/ChainGraph/_hooks/useChainGraphData.js +29 -8
- package/es/components/ChainGraph/_hooks/useChainGraphLayout.js +14 -3
- package/es/components/Chart/Bar/index.js +49 -19
- package/es/components/Chart/Bubble/index.js +15 -5
- package/es/components/Chart/Heatmap/index.js +15 -5
- package/es/components/Chart/Line/index.js +49 -19
- package/es/components/Chart/Pie/Pie3D/index.js +15 -5
- package/es/components/Chart/Pie/index.js +15 -5
- package/es/components/Chart/Sankey/index.js +11 -2
- package/es/components/Chart/Tree/index.js +11 -2
- package/es/components/Select/_hooks/useSelectComposition.js +6 -2
- package/es/components/Table/_hooks/useAutoScrolling.js +16 -7
- package/es/layout/Menu/_hooks/useOnlyLvOneMenu.js +9 -2
- package/lib/components/ChainGraph/_hooks/useChainGraphData.js +24 -7
- package/lib/components/ChainGraph/_hooks/useChainGraphLayout.js +12 -2
- package/lib/components/Chart/Bar/index.js +45 -18
- package/lib/components/Chart/Bubble/index.js +14 -5
- package/lib/components/Chart/Heatmap/index.js +14 -5
- package/lib/components/Chart/Line/index.js +45 -18
- package/lib/components/Chart/Pie/Pie3D/index.js +14 -5
- package/lib/components/Chart/Pie/index.js +14 -5
- package/lib/components/Chart/Sankey/index.js +10 -2
- package/lib/components/Chart/Tree/index.js +10 -2
- package/lib/components/Select/_hooks/useSelectComposition.js +6 -2
- package/lib/components/Table/_hooks/useAutoScrolling.js +16 -7
- package/lib/layout/Menu/_hooks/useOnlyLvOneMenu.js +8 -2
- package/package.json +1 -1
- package/src/__tests__/callbackDepsGuard.test.ts +119 -0
- package/src/components/ChainGraph/_hooks/callbacks.test.tsx +155 -0
- package/src/components/ChainGraph/_hooks/useChainGraphData.ts +38 -10
- package/src/components/ChainGraph/_hooks/useChainGraphLayout.ts +16 -3
- package/src/components/Chart/Bar/index.tsx +59 -21
- package/src/components/Chart/Bubble/index.tsx +15 -5
- package/src/components/Chart/Heatmap/index.tsx +19 -5
- package/src/components/Chart/Line/index.tsx +59 -21
- package/src/components/Chart/Pie/Pie3D/index.tsx +15 -5
- package/src/components/Chart/Pie/index.tsx +15 -5
- package/src/components/Chart/Sankey/index.tsx +10 -4
- package/src/components/Chart/Tree/index.tsx +10 -4
- package/src/components/Chart/callbacks.test.tsx +315 -0
- package/src/components/Select/_hooks/useSelectComposition.test.ts +47 -0
- package/src/components/Select/_hooks/useSelectComposition.ts +6 -2
- package/src/components/Table/_hooks/useAutoScrolling.test.tsx +95 -0
- package/src/components/Table/_hooks/useAutoScrolling.ts +16 -7
- package/src/layout/Menu/_hooks/useOnlyLvOneMenu.test.tsx +56 -0
- package/src/layout/Menu/_hooks/useOnlyLvOneMenu.ts +8 -2
|
@@ -4,8 +4,9 @@ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o =
|
|
|
4
4
|
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
|
5
5
|
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
|
6
6
|
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
|
7
|
-
import { useEffect, useState } from "react";
|
|
7
|
+
import { useCallback, useEffect, useState } from "react";
|
|
8
8
|
import { Equal } from "hsu-utils";
|
|
9
|
+
import { useLatestRef } from "../../../hooks/useLatestRef";
|
|
9
10
|
export function useChainGraphData(props) {
|
|
10
11
|
var graph = props.graph,
|
|
11
12
|
data = props.data,
|
|
@@ -22,6 +23,29 @@ export function useChainGraphData(props) {
|
|
|
22
23
|
_useState4 = _slicedToArray(_useState3, 2),
|
|
23
24
|
isLayouting = _useState4[0],
|
|
24
25
|
setIsLayouting = _useState4[1];
|
|
26
|
+
|
|
27
|
+
// 这三个回调都是「交给图实例、由它在后续事件里回调」的出口,不是数据本身。
|
|
28
|
+
// 它们进依赖数组是条死依赖:effect 体被 ObjEqual(lastData, data) 挡住,
|
|
29
|
+
// 引用变了也不会重新 setData —— 图里存的还是首次 setData 时那个闭包,
|
|
30
|
+
// 换了引用永远调不到(stale closure)。改成引用恒定的转发函数:
|
|
31
|
+
// 依赖数组只留真正的输入(graph/data/level/rootLevel),调用时总是取到最新的回调。
|
|
32
|
+
var getImageRef = useLatestRef(getImage);
|
|
33
|
+
var labelRenderRef = useLatestRef(labelRender);
|
|
34
|
+
var onLayoutingChangeRef = useLatestRef(onLayoutingChange);
|
|
35
|
+
var emitImage = useCallback(function (img) {
|
|
36
|
+
var _getImageRef$current;
|
|
37
|
+
(_getImageRef$current = getImageRef.current) === null || _getImageRef$current === void 0 || _getImageRef$current.call(getImageRef, img);
|
|
38
|
+
}, [getImageRef]);
|
|
39
|
+
// labelRender 在 ChainGraphServices.setData 里是「传了才改写 label」的真值判断,
|
|
40
|
+
// 所以这里保留「有没有传」的语义:没传就传 undefined,传了才给转发函数。
|
|
41
|
+
var renderLabel = useCallback(function (label) {
|
|
42
|
+
return labelRenderRef.current(label);
|
|
43
|
+
}, [labelRenderRef]);
|
|
44
|
+
var emitLayouting = useCallback(function (value) {
|
|
45
|
+
var _onLayoutingChangeRef;
|
|
46
|
+
setIsLayouting(value);
|
|
47
|
+
(_onLayoutingChangeRef = onLayoutingChangeRef.current) === null || _onLayoutingChangeRef === void 0 || _onLayoutingChangeRef.call(onLayoutingChangeRef, value);
|
|
48
|
+
}, [onLayoutingChangeRef]);
|
|
25
49
|
useEffect(function () {
|
|
26
50
|
if (graph && !Equal.ObjEqual(lastData, data)) {
|
|
27
51
|
setLastData(data);
|
|
@@ -29,15 +53,12 @@ export function useChainGraphData(props) {
|
|
|
29
53
|
data: data,
|
|
30
54
|
level: level,
|
|
31
55
|
rootLevel: rootLevel,
|
|
32
|
-
getImage:
|
|
33
|
-
isLayouting:
|
|
34
|
-
|
|
35
|
-
onLayoutingChange === null || onLayoutingChange === void 0 || onLayoutingChange(value);
|
|
36
|
-
},
|
|
37
|
-
labelRender: labelRender
|
|
56
|
+
getImage: emitImage,
|
|
57
|
+
isLayouting: emitLayouting,
|
|
58
|
+
labelRender: labelRenderRef.current ? renderLabel : undefined
|
|
38
59
|
});
|
|
39
60
|
}
|
|
40
|
-
}, [graph, data, level, rootLevel,
|
|
61
|
+
}, [graph, data, level, rootLevel, lastData, emitImage, emitLayouting, renderLabel, labelRenderRef]);
|
|
41
62
|
return {
|
|
42
63
|
isLayouting: isLayouting
|
|
43
64
|
};
|
|
@@ -1,12 +1,23 @@
|
|
|
1
|
-
import { useEffect } from "react";
|
|
1
|
+
import { useCallback, useEffect } from "react";
|
|
2
|
+
import { useLatestRef } from "../../../hooks/useLatestRef";
|
|
2
3
|
export function useChainGraphLayout(props) {
|
|
3
4
|
var graph = props.graph,
|
|
4
5
|
octopus = props.octopus,
|
|
5
6
|
rootLevel = props.rootLevel,
|
|
6
7
|
getImage = props.getImage;
|
|
8
|
+
|
|
9
|
+
// getImage 只是「布局完成后把截图 dataURL 交出去」的出口,不是布局的输入。
|
|
10
|
+
// 它进依赖数组会让消费方每传一次内联箭头就重新 changeLayout 一次 —— 整张图重排;
|
|
11
|
+
// 消费方再把截图存进 state,就变成「重排 → 出图 → setState → 新引用 → 再重排」的死循环。
|
|
12
|
+
// 用引用恒定的转发函数注册,调用时再取最新的 getImage。
|
|
13
|
+
var getImageRef = useLatestRef(getImage);
|
|
14
|
+
var emitImage = useCallback(function (img) {
|
|
15
|
+
var _getImageRef$current;
|
|
16
|
+
(_getImageRef$current = getImageRef.current) === null || _getImageRef$current === void 0 || _getImageRef$current.call(getImageRef, img);
|
|
17
|
+
}, [getImageRef]);
|
|
7
18
|
useEffect(function () {
|
|
8
19
|
if (graph && octopus !== undefined) {
|
|
9
|
-
graph.changeLayout(octopus, rootLevel,
|
|
20
|
+
graph.changeLayout(octopus, rootLevel, emitImage);
|
|
10
21
|
}
|
|
11
|
-
}, [graph, octopus, rootLevel,
|
|
22
|
+
}, [graph, octopus, rootLevel, emitImage]);
|
|
12
23
|
}
|
|
@@ -16,6 +16,7 @@ import { autoScrollByItem } from "../_utils/autoSmooth";
|
|
|
16
16
|
import { buildCartesianSeriesOptions, createDefaultCategoryXAxis, createDefaultValueYAxis, getSliderShow, percentWindowToIndexWindow, resolveScrollConfig } from "../_utils/cartesian";
|
|
17
17
|
import { resolveChartChrome } from "../_utils/chartTheme";
|
|
18
18
|
import useIsDark from "../../../hooks/useIsDark";
|
|
19
|
+
import useLatestRef from "../../../hooks/useLatestRef";
|
|
19
20
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
20
21
|
var ChartBar = function ChartBar(props) {
|
|
21
22
|
var className = props.className,
|
|
@@ -62,6 +63,30 @@ var ChartBar = function ChartBar(props) {
|
|
|
62
63
|
return resolveChartChrome(isDark);
|
|
63
64
|
}, [isDark]);
|
|
64
65
|
|
|
66
|
+
// 回调 prop 一律走 useLatestRef,不进依赖数组:消费方传内联箭头(React 里最常见的
|
|
67
|
+
// 写法)时每次渲染都是新引用,进依赖数组会让「init + setOption(notMerge)」整段重跑,
|
|
68
|
+
// 还会把当前可视窗口再同步一次给父级 —— 父级据此改 state 就是死循环。
|
|
69
|
+
// 但「有没有传回调」决定要不要注册监听,所以单独拆成布尔量进依赖数组,
|
|
70
|
+
// 这样「从无到有传入回调」仍会重新注册,不会漏。
|
|
71
|
+
var onClickRef = useLatestRef(onClick);
|
|
72
|
+
var onLegendSelectChangedRef = useLatestRef(onLegendSelectChanged);
|
|
73
|
+
var onDataZoomWindowChangedRef = useLatestRef(onDataZoomWindowChanged);
|
|
74
|
+
var hasOnClick = !!onClick;
|
|
75
|
+
var hasOnLegendSelectChanged = !!onLegendSelectChanged;
|
|
76
|
+
var hasOnDataZoomWindowChanged = !!onDataZoomWindowChanged;
|
|
77
|
+
// 已通知过父级的窗口用 ref 记账(不参与渲染):窗口没变就不再通知,
|
|
78
|
+
// 掐断「通知 → 父级重算坐标轴 → chartOption 变 → effect 重跑 → 再通知」的自激回路
|
|
79
|
+
var notifiedZoomWindowRef = useRef(null);
|
|
80
|
+
var emitZoomWindow = useCallback(function (next) {
|
|
81
|
+
var _onDataZoomWindowChan;
|
|
82
|
+
var prev = notifiedZoomWindowRef.current;
|
|
83
|
+
if (prev && prev.startIndex === next.startIndex && prev.endIndex === next.endIndex) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
notifiedZoomWindowRef.current = next;
|
|
87
|
+
(_onDataZoomWindowChan = onDataZoomWindowChangedRef.current) === null || _onDataZoomWindowChan === void 0 || _onDataZoomWindowChan.call(onDataZoomWindowChangedRef, next);
|
|
88
|
+
}, [onDataZoomWindowChangedRef]);
|
|
89
|
+
|
|
65
90
|
// Cache the chart option with useMemo
|
|
66
91
|
var chartOption = useMemo(function () {
|
|
67
92
|
var _xAxisData$length, _ref, _ref2;
|
|
@@ -239,16 +264,16 @@ var ChartBar = function ChartBar(props) {
|
|
|
239
264
|
}
|
|
240
265
|
|
|
241
266
|
// Sync the current visible window to the caller (on initial render and after restore), used to recalculate axes based on the displayed portion
|
|
242
|
-
if (
|
|
267
|
+
if (hasOnDataZoomWindowChanged) {
|
|
243
268
|
var _chart$getOption3, _xAxisData$length2;
|
|
244
269
|
var zooms = (_chart$getOption3 = chart.getOption()) === null || _chart$getOption3 === void 0 ? void 0 : _chart$getOption3.dataZoom;
|
|
245
270
|
var zoom = zooms === null || zooms === void 0 ? void 0 : zooms[0];
|
|
246
271
|
var totalLen = (_xAxisData$length2 = xAxisData === null || xAxisData === void 0 ? void 0 : xAxisData.length) !== null && _xAxisData$length2 !== void 0 ? _xAxisData$length2 : 0;
|
|
247
272
|
if (typeof (zoom === null || zoom === void 0 ? void 0 : zoom.start) === "number" && typeof (zoom === null || zoom === void 0 ? void 0 : zoom.end) === "number") {
|
|
248
|
-
|
|
273
|
+
emitZoomWindow(percentWindowToIndexWindow(zoom.start, zoom.end, totalLen));
|
|
249
274
|
} else {
|
|
250
275
|
// Without dataZoom (e.g. scrolling not enabled due to insufficient data) the window is the full range; sync once to avoid a stale old window
|
|
251
|
-
|
|
276
|
+
emitZoomWindow({
|
|
252
277
|
startIndex: 0,
|
|
253
278
|
endIndex: Math.max(0, totalLen - 1)
|
|
254
279
|
});
|
|
@@ -264,17 +289,22 @@ var ChartBar = function ChartBar(props) {
|
|
|
264
289
|
resizeObserverRef.current.observe(chartRef.current);
|
|
265
290
|
}
|
|
266
291
|
|
|
267
|
-
// Add click event
|
|
268
|
-
|
|
292
|
+
// Add click event(注册与否看布尔量,实际调用取最新引用)
|
|
293
|
+
var handleClick = function handleClick(event) {
|
|
294
|
+
var _onClickRef$current;
|
|
295
|
+
(_onClickRef$current = onClickRef.current) === null || _onClickRef$current === void 0 || _onClickRef$current.call(onClickRef, event);
|
|
296
|
+
};
|
|
297
|
+
if (hasOnClick) {
|
|
269
298
|
var _chartInstanceRef$cur2;
|
|
270
|
-
(_chartInstanceRef$cur2 = chartInstanceRef.current) === null || _chartInstanceRef$cur2 === void 0 || _chartInstanceRef$cur2.on("click",
|
|
299
|
+
(_chartInstanceRef$cur2 = chartInstanceRef.current) === null || _chartInstanceRef$cur2 === void 0 || _chartInstanceRef$cur2.on("click", handleClick);
|
|
271
300
|
}
|
|
272
301
|
|
|
273
302
|
// Legend selection event
|
|
274
303
|
var handleLegendSelectChanged = function handleLegendSelectChanged(params) {
|
|
275
|
-
|
|
304
|
+
var _onLegendSelectChange;
|
|
305
|
+
(_onLegendSelectChange = onLegendSelectChangedRef.current) === null || _onLegendSelectChange === void 0 || _onLegendSelectChange.call(onLegendSelectChangedRef, params.selected);
|
|
276
306
|
};
|
|
277
|
-
if (
|
|
307
|
+
if (hasOnLegendSelectChanged) {
|
|
278
308
|
var _chartInstanceRef$cur3;
|
|
279
309
|
(_chartInstanceRef$cur3 = chartInstanceRef.current) === null || _chartInstanceRef$cur3 === void 0 || _chartInstanceRef$cur3.on("legendselectchanged", handleLegendSelectChanged);
|
|
280
310
|
}
|
|
@@ -285,16 +315,16 @@ var ChartBar = function ChartBar(props) {
|
|
|
285
315
|
var raw = params;
|
|
286
316
|
var info = (_raw$batch$ = raw === null || raw === void 0 || (_raw$batch = raw.batch) === null || _raw$batch === void 0 ? void 0 : _raw$batch[0]) !== null && _raw$batch$ !== void 0 ? _raw$batch$ : raw;
|
|
287
317
|
if (typeof (info === null || info === void 0 ? void 0 : info.startValue) === "number" && typeof (info === null || info === void 0 ? void 0 : info.endValue) === "number") {
|
|
288
|
-
|
|
318
|
+
emitZoomWindow({
|
|
289
319
|
startIndex: Math.max(0, Math.round(info.startValue)),
|
|
290
320
|
endIndex: Math.max(0, Math.round(info.endValue))
|
|
291
321
|
});
|
|
292
322
|
} else if (typeof (info === null || info === void 0 ? void 0 : info.start) === "number" && typeof (info === null || info === void 0 ? void 0 : info.end) === "number") {
|
|
293
323
|
var _xAxisData$length3;
|
|
294
|
-
|
|
324
|
+
emitZoomWindow(percentWindowToIndexWindow(info.start, info.end, (_xAxisData$length3 = xAxisData === null || xAxisData === void 0 ? void 0 : xAxisData.length) !== null && _xAxisData$length3 !== void 0 ? _xAxisData$length3 : 0));
|
|
295
325
|
}
|
|
296
326
|
};
|
|
297
|
-
if (
|
|
327
|
+
if (hasOnDataZoomWindowChanged) {
|
|
298
328
|
var _chartInstanceRef$cur4;
|
|
299
329
|
(_chartInstanceRef$cur4 = chartInstanceRef.current) === null || _chartInstanceRef$cur4 === void 0 || _chartInstanceRef$cur4.on("datazoom", handleDataZoom);
|
|
300
330
|
}
|
|
@@ -322,15 +352,15 @@ var ChartBar = function ChartBar(props) {
|
|
|
322
352
|
// Cleanup function
|
|
323
353
|
return function () {
|
|
324
354
|
window.removeEventListener("resize", handleResize);
|
|
325
|
-
if (
|
|
355
|
+
if (hasOnClick) {
|
|
326
356
|
var _chartInstanceRef$cur5;
|
|
327
|
-
(_chartInstanceRef$cur5 = chartInstanceRef.current) === null || _chartInstanceRef$cur5 === void 0 || _chartInstanceRef$cur5.off("click",
|
|
357
|
+
(_chartInstanceRef$cur5 = chartInstanceRef.current) === null || _chartInstanceRef$cur5 === void 0 || _chartInstanceRef$cur5.off("click", handleClick);
|
|
328
358
|
}
|
|
329
|
-
if (
|
|
359
|
+
if (hasOnLegendSelectChanged) {
|
|
330
360
|
var _chartInstanceRef$cur6;
|
|
331
361
|
(_chartInstanceRef$cur6 = chartInstanceRef.current) === null || _chartInstanceRef$cur6 === void 0 || _chartInstanceRef$cur6.off("legendselectchanged", handleLegendSelectChanged);
|
|
332
362
|
}
|
|
333
|
-
if (
|
|
363
|
+
if (hasOnDataZoomWindowChanged) {
|
|
334
364
|
var _chartInstanceRef$cur7;
|
|
335
365
|
(_chartInstanceRef$cur7 = chartInstanceRef.current) === null || _chartInstanceRef$cur7 === void 0 || _chartInstanceRef$cur7.off("datazoom", handleDataZoom);
|
|
336
366
|
}
|
|
@@ -339,7 +369,7 @@ var ChartBar = function ChartBar(props) {
|
|
|
339
369
|
legendScrollRef.current = null;
|
|
340
370
|
}
|
|
341
371
|
};
|
|
342
|
-
}, [chartOption, handleResize,
|
|
372
|
+
}, [chartOption, handleResize, onClickRef, onLegendSelectChangedRef, hasOnClick, hasOnLegendSelectChanged, hasOnDataZoomWindowChanged, emitZoomWindow, xAxisData, enableLegendAutoScroll, legendVisibleCount, legendScrollInterval,
|
|
343
373
|
// 图例是否接管滚轮由它推导,漏了会拿到过期的滚动配置
|
|
344
374
|
normalizedScroll, containerReady]);
|
|
345
375
|
|
|
@@ -359,13 +389,13 @@ var ChartBar = function ChartBar(props) {
|
|
|
359
389
|
startIndex: normalizedScroll.startIndex,
|
|
360
390
|
autoPlay: normalizedScroll.autoScroll,
|
|
361
391
|
enableWheelScroll: enableWheelScroll,
|
|
362
|
-
onWindowChange:
|
|
363
|
-
return
|
|
392
|
+
onWindowChange: hasOnDataZoomWindowChanged ? function (startPercent, endPercent) {
|
|
393
|
+
return emitZoomWindow(percentWindowToIndexWindow(startPercent, endPercent, xAxisData.length));
|
|
364
394
|
} : undefined
|
|
365
395
|
}),
|
|
366
396
|
dispose = _autoScrollByItem.dispose;
|
|
367
397
|
return dispose;
|
|
368
|
-
}, [dataZoom, normalizedScroll, sliderDataZoom, xAxisData,
|
|
398
|
+
}, [dataZoom, normalizedScroll, sliderDataZoom, xAxisData, hasOnDataZoomWindowChanged, emitZoomWindow]);
|
|
369
399
|
|
|
370
400
|
// Clean up resources when the component unmounts
|
|
371
401
|
useEffect(function () {
|
|
@@ -279,6 +279,12 @@ var Bubble = function Bubble(props) {
|
|
|
279
279
|
}, [chartOption, data]);
|
|
280
280
|
var onChartRef = useLatestRef(onChart);
|
|
281
281
|
|
|
282
|
+
// onClick 不进依赖数组:消费方传内联箭头时每次渲染都是新引用,effect 跟着重跑就会
|
|
283
|
+
// 再走一遍 setOption(notMerge),动画重播、悬浮/高亮态被清掉。注册与否看布尔量,
|
|
284
|
+
// 这样「从无到有传入 onClick」仍会注册;实际调用取 ref 里的最新引用。
|
|
285
|
+
var onClickRef = useLatestRef(onClick);
|
|
286
|
+
var hasOnClick = !!onClick;
|
|
287
|
+
|
|
282
288
|
// 回调 prop 不进依赖数组:消费方传内联箭头时每次渲染都是新引用,effect 会跟着
|
|
283
289
|
// 重跑并再调一次回调 —— 回调里 setState 就是死循环(详见 Input/TextArea 的说明)
|
|
284
290
|
// Initialize the chart
|
|
@@ -305,20 +311,24 @@ var Bubble = function Bubble(props) {
|
|
|
305
311
|
window.addEventListener("resize", handleResize);
|
|
306
312
|
|
|
307
313
|
// Add click event
|
|
308
|
-
|
|
314
|
+
var handleClick = function handleClick(event) {
|
|
315
|
+
var _onClickRef$current;
|
|
316
|
+
(_onClickRef$current = onClickRef.current) === null || _onClickRef$current === void 0 || _onClickRef$current.call(onClickRef, event);
|
|
317
|
+
};
|
|
318
|
+
if (hasOnClick) {
|
|
309
319
|
var _chartInstanceRef$cur2;
|
|
310
|
-
(_chartInstanceRef$cur2 = chartInstanceRef.current) === null || _chartInstanceRef$cur2 === void 0 || _chartInstanceRef$cur2.on("click",
|
|
320
|
+
(_chartInstanceRef$cur2 = chartInstanceRef.current) === null || _chartInstanceRef$cur2 === void 0 || _chartInstanceRef$cur2.on("click", handleClick);
|
|
311
321
|
}
|
|
312
322
|
|
|
313
323
|
// Cleanup function
|
|
314
324
|
return function () {
|
|
315
325
|
window.removeEventListener("resize", handleResize);
|
|
316
|
-
if (
|
|
326
|
+
if (hasOnClick) {
|
|
317
327
|
var _chartInstanceRef$cur3;
|
|
318
|
-
(_chartInstanceRef$cur3 = chartInstanceRef.current) === null || _chartInstanceRef$cur3 === void 0 || _chartInstanceRef$cur3.off("click",
|
|
328
|
+
(_chartInstanceRef$cur3 = chartInstanceRef.current) === null || _chartInstanceRef$cur3 === void 0 || _chartInstanceRef$cur3.off("click", handleClick);
|
|
319
329
|
}
|
|
320
330
|
};
|
|
321
|
-
}, [chartOption, containerSize.width, containerSize.height, handleResize, onChartRef,
|
|
331
|
+
}, [chartOption, containerSize.width, containerSize.height, handleResize, onChartRef, onClickRef, hasOnClick]);
|
|
322
332
|
|
|
323
333
|
// Dispose the chart instance when the component unmounts
|
|
324
334
|
useEffect(function () {
|
|
@@ -195,6 +195,12 @@ var Heatmap = function Heatmap(props) {
|
|
|
195
195
|
}, []);
|
|
196
196
|
var onChartRef = useLatestRef(onChart);
|
|
197
197
|
|
|
198
|
+
// onClick 不进依赖数组:消费方传内联箭头时每次渲染都是新引用,effect 跟着重跑就会
|
|
199
|
+
// 再走一遍 setOption(notMerge),动画重播、悬浮/高亮态被清掉。注册与否看布尔量,
|
|
200
|
+
// 这样「从无到有传入 onClick」仍会注册;实际调用取 ref 里的最新引用。
|
|
201
|
+
var onClickRef = useLatestRef(onClick);
|
|
202
|
+
var hasOnClick = !!onClick;
|
|
203
|
+
|
|
198
204
|
// 回调 prop 不进依赖数组:消费方传内联箭头时每次渲染都是新引用,effect 会跟着
|
|
199
205
|
// 重跑并再调一次回调 —— 回调里 setState 就是死循环(详见 Input/TextArea 的说明)
|
|
200
206
|
// Initialize the chart
|
|
@@ -224,20 +230,24 @@ var Heatmap = function Heatmap(props) {
|
|
|
224
230
|
}
|
|
225
231
|
|
|
226
232
|
// Add click event
|
|
227
|
-
|
|
233
|
+
var handleClick = function handleClick(event) {
|
|
234
|
+
var _onClickRef$current;
|
|
235
|
+
(_onClickRef$current = onClickRef.current) === null || _onClickRef$current === void 0 || _onClickRef$current.call(onClickRef, event);
|
|
236
|
+
};
|
|
237
|
+
if (hasOnClick) {
|
|
228
238
|
var _chartInstanceRef$cur2;
|
|
229
|
-
(_chartInstanceRef$cur2 = chartInstanceRef.current) === null || _chartInstanceRef$cur2 === void 0 || _chartInstanceRef$cur2.on("click",
|
|
239
|
+
(_chartInstanceRef$cur2 = chartInstanceRef.current) === null || _chartInstanceRef$cur2 === void 0 || _chartInstanceRef$cur2.on("click", handleClick);
|
|
230
240
|
}
|
|
231
241
|
|
|
232
242
|
// Cleanup function
|
|
233
243
|
return function () {
|
|
234
244
|
window.removeEventListener("resize", handleResize);
|
|
235
|
-
if (
|
|
245
|
+
if (hasOnClick) {
|
|
236
246
|
var _chartInstanceRef$cur3;
|
|
237
|
-
(_chartInstanceRef$cur3 = chartInstanceRef.current) === null || _chartInstanceRef$cur3 === void 0 || _chartInstanceRef$cur3.off("click",
|
|
247
|
+
(_chartInstanceRef$cur3 = chartInstanceRef.current) === null || _chartInstanceRef$cur3 === void 0 || _chartInstanceRef$cur3.off("click", handleClick);
|
|
238
248
|
}
|
|
239
249
|
};
|
|
240
|
-
}, [chartOption, handleResize, onChartRef,
|
|
250
|
+
}, [chartOption, handleResize, onChartRef, onClickRef, hasOnClick, containerReady]);
|
|
241
251
|
|
|
242
252
|
// Clean up resources when the component unmounts
|
|
243
253
|
useEffect(function () {
|
|
@@ -16,6 +16,7 @@ import { autoScrollByItem } from "../_utils/autoSmooth";
|
|
|
16
16
|
import { buildCartesianSeriesOptions, createDefaultCategoryXAxis, createDefaultValueYAxis, getSliderShow, percentWindowToIndexWindow, resolveScrollConfig } from "../_utils/cartesian";
|
|
17
17
|
import { resolveChartChrome } from "../_utils/chartTheme";
|
|
18
18
|
import useIsDark from "../../../hooks/useIsDark";
|
|
19
|
+
import useLatestRef from "../../../hooks/useLatestRef";
|
|
19
20
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
20
21
|
var ChartLine = function ChartLine(props) {
|
|
21
22
|
var className = props.className,
|
|
@@ -62,6 +63,30 @@ var ChartLine = function ChartLine(props) {
|
|
|
62
63
|
return resolveChartChrome(isDark);
|
|
63
64
|
}, [isDark]);
|
|
64
65
|
|
|
66
|
+
// 回调 prop 一律走 useLatestRef,不进依赖数组:消费方传内联箭头(React 里最常见的
|
|
67
|
+
// 写法)时每次渲染都是新引用,进依赖数组会让「init + setOption(notMerge)」整段重跑,
|
|
68
|
+
// 还会把当前可视窗口再同步一次给父级 —— 父级据此改 state 就是死循环。
|
|
69
|
+
// 但「有没有传回调」决定要不要注册监听,所以单独拆成布尔量进依赖数组,
|
|
70
|
+
// 这样「从无到有传入回调」仍会重新注册,不会漏。
|
|
71
|
+
var onClickRef = useLatestRef(onClick);
|
|
72
|
+
var onLegendSelectChangedRef = useLatestRef(onLegendSelectChanged);
|
|
73
|
+
var onDataZoomWindowChangedRef = useLatestRef(onDataZoomWindowChanged);
|
|
74
|
+
var hasOnClick = !!onClick;
|
|
75
|
+
var hasOnLegendSelectChanged = !!onLegendSelectChanged;
|
|
76
|
+
var hasOnDataZoomWindowChanged = !!onDataZoomWindowChanged;
|
|
77
|
+
// 已通知过父级的窗口用 ref 记账(不参与渲染):窗口没变就不再通知,
|
|
78
|
+
// 掐断「通知 → 父级重算坐标轴 → chartOption 变 → effect 重跑 → 再通知」的自激回路
|
|
79
|
+
var notifiedZoomWindowRef = useRef(null);
|
|
80
|
+
var emitZoomWindow = useCallback(function (next) {
|
|
81
|
+
var _onDataZoomWindowChan;
|
|
82
|
+
var prev = notifiedZoomWindowRef.current;
|
|
83
|
+
if (prev && prev.startIndex === next.startIndex && prev.endIndex === next.endIndex) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
notifiedZoomWindowRef.current = next;
|
|
87
|
+
(_onDataZoomWindowChan = onDataZoomWindowChangedRef.current) === null || _onDataZoomWindowChan === void 0 || _onDataZoomWindowChan.call(onDataZoomWindowChangedRef, next);
|
|
88
|
+
}, [onDataZoomWindowChangedRef]);
|
|
89
|
+
|
|
65
90
|
// Cache the chart option with useMemo
|
|
66
91
|
var chartOption = useMemo(function () {
|
|
67
92
|
var _xAxisData$length, _ref, _ref2;
|
|
@@ -236,16 +261,16 @@ var ChartLine = function ChartLine(props) {
|
|
|
236
261
|
}
|
|
237
262
|
|
|
238
263
|
// Sync the current visible window to the caller (on initial render and after restore), used to recalculate axes based on the displayed portion
|
|
239
|
-
if (
|
|
264
|
+
if (hasOnDataZoomWindowChanged) {
|
|
240
265
|
var _chart$getOption3, _xAxisData$length2;
|
|
241
266
|
var zooms = (_chart$getOption3 = chart.getOption()) === null || _chart$getOption3 === void 0 ? void 0 : _chart$getOption3.dataZoom;
|
|
242
267
|
var zoom = zooms === null || zooms === void 0 ? void 0 : zooms[0];
|
|
243
268
|
var totalLen = (_xAxisData$length2 = xAxisData === null || xAxisData === void 0 ? void 0 : xAxisData.length) !== null && _xAxisData$length2 !== void 0 ? _xAxisData$length2 : 0;
|
|
244
269
|
if (typeof (zoom === null || zoom === void 0 ? void 0 : zoom.start) === "number" && typeof (zoom === null || zoom === void 0 ? void 0 : zoom.end) === "number") {
|
|
245
|
-
|
|
270
|
+
emitZoomWindow(percentWindowToIndexWindow(zoom.start, zoom.end, totalLen));
|
|
246
271
|
} else {
|
|
247
272
|
// Without dataZoom (e.g. scrolling not enabled due to insufficient data) the window is the full range; sync once to avoid a stale old window
|
|
248
|
-
|
|
273
|
+
emitZoomWindow({
|
|
249
274
|
startIndex: 0,
|
|
250
275
|
endIndex: Math.max(0, totalLen - 1)
|
|
251
276
|
});
|
|
@@ -261,17 +286,22 @@ var ChartLine = function ChartLine(props) {
|
|
|
261
286
|
resizeObserverRef.current.observe(chartRef.current);
|
|
262
287
|
}
|
|
263
288
|
|
|
264
|
-
// Add click event
|
|
265
|
-
|
|
289
|
+
// Add click event(注册与否看布尔量,实际调用取最新引用)
|
|
290
|
+
var handleClick = function handleClick(event) {
|
|
291
|
+
var _onClickRef$current;
|
|
292
|
+
(_onClickRef$current = onClickRef.current) === null || _onClickRef$current === void 0 || _onClickRef$current.call(onClickRef, event);
|
|
293
|
+
};
|
|
294
|
+
if (hasOnClick) {
|
|
266
295
|
var _chartInstanceRef$cur2;
|
|
267
|
-
(_chartInstanceRef$cur2 = chartInstanceRef.current) === null || _chartInstanceRef$cur2 === void 0 || _chartInstanceRef$cur2.on("click",
|
|
296
|
+
(_chartInstanceRef$cur2 = chartInstanceRef.current) === null || _chartInstanceRef$cur2 === void 0 || _chartInstanceRef$cur2.on("click", handleClick);
|
|
268
297
|
}
|
|
269
298
|
|
|
270
299
|
// Legend selection event
|
|
271
300
|
var handleLegendSelectChanged = function handleLegendSelectChanged(params) {
|
|
272
|
-
|
|
301
|
+
var _onLegendSelectChange;
|
|
302
|
+
(_onLegendSelectChange = onLegendSelectChangedRef.current) === null || _onLegendSelectChange === void 0 || _onLegendSelectChange.call(onLegendSelectChangedRef, params.selected);
|
|
273
303
|
};
|
|
274
|
-
if (
|
|
304
|
+
if (hasOnLegendSelectChanged) {
|
|
275
305
|
var _chartInstanceRef$cur3;
|
|
276
306
|
(_chartInstanceRef$cur3 = chartInstanceRef.current) === null || _chartInstanceRef$cur3 === void 0 || _chartInstanceRef$cur3.on("legendselectchanged", handleLegendSelectChanged);
|
|
277
307
|
}
|
|
@@ -282,16 +312,16 @@ var ChartLine = function ChartLine(props) {
|
|
|
282
312
|
var raw = params;
|
|
283
313
|
var info = (_raw$batch$ = raw === null || raw === void 0 || (_raw$batch = raw.batch) === null || _raw$batch === void 0 ? void 0 : _raw$batch[0]) !== null && _raw$batch$ !== void 0 ? _raw$batch$ : raw;
|
|
284
314
|
if (typeof (info === null || info === void 0 ? void 0 : info.startValue) === "number" && typeof (info === null || info === void 0 ? void 0 : info.endValue) === "number") {
|
|
285
|
-
|
|
315
|
+
emitZoomWindow({
|
|
286
316
|
startIndex: Math.max(0, Math.round(info.startValue)),
|
|
287
317
|
endIndex: Math.max(0, Math.round(info.endValue))
|
|
288
318
|
});
|
|
289
319
|
} else if (typeof (info === null || info === void 0 ? void 0 : info.start) === "number" && typeof (info === null || info === void 0 ? void 0 : info.end) === "number") {
|
|
290
320
|
var _xAxisData$length3;
|
|
291
|
-
|
|
321
|
+
emitZoomWindow(percentWindowToIndexWindow(info.start, info.end, (_xAxisData$length3 = xAxisData === null || xAxisData === void 0 ? void 0 : xAxisData.length) !== null && _xAxisData$length3 !== void 0 ? _xAxisData$length3 : 0));
|
|
292
322
|
}
|
|
293
323
|
};
|
|
294
|
-
if (
|
|
324
|
+
if (hasOnDataZoomWindowChanged) {
|
|
295
325
|
var _chartInstanceRef$cur4;
|
|
296
326
|
(_chartInstanceRef$cur4 = chartInstanceRef.current) === null || _chartInstanceRef$cur4 === void 0 || _chartInstanceRef$cur4.on("datazoom", handleDataZoom);
|
|
297
327
|
}
|
|
@@ -319,15 +349,15 @@ var ChartLine = function ChartLine(props) {
|
|
|
319
349
|
// Cleanup function
|
|
320
350
|
return function () {
|
|
321
351
|
window.removeEventListener("resize", handleResize);
|
|
322
|
-
if (
|
|
352
|
+
if (hasOnClick) {
|
|
323
353
|
var _chartInstanceRef$cur5;
|
|
324
|
-
(_chartInstanceRef$cur5 = chartInstanceRef.current) === null || _chartInstanceRef$cur5 === void 0 || _chartInstanceRef$cur5.off("click",
|
|
354
|
+
(_chartInstanceRef$cur5 = chartInstanceRef.current) === null || _chartInstanceRef$cur5 === void 0 || _chartInstanceRef$cur5.off("click", handleClick);
|
|
325
355
|
}
|
|
326
|
-
if (
|
|
356
|
+
if (hasOnLegendSelectChanged) {
|
|
327
357
|
var _chartInstanceRef$cur6;
|
|
328
358
|
(_chartInstanceRef$cur6 = chartInstanceRef.current) === null || _chartInstanceRef$cur6 === void 0 || _chartInstanceRef$cur6.off("legendselectchanged", handleLegendSelectChanged);
|
|
329
359
|
}
|
|
330
|
-
if (
|
|
360
|
+
if (hasOnDataZoomWindowChanged) {
|
|
331
361
|
var _chartInstanceRef$cur7;
|
|
332
362
|
(_chartInstanceRef$cur7 = chartInstanceRef.current) === null || _chartInstanceRef$cur7 === void 0 || _chartInstanceRef$cur7.off("datazoom", handleDataZoom);
|
|
333
363
|
}
|
|
@@ -336,7 +366,7 @@ var ChartLine = function ChartLine(props) {
|
|
|
336
366
|
legendScrollRef.current = null;
|
|
337
367
|
}
|
|
338
368
|
};
|
|
339
|
-
}, [chartOption, handleResize,
|
|
369
|
+
}, [chartOption, handleResize, onClickRef, onLegendSelectChangedRef, hasOnClick, hasOnLegendSelectChanged, hasOnDataZoomWindowChanged, emitZoomWindow, xAxisData, enableLegendAutoScroll, legendVisibleCount, legendScrollInterval,
|
|
340
370
|
// 图例是否接管滚轮由它推导,漏了会拿到过期的滚动配置
|
|
341
371
|
normalizedScroll, containerReady]);
|
|
342
372
|
|
|
@@ -356,13 +386,13 @@ var ChartLine = function ChartLine(props) {
|
|
|
356
386
|
startIndex: normalizedScroll.startIndex,
|
|
357
387
|
autoPlay: normalizedScroll.autoScroll,
|
|
358
388
|
enableWheelScroll: enableWheelScroll,
|
|
359
|
-
onWindowChange:
|
|
360
|
-
return
|
|
389
|
+
onWindowChange: hasOnDataZoomWindowChanged ? function (startPercent, endPercent) {
|
|
390
|
+
return emitZoomWindow(percentWindowToIndexWindow(startPercent, endPercent, xAxisData.length));
|
|
361
391
|
} : undefined
|
|
362
392
|
}),
|
|
363
393
|
dispose = _autoScrollByItem.dispose;
|
|
364
394
|
return dispose;
|
|
365
|
-
}, [dataZoom, normalizedScroll, sliderDataZoom, xAxisData,
|
|
395
|
+
}, [dataZoom, normalizedScroll, sliderDataZoom, xAxisData, hasOnDataZoomWindowChanged, emitZoomWindow]);
|
|
366
396
|
|
|
367
397
|
// Clean up resources when the component unmounts
|
|
368
398
|
useEffect(function () {
|
|
@@ -92,6 +92,12 @@ var ChartPie3D = function ChartPie3D(props) {
|
|
|
92
92
|
});
|
|
93
93
|
var onChartRef = useLatestRef(onChart);
|
|
94
94
|
|
|
95
|
+
// onClick 不进依赖数组:消费方传内联箭头时每次渲染都是新引用,effect 跟着重跑会重建
|
|
96
|
+
// 3D 饼的 option 并重播动画。注册与否看布尔量(保证「从无到有传入」仍会注册),
|
|
97
|
+
// 实际调用取 ref 里的最新引用。
|
|
98
|
+
var onClickRef = useLatestRef(onClick);
|
|
99
|
+
var hasOnClick = !!onClick;
|
|
100
|
+
|
|
95
101
|
// 回调 prop 不进依赖数组:消费方传内联箭头时每次渲染都是新引用,effect 会跟着
|
|
96
102
|
// 重跑并再调一次回调 —— 回调里 setState 就是死循环(详见 Input/TextArea 的说明)
|
|
97
103
|
useEffect(function () {
|
|
@@ -112,20 +118,24 @@ var ChartPie3D = function ChartPie3D(props) {
|
|
|
112
118
|
}
|
|
113
119
|
chart.on("mouseover", handleMouseOver);
|
|
114
120
|
chart.on("globalout", handleGlobalOut);
|
|
115
|
-
|
|
116
|
-
|
|
121
|
+
var handleClick = function handleClick(event) {
|
|
122
|
+
var _onClickRef$current;
|
|
123
|
+
(_onClickRef$current = onClickRef.current) === null || _onClickRef$current === void 0 || _onClickRef$current.call(onClickRef, event);
|
|
124
|
+
};
|
|
125
|
+
if (hasOnClick) {
|
|
126
|
+
chart.on("click", handleClick);
|
|
117
127
|
}
|
|
118
128
|
return function () {
|
|
119
129
|
window.removeEventListener("resize", handleResize);
|
|
120
130
|
if (chart) {
|
|
121
131
|
chart.off("mouseover", handleMouseOver);
|
|
122
132
|
chart.off("globalout", handleGlobalOut);
|
|
123
|
-
if (
|
|
124
|
-
chart.off("click",
|
|
133
|
+
if (hasOnClick) {
|
|
134
|
+
chart.off("click", handleClick);
|
|
125
135
|
}
|
|
126
136
|
}
|
|
127
137
|
};
|
|
128
|
-
}, [chartOption, handleResize, handleMouseOver, handleGlobalOut, onChartRef,
|
|
138
|
+
}, [chartOption, handleResize, handleMouseOver, handleGlobalOut, onChartRef, onClickRef, hasOnClick, containerReady]);
|
|
129
139
|
useEffect(function () {
|
|
130
140
|
return function () {
|
|
131
141
|
if (resizeObserverRef.current) {
|
|
@@ -210,6 +210,12 @@ var ChartPie = function ChartPie(props) {
|
|
|
210
210
|
}, []);
|
|
211
211
|
var onChartRef = useLatestRef(onChart);
|
|
212
212
|
|
|
213
|
+
// onClick 不进依赖数组:消费方传内联箭头时每次渲染都是新引用,effect 跟着重跑就会
|
|
214
|
+
// 再走一遍 setOption(notMerge),动画重播、悬浮/高亮态被清掉。注册与否看布尔量,
|
|
215
|
+
// 这样「从无到有传入 onClick」仍会注册;实际调用取 ref 里的最新引用。
|
|
216
|
+
var onClickRef = useLatestRef(onClick);
|
|
217
|
+
var hasOnClick = !!onClick;
|
|
218
|
+
|
|
213
219
|
// 回调 prop 不进依赖数组:消费方传内联箭头时每次渲染都是新引用,effect 会跟着
|
|
214
220
|
// 重跑并再调一次回调 —— 回调里 setState 就是死循环(详见 Input/TextArea 的说明)
|
|
215
221
|
// Initialize the chart
|
|
@@ -239,9 +245,13 @@ var ChartPie = function ChartPie(props) {
|
|
|
239
245
|
}
|
|
240
246
|
|
|
241
247
|
// Add click event
|
|
242
|
-
|
|
248
|
+
var handleClick = function handleClick(event) {
|
|
249
|
+
var _onClickRef$current;
|
|
250
|
+
(_onClickRef$current = onClickRef.current) === null || _onClickRef$current === void 0 || _onClickRef$current.call(onClickRef, event);
|
|
251
|
+
};
|
|
252
|
+
if (hasOnClick) {
|
|
243
253
|
var _chartInstanceRef$cur2;
|
|
244
|
-
(_chartInstanceRef$cur2 = chartInstanceRef.current) === null || _chartInstanceRef$cur2 === void 0 || _chartInstanceRef$cur2.on("click",
|
|
254
|
+
(_chartInstanceRef$cur2 = chartInstanceRef.current) === null || _chartInstanceRef$cur2 === void 0 || _chartInstanceRef$cur2.on("click", handleClick);
|
|
245
255
|
}
|
|
246
256
|
|
|
247
257
|
// Legend auto-scroll
|
|
@@ -262,9 +272,9 @@ var ChartPie = function ChartPie(props) {
|
|
|
262
272
|
// Cleanup function
|
|
263
273
|
return function () {
|
|
264
274
|
window.removeEventListener("resize", handleResize);
|
|
265
|
-
if (
|
|
275
|
+
if (hasOnClick) {
|
|
266
276
|
var _chartInstanceRef$cur3;
|
|
267
|
-
(_chartInstanceRef$cur3 = chartInstanceRef.current) === null || _chartInstanceRef$cur3 === void 0 || _chartInstanceRef$cur3.off("click",
|
|
277
|
+
(_chartInstanceRef$cur3 = chartInstanceRef.current) === null || _chartInstanceRef$cur3 === void 0 || _chartInstanceRef$cur3.off("click", handleClick);
|
|
268
278
|
}
|
|
269
279
|
|
|
270
280
|
// Clean up legend scrolling
|
|
@@ -273,7 +283,7 @@ var ChartPie = function ChartPie(props) {
|
|
|
273
283
|
legendScrollRef.current = null;
|
|
274
284
|
}
|
|
275
285
|
};
|
|
276
|
-
}, [chartOption, handleResize, onChartRef,
|
|
286
|
+
}, [chartOption, handleResize, onChartRef, onClickRef, hasOnClick, enableLegendAutoScroll, seriesData, legendVisibleCount, legendScrollInterval, containerReady]);
|
|
277
287
|
|
|
278
288
|
// Clean up resources when the component unmounts
|
|
279
289
|
useEffect(function () {
|
|
@@ -14,6 +14,7 @@ import React, { useCallback, useEffect, useMemo, useRef } from "react";
|
|
|
14
14
|
import useContainerReady from "../_hooks/useContainerReady";
|
|
15
15
|
import styles from "../index.module.scss";
|
|
16
16
|
import * as echarts from "echarts";
|
|
17
|
+
import useLatestRef from "../../../hooks/useLatestRef";
|
|
17
18
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
18
19
|
var Sankey = function Sankey(props) {
|
|
19
20
|
var className = props.className,
|
|
@@ -103,6 +104,13 @@ var Sankey = function Sankey(props) {
|
|
|
103
104
|
return option;
|
|
104
105
|
}, [seriesData, seriesLinks, series]);
|
|
105
106
|
|
|
107
|
+
// getImage 只是「出图后把 dataURL 交出去」的出口,既不决定图怎么画,
|
|
108
|
+
// 也不该决定要不要重画。它进依赖数组会让 effect 跟着重跑 → setOption(notMerge)
|
|
109
|
+
// → 图重绘 → 再触发一次 finished → 再回调;消费方把图存进 state 就是死循环。
|
|
110
|
+
// 而且 finished 监听只在首次 init 时注册,闭包里锁死的是首帧的 getImage,
|
|
111
|
+
// 后续换了引用永远调不到 —— 依赖数组写了它也没用,是条死依赖。走 ref 两个问题一起解决。
|
|
112
|
+
var getImageRef = useLatestRef(getImage);
|
|
113
|
+
|
|
106
114
|
// Callback handling chart resize
|
|
107
115
|
var handleResize = useCallback(function () {
|
|
108
116
|
var _chartInstanceRef$cur;
|
|
@@ -125,7 +133,8 @@ var Sankey = function Sankey(props) {
|
|
|
125
133
|
|
|
126
134
|
// Attach the finished event listener on first initialization
|
|
127
135
|
chart.on("finished", function () {
|
|
128
|
-
|
|
136
|
+
var _getImageRef$current;
|
|
137
|
+
(_getImageRef$current = getImageRef.current) === null || _getImageRef$current === void 0 || _getImageRef$current.call(getImageRef, chart.getDataURL({
|
|
129
138
|
type: "png",
|
|
130
139
|
pixelRatio: 1,
|
|
131
140
|
backgroundColor: "#fff"
|
|
@@ -149,7 +158,7 @@ var Sankey = function Sankey(props) {
|
|
|
149
158
|
return function () {
|
|
150
159
|
window.removeEventListener("resize", handleResize);
|
|
151
160
|
};
|
|
152
|
-
}, [chartOption, handleResize,
|
|
161
|
+
}, [chartOption, handleResize, getImageRef, containerReady]);
|
|
153
162
|
|
|
154
163
|
// Clean up resources on unmount
|
|
155
164
|
useEffect(function () {
|