@hsu-react/ui 0.0.7 → 0.0.9
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/Chart/Bar/index.d.ts +5 -1
- package/es/components/Chart/Bar/index.js +84 -9
- package/es/components/Chart/Line/index.d.ts +5 -1
- package/es/components/Chart/Line/index.js +84 -9
- package/es/components/Chart/_utils/autoSmooth.d.ts +2 -0
- package/es/components/Chart/_utils/autoSmooth.js +12 -2
- package/es/components/Chart/_utils/cartesian.d.ts +11 -0
- package/es/components/Chart/_utils/cartesian.js +19 -0
- package/es/components/Chart/chartUtils/chartTooltipFormatter.d.ts +2 -0
- package/es/components/Chart/chartUtils/chartTooltipFormatter.js +13 -3
- package/es/components/Chart/chartUtils/index.d.ts +5 -2
- package/es/components/Chart/chartUtils/index.js +3 -1
- package/es/components/Chart/chartUtils/useDataZoomWindow.d.ts +19 -0
- package/es/components/Chart/chartUtils/useDataZoomWindow.js +37 -0
- package/es/components/Chart/chartUtils/useLegendSelection.d.ts +14 -0
- package/es/components/Chart/chartUtils/useLegendSelection.js +35 -0
- package/es/components/Modal/index.module.scss +1 -0
- package/es/components/Panel/ListPanel/ListModalPanel/index.js +33 -5
- package/es/components/Panel/ListPanel/ListModalPanel/index.module.scss +17 -2
- package/es/components/Panel/ListPanel/index.module.scss +11 -12
- package/lib/components/Chart/Bar/index.d.ts +5 -1
- package/lib/components/Chart/Bar/index.js +68 -4
- package/lib/components/Chart/Line/index.d.ts +5 -1
- package/lib/components/Chart/Line/index.js +68 -4
- package/lib/components/Chart/_utils/autoSmooth.d.ts +2 -0
- package/lib/components/Chart/_utils/autoSmooth.js +11 -1
- package/lib/components/Chart/_utils/cartesian.d.ts +11 -0
- package/lib/components/Chart/_utils/cartesian.js +21 -1
- package/lib/components/Chart/chartUtils/chartTooltipFormatter.d.ts +2 -0
- package/lib/components/Chart/chartUtils/chartTooltipFormatter.js +5 -3
- package/lib/components/Chart/chartUtils/index.d.ts +5 -2
- package/lib/components/Chart/chartUtils/index.js +14 -0
- package/lib/components/Chart/chartUtils/useDataZoomWindow.d.ts +19 -0
- package/lib/components/Chart/chartUtils/useDataZoomWindow.js +31 -0
- package/lib/components/Chart/chartUtils/useLegendSelection.d.ts +14 -0
- package/lib/components/Chart/chartUtils/useLegendSelection.js +26 -0
- package/lib/components/Modal/index.module.scss +1 -0
- package/lib/components/Panel/ListPanel/ListModalPanel/index.js +21 -2
- package/lib/components/Panel/ListPanel/ListModalPanel/index.module.scss +17 -2
- package/lib/components/Panel/ListPanel/index.module.scss +11 -12
- package/package.json +2 -2
- package/src/components/Chart/Bar/index.tsx +132 -2
- package/src/components/Chart/Line/index.tsx +132 -2
- package/src/components/Chart/_utils/autoSmooth.ts +181 -164
- package/src/components/Chart/_utils/cartesian.ts +28 -0
- package/src/components/Chart/chartUtils/chartTooltipFormatter.ts +11 -2
- package/src/components/Chart/chartUtils/index.ts +53 -37
- package/src/components/Chart/chartUtils/useDataZoomWindow.ts +61 -0
- package/src/components/Chart/chartUtils/useLegendSelection.ts +35 -0
- package/src/components/Modal/index.module.scss +1 -0
- package/src/components/Panel/ListPanel/ListModalPanel/index.module.scss +17 -2
- package/src/components/Panel/ListPanel/ListModalPanel/index.tsx +261 -233
- package/src/components/Panel/ListPanel/index.module.scss +11 -12
|
@@ -1,164 +1,181 @@
|
|
|
1
|
-
import * as echarts from "echarts";
|
|
2
|
-
|
|
3
|
-
export interface AutoScrollByItemProps {
|
|
4
|
-
chart: echarts.ECharts;
|
|
5
|
-
xAxisData?: Array<string>;
|
|
6
|
-
windowSize?: number;
|
|
7
|
-
interval?: number;
|
|
8
|
-
startIndex?: number;
|
|
9
|
-
autoPlay?: boolean;
|
|
10
|
-
enableWheelScroll?: boolean;
|
|
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
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
chart.
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
if (
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
}
|
|
1
|
+
import * as echarts from "echarts";
|
|
2
|
+
|
|
3
|
+
export interface AutoScrollByItemProps {
|
|
4
|
+
chart: echarts.ECharts;
|
|
5
|
+
xAxisData?: Array<string>;
|
|
6
|
+
windowSize?: number;
|
|
7
|
+
interval?: number;
|
|
8
|
+
startIndex?: number;
|
|
9
|
+
autoPlay?: boolean;
|
|
10
|
+
enableWheelScroll?: boolean;
|
|
11
|
+
/** 窗口变化回调(创建同步、自动滚动、滚轮、resize 均触发),参数为当前窗口 start/end 百分比 */
|
|
12
|
+
onWindowChange?: (startPercent: number, endPercent: number) => void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function autoScrollByItem(props: AutoScrollByItemProps) {
|
|
16
|
+
const {
|
|
17
|
+
chart,
|
|
18
|
+
xAxisData,
|
|
19
|
+
windowSize = 10,
|
|
20
|
+
interval = 2000,
|
|
21
|
+
startIndex = 0,
|
|
22
|
+
autoPlay = true,
|
|
23
|
+
enableWheelScroll = true,
|
|
24
|
+
onWindowChange,
|
|
25
|
+
} = props;
|
|
26
|
+
const total = xAxisData?.length ?? 0;
|
|
27
|
+
if (total <= 0) {
|
|
28
|
+
return {
|
|
29
|
+
pause: () => {},
|
|
30
|
+
resume: () => {},
|
|
31
|
+
dispose: () => {},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const initialStartIndex = Math.max(
|
|
36
|
+
0,
|
|
37
|
+
Math.min(startIndex, Math.max(total - 1, 0)),
|
|
38
|
+
);
|
|
39
|
+
const stepPercent = total > 0 ? (1 / total) * 100 : 0;
|
|
40
|
+
const windowSizePercent = total > 0 ? (windowSize / total) * 100 : 100;
|
|
41
|
+
const initialStartPercent = total > 0 ? (initialStartIndex / total) * 100 : 0;
|
|
42
|
+
let start = initialStartPercent;
|
|
43
|
+
let end = Math.min(initialStartPercent + windowSizePercent, 100);
|
|
44
|
+
|
|
45
|
+
// 图表已有 dataZoom 窗口时(组件重渲染重建滚动器)从当前位置继续,
|
|
46
|
+
// 避免图例点选、坐标轴重算等触发的重渲染把已滚动位置重置回初始窗口
|
|
47
|
+
const currentZoom = (
|
|
48
|
+
chart.getOption() as { dataZoom?: Array<{ start?: number; end?: number }> }
|
|
49
|
+
)?.dataZoom?.[0];
|
|
50
|
+
if (
|
|
51
|
+
typeof currentZoom?.start === "number" &&
|
|
52
|
+
typeof currentZoom?.end === "number"
|
|
53
|
+
) {
|
|
54
|
+
start = currentZoom.start;
|
|
55
|
+
end = currentZoom.end;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const syncDataZoomRange = () => {
|
|
59
|
+
const option = chart.getOption() as {
|
|
60
|
+
dataZoom?: Array<Record<string, unknown>>;
|
|
61
|
+
};
|
|
62
|
+
const currentDataZoom = option?.dataZoom;
|
|
63
|
+
if (!currentDataZoom?.length) return;
|
|
64
|
+
chart.setOption({
|
|
65
|
+
dataZoom: currentDataZoom.map((dz) => ({
|
|
66
|
+
...dz,
|
|
67
|
+
start,
|
|
68
|
+
end,
|
|
69
|
+
})),
|
|
70
|
+
});
|
|
71
|
+
onWindowChange?.(start, end);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
syncDataZoomRange();
|
|
75
|
+
|
|
76
|
+
let timer: NodeJS.Timeout | null = null;
|
|
77
|
+
if (autoPlay) {
|
|
78
|
+
timer = setInterval(tick, interval);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function tick() {
|
|
82
|
+
start += stepPercent;
|
|
83
|
+
end += stepPercent;
|
|
84
|
+
|
|
85
|
+
if (end > 100) {
|
|
86
|
+
start = 0;
|
|
87
|
+
end = windowSizePercent;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
syncDataZoomRange();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (autoPlay) {
|
|
94
|
+
chart.getZr().on("mouseover", pause);
|
|
95
|
+
chart.getZr().on("mouseout", resume);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function pause() {
|
|
99
|
+
if (timer) {
|
|
100
|
+
clearInterval(timer);
|
|
101
|
+
timer = null;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
function resume() {
|
|
105
|
+
if (autoPlay && !timer) {
|
|
106
|
+
timer = setInterval(tick, interval);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const chartDom = chart.getDom();
|
|
111
|
+
const applyWheelDelta = (delta: number) => {
|
|
112
|
+
if (delta === 0) return;
|
|
113
|
+
const direction = delta > 0 ? 1 : -1;
|
|
114
|
+
|
|
115
|
+
start += direction * stepPercent;
|
|
116
|
+
end += direction * stepPercent;
|
|
117
|
+
|
|
118
|
+
if (start < 0) {
|
|
119
|
+
start = 0;
|
|
120
|
+
end = windowSizePercent;
|
|
121
|
+
}
|
|
122
|
+
if (end > 100) {
|
|
123
|
+
end = 100;
|
|
124
|
+
start = Math.max(0, 100 - windowSizePercent);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
syncDataZoomRange();
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
function handleWheel(event: Event) {
|
|
131
|
+
if (!enableWheelScroll) return;
|
|
132
|
+
const wheelEvent = event as WheelEvent;
|
|
133
|
+
wheelEvent.preventDefault();
|
|
134
|
+
applyWheelDelta(wheelEvent.deltaY);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function handleZrMouseWheel(params: unknown) {
|
|
138
|
+
if (!enableWheelScroll) return;
|
|
139
|
+
const eventLike = (params as { event?: Record<string, unknown> })?.event;
|
|
140
|
+
const nativeEvent = eventLike?.event as WheelEvent | undefined;
|
|
141
|
+
const deltaFromNative = nativeEvent?.deltaY;
|
|
142
|
+
const deltaFromEventLike =
|
|
143
|
+
(eventLike?.deltaY as number | undefined) ??
|
|
144
|
+
(eventLike?.zrDelta as number | undefined);
|
|
145
|
+
const wheelDelta = eventLike?.wheelDelta as number | undefined;
|
|
146
|
+
const resolvedDelta =
|
|
147
|
+
deltaFromNative ??
|
|
148
|
+
deltaFromEventLike ??
|
|
149
|
+
(typeof wheelDelta === "number" ? -wheelDelta : undefined);
|
|
150
|
+
|
|
151
|
+
if (typeof resolvedDelta !== "number") return;
|
|
152
|
+
nativeEvent?.preventDefault();
|
|
153
|
+
applyWheelDelta(resolvedDelta);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (enableWheelScroll) {
|
|
157
|
+
chartDom.addEventListener("wheel", handleWheel, { passive: false });
|
|
158
|
+
chart.getZr().on("mousewheel", handleZrMouseWheel);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const handleWindowResize = () => {
|
|
162
|
+
chart.resize();
|
|
163
|
+
syncDataZoomRange();
|
|
164
|
+
};
|
|
165
|
+
window.addEventListener("resize", handleWindowResize);
|
|
166
|
+
|
|
167
|
+
function dispose() {
|
|
168
|
+
pause();
|
|
169
|
+
if (autoPlay) {
|
|
170
|
+
chart.getZr().off("mouseover", pause);
|
|
171
|
+
chart.getZr().off("mouseout", resume);
|
|
172
|
+
}
|
|
173
|
+
if (enableWheelScroll) {
|
|
174
|
+
chartDom.removeEventListener("wheel", handleWheel);
|
|
175
|
+
chart.getZr().off("mousewheel", handleZrMouseWheel);
|
|
176
|
+
}
|
|
177
|
+
window.removeEventListener("resize", handleWindowResize);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return { pause, resume, dispose };
|
|
181
|
+
}
|
|
@@ -21,6 +21,34 @@ export interface NormalizedScrollConfig {
|
|
|
21
21
|
wheelModeWhenSliderHidden: "scroll" | "none";
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
/** dataZoom 当前可见窗口对应的 x 轴索引区间(闭区间) */
|
|
25
|
+
export interface DataZoomIndexWindow {
|
|
26
|
+
startIndex: number;
|
|
27
|
+
endIndex: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* 把 dataZoom 的 start/end 百分比换算为 x 轴索引窗口。
|
|
32
|
+
* 与本组件族写入 dataZoom 的百分比约定一致(index / total * 100),
|
|
33
|
+
* 对 echarts 原生交互产生的百分比做外扩取整,边界最多多含一项,不影响坐标轴量级。
|
|
34
|
+
*/
|
|
35
|
+
export const percentWindowToIndexWindow = (
|
|
36
|
+
startPercent: number,
|
|
37
|
+
endPercent: number,
|
|
38
|
+
total: number,
|
|
39
|
+
): DataZoomIndexWindow => {
|
|
40
|
+
if (total <= 0) return { startIndex: 0, endIndex: 0 };
|
|
41
|
+
const startIndex = Math.max(
|
|
42
|
+
0,
|
|
43
|
+
Math.min(total - 1, Math.floor((startPercent / 100) * total)),
|
|
44
|
+
);
|
|
45
|
+
const endIndex = Math.max(
|
|
46
|
+
startIndex,
|
|
47
|
+
Math.min(total - 1, Math.ceil((endPercent / 100) * total) - 1),
|
|
48
|
+
);
|
|
49
|
+
return { startIndex, endIndex };
|
|
50
|
+
};
|
|
51
|
+
|
|
24
52
|
export const createDefaultCategoryXAxis = (
|
|
25
53
|
xAxisData?: Array<string>,
|
|
26
54
|
): ChartOptionType => ({
|
|
@@ -22,6 +22,8 @@ export interface ChartTooltipFormatterProps {
|
|
|
22
22
|
hideMarker?: boolean;
|
|
23
23
|
textStyle?: Record<string, unknown>;
|
|
24
24
|
unit?: string;
|
|
25
|
+
/** 多系列时按数值从大到小排序展示(大的在上) */
|
|
26
|
+
sortDescending?: boolean;
|
|
25
27
|
}
|
|
26
28
|
|
|
27
29
|
const chartTooltipFormatter = (props: ChartTooltipFormatterProps) => {
|
|
@@ -31,6 +33,7 @@ const chartTooltipFormatter = (props: ChartTooltipFormatterProps) => {
|
|
|
31
33
|
hideMarker,
|
|
32
34
|
textStyle = { fontSize: 14, color: "#666", fontWeight: 400 },
|
|
33
35
|
unit,
|
|
36
|
+
sortDescending,
|
|
34
37
|
} = props;
|
|
35
38
|
|
|
36
39
|
if (!Array.isArray(params)) {
|
|
@@ -77,13 +80,19 @@ const chartTooltipFormatter = (props: ChartTooltipFormatterProps) => {
|
|
|
77
80
|
`;
|
|
78
81
|
}
|
|
79
82
|
|
|
80
|
-
const
|
|
83
|
+
const sortedParams = sortDescending
|
|
84
|
+
? [...params].sort(
|
|
85
|
+
(a, b) => (Number(b.value) || 0) - (Number(a.value) || 0),
|
|
86
|
+
)
|
|
87
|
+
: params;
|
|
88
|
+
|
|
89
|
+
const items = sortedParams
|
|
81
90
|
?.map((item, idx) => {
|
|
82
91
|
const value = item.value ?? "";
|
|
83
92
|
|
|
84
93
|
return `
|
|
85
94
|
<div style="margin: 0 0 ${
|
|
86
|
-
idx ===
|
|
95
|
+
idx === sortedParams.length - 1 ? "0" : "10px"
|
|
87
96
|
} 0;line-height:1;">
|
|
88
97
|
<div style="margin: 0px 0 0;line-height:1;">
|
|
89
98
|
${hideMarker ? "" : `${item?.marker}`}
|
|
@@ -1,37 +1,53 @@
|
|
|
1
|
-
import chartTooltipFormatter from "./chartTooltipFormatter";
|
|
2
|
-
import {
|
|
3
|
-
TooltipParams,
|
|
4
|
-
ChartTooltipFormatterProps,
|
|
5
|
-
} from "./chartTooltipFormatter";
|
|
6
|
-
import {
|
|
7
|
-
autoScrollLegend,
|
|
8
|
-
AutoScrollLegendProps,
|
|
9
|
-
} from "../_utils/autoScrollLegend";
|
|
10
|
-
import { calculateAxisConfig } from "./calculateAxisConfig";
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
} from "./
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
1
|
+
import chartTooltipFormatter from "./chartTooltipFormatter";
|
|
2
|
+
import {
|
|
3
|
+
TooltipParams,
|
|
4
|
+
ChartTooltipFormatterProps,
|
|
5
|
+
} from "./chartTooltipFormatter";
|
|
6
|
+
import {
|
|
7
|
+
autoScrollLegend,
|
|
8
|
+
AutoScrollLegendProps,
|
|
9
|
+
} from "../_utils/autoScrollLegend";
|
|
10
|
+
import { calculateAxisConfig } from "./calculateAxisConfig";
|
|
11
|
+
import {
|
|
12
|
+
useLegendSelection,
|
|
13
|
+
LegendSelectionResult,
|
|
14
|
+
} from "./useLegendSelection";
|
|
15
|
+
import {
|
|
16
|
+
useDataZoomWindow,
|
|
17
|
+
DataZoomWindowOptions,
|
|
18
|
+
DataZoomWindowResult,
|
|
19
|
+
} from "./useDataZoomWindow";
|
|
20
|
+
import { DataZoomIndexWindow } from "../_utils/cartesian";
|
|
21
|
+
import {
|
|
22
|
+
MB_PER_GB,
|
|
23
|
+
MB_PER_TB,
|
|
24
|
+
trimAxisNumber,
|
|
25
|
+
chineseMagnitudeDivisor,
|
|
26
|
+
formatChineseMagnitudeTick,
|
|
27
|
+
mbDisplayTier,
|
|
28
|
+
formatMbAxisTick,
|
|
29
|
+
} from "./yAxisDisplayUnit";
|
|
30
|
+
|
|
31
|
+
export {
|
|
32
|
+
chartTooltipFormatter,
|
|
33
|
+
autoScrollLegend,
|
|
34
|
+
calculateAxisConfig,
|
|
35
|
+
useLegendSelection,
|
|
36
|
+
useDataZoomWindow,
|
|
37
|
+
MB_PER_GB,
|
|
38
|
+
MB_PER_TB,
|
|
39
|
+
trimAxisNumber,
|
|
40
|
+
chineseMagnitudeDivisor,
|
|
41
|
+
formatChineseMagnitudeTick,
|
|
42
|
+
mbDisplayTier,
|
|
43
|
+
formatMbAxisTick,
|
|
44
|
+
};
|
|
45
|
+
export type {
|
|
46
|
+
TooltipParams,
|
|
47
|
+
ChartTooltipFormatterProps,
|
|
48
|
+
AutoScrollLegendProps,
|
|
49
|
+
LegendSelectionResult,
|
|
50
|
+
DataZoomWindowOptions,
|
|
51
|
+
DataZoomWindowResult,
|
|
52
|
+
DataZoomIndexWindow,
|
|
53
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { useCallback, useState } from "react";
|
|
2
|
+
import { DataZoomIndexWindow } from "../_utils/cartesian";
|
|
3
|
+
|
|
4
|
+
export interface DataZoomWindowOptions {
|
|
5
|
+
/** 开关:是否按 dataZoom 当前可见窗口重算坐标轴,默认开启 */
|
|
6
|
+
enabled?: boolean;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface DataZoomWindowResult {
|
|
10
|
+
/** 当前可见窗口;开关关闭或尚未收到回调时为 null(表示全量) */
|
|
11
|
+
zoomWindow: DataZoomIndexWindow | null;
|
|
12
|
+
/** 传给 Chart.Bar / Chart.Line 的 onDataZoomWindowChanged;开关关闭时为 undefined(不绑定事件) */
|
|
13
|
+
onDataZoomWindowChanged?: (window: DataZoomIndexWindow) => void;
|
|
14
|
+
/** 按当前可见窗口裁剪系列数据,配合 calculateAxisConfig 只对展示部分重算坐标轴 */
|
|
15
|
+
sliceByZoomWindow: <T>(values?: T[] | null) => T[];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* dataZoom 可见窗口管理:配合 Chart.Bar / Chart.Line 的 onDataZoomWindowChanged,
|
|
20
|
+
* 在调用方按"当前可见窗口"裁剪数据后重算 Y 轴 min/max/interval(calculateAxisConfig),
|
|
21
|
+
* 实现滑块拖动/滚轮/自动滚动时坐标轴跟随展示部分动态重算;可与 useLegendSelection 叠加。
|
|
22
|
+
*/
|
|
23
|
+
export function useDataZoomWindow(
|
|
24
|
+
options?: DataZoomWindowOptions,
|
|
25
|
+
): DataZoomWindowResult {
|
|
26
|
+
const enabled = options?.enabled ?? true;
|
|
27
|
+
const [zoomWindow, setZoomWindow] = useState<DataZoomIndexWindow | null>(
|
|
28
|
+
null,
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
const onDataZoomWindowChanged = useCallback((next: DataZoomIndexWindow) => {
|
|
32
|
+
// 窗口未变化时保持原引用,避免重渲染 → 同步回调 → 再重渲染的循环
|
|
33
|
+
setZoomWindow((prev) =>
|
|
34
|
+
prev &&
|
|
35
|
+
prev.startIndex === next.startIndex &&
|
|
36
|
+
prev.endIndex === next.endIndex
|
|
37
|
+
? prev
|
|
38
|
+
: next,
|
|
39
|
+
);
|
|
40
|
+
}, []);
|
|
41
|
+
|
|
42
|
+
const effectiveWindow = enabled ? zoomWindow : null;
|
|
43
|
+
|
|
44
|
+
const sliceByZoomWindow = useCallback(
|
|
45
|
+
<T>(values?: T[] | null): T[] => {
|
|
46
|
+
if (!values) return [];
|
|
47
|
+
if (!effectiveWindow) return values;
|
|
48
|
+
return values.slice(
|
|
49
|
+
effectiveWindow.startIndex,
|
|
50
|
+
effectiveWindow.endIndex + 1,
|
|
51
|
+
);
|
|
52
|
+
},
|
|
53
|
+
[effectiveWindow],
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
zoomWindow: effectiveWindow,
|
|
58
|
+
onDataZoomWindowChanged: enabled ? onDataZoomWindowChanged : undefined,
|
|
59
|
+
sliceByZoomWindow,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { useCallback, useState } from "react";
|
|
2
|
+
|
|
3
|
+
export interface LegendSelectionResult {
|
|
4
|
+
/** 传给图表 legend.selected,保证重渲染(setOption notMerge)后隐藏状态不丢 */
|
|
5
|
+
legendSelected: Record<string, boolean>;
|
|
6
|
+
/** 传给图表 onLegendSelectChanged */
|
|
7
|
+
onLegendSelectChanged: (selected: Record<string, boolean>) => void;
|
|
8
|
+
/** 判断某系列当前是否可见(未点过的系列默认可见) */
|
|
9
|
+
isSeriesVisible: (name?: string | null) => boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* 图例选中状态管理:配合 Chart.Bar / Chart.Line 的 onLegendSelectChanged,
|
|
14
|
+
* 在调用方按"当前可见系列"重算 Y 轴 min/max/interval(calculateAxisConfig),
|
|
15
|
+
* 实现图例隐藏某一项后坐标轴自动重算。
|
|
16
|
+
*/
|
|
17
|
+
export function useLegendSelection(): LegendSelectionResult {
|
|
18
|
+
const [legendSelected, setLegendSelected] = useState<Record<string, boolean>>(
|
|
19
|
+
{},
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
const onLegendSelectChanged = useCallback(
|
|
23
|
+
(selected: Record<string, boolean>) => {
|
|
24
|
+
setLegendSelected({ ...selected });
|
|
25
|
+
},
|
|
26
|
+
[],
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const isSeriesVisible = useCallback(
|
|
30
|
+
(name?: string | null) => name == null || legendSelected[name] !== false,
|
|
31
|
+
[legendSelected],
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
return { legendSelected, onLegendSelectChanged, isSeriesVisible };
|
|
35
|
+
}
|
|
@@ -1,10 +1,25 @@
|
|
|
1
|
+
.modal {
|
|
2
|
+
// 定高让内部“height: 100%”链路可解析(antd Modal 默认内容自适应,内层设置 height/max-height 无效)
|
|
3
|
+
height: 700px;
|
|
4
|
+
|
|
5
|
+
&.fullscreen {
|
|
6
|
+
top: 0;
|
|
7
|
+
|
|
8
|
+
width: 100vw !important;
|
|
9
|
+
max-width: 100vw !important;
|
|
10
|
+
height: 100vh !important;
|
|
11
|
+
|
|
12
|
+
margin: 0;
|
|
13
|
+
padding-bottom: 0;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
1
17
|
.ListModalPanel {
|
|
2
18
|
display: flex;
|
|
3
19
|
flex-direction: column;
|
|
4
20
|
row-gap: 10px;
|
|
5
21
|
|
|
6
|
-
height:
|
|
7
|
-
max-height: 70vh;
|
|
22
|
+
height: 100%;
|
|
8
23
|
|
|
9
24
|
.search {
|
|
10
25
|
padding: 0px;
|