@agions/taroviz 1.11.1 → 2.0.3
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/CHANGELOG.md +245 -0
- package/README.md +104 -302
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/vendors.js +1 -0
- package/dist/cjs/vendors~echarts.js +1 -0
- package/dist/esm/index.js +1 -58151
- package/dist/esm/vendors.js +1 -0
- package/dist/esm/vendors~echarts.js +1 -0
- package/package.json +19 -25
- package/src/adapters/MiniAppAdapter.ts +136 -0
- package/src/adapters/__tests__/index.test.ts +1 -1
- package/src/adapters/h5/__tests__/index.test.ts +4 -2
- package/src/adapters/h5/index.ts +63 -64
- package/src/adapters/harmony/index.ts +23 -245
- package/src/adapters/index.ts +49 -45
- package/src/adapters/swan/index.ts +6 -69
- package/src/adapters/tt/index.ts +7 -70
- package/src/adapters/types.ts +25 -58
- package/src/adapters/weapp/index.ts +6 -69
- package/src/charts/__tests__/testUtils.tsx +87 -0
- package/src/charts/boxplot/__tests__/index.test.tsx +49 -103
- package/src/charts/boxplot/index.tsx +2 -1
- package/src/charts/boxplot/types.ts +17 -16
- package/src/charts/common/BaseChartWrapper.tsx +90 -82
- package/src/charts/common/__mocks__/BaseChartWrapper.tsx +17 -0
- package/src/charts/createChartComponent.tsx +36 -0
- package/src/charts/createOptionChartComponent.tsx +32 -0
- package/src/charts/funnel/__tests__/index.test.tsx +99 -0
- package/src/charts/funnel/index.tsx +60 -10
- package/src/charts/funnel/types.ts +6 -0
- package/src/charts/graph/__tests__/index.test.tsx +102 -33
- package/src/charts/graph/index.tsx +66 -9
- package/src/charts/graph/types.ts +6 -0
- package/src/charts/heatmap/__tests__/index.test.tsx +139 -0
- package/src/charts/heatmap/index.tsx +103 -10
- package/src/charts/heatmap/types.ts +6 -0
- package/src/charts/index.ts +74 -26
- package/src/charts/liquid/__tests__/index.test.tsx +52 -0
- package/src/charts/liquid/index.tsx +239 -182
- package/src/charts/liquid/types.ts +11 -11
- package/src/charts/parallel/__tests__/index.test.tsx +40 -67
- package/src/charts/parallel/index.tsx +2 -1
- package/src/charts/parallel/types.ts +19 -18
- package/src/charts/radar/__tests__/index.test.tsx +210 -0
- package/src/charts/radar/index.tsx +143 -10
- package/src/charts/radar/types.ts +13 -0
- package/src/charts/sankey/__tests__/index.test.tsx +124 -0
- package/src/charts/sankey/index.tsx +62 -10
- package/src/charts/sankey/types.ts +6 -0
- package/src/charts/tree/__tests__/index.test.tsx +71 -0
- package/src/charts/tree/index.tsx +5 -2
- package/src/charts/tree/types.ts +9 -9
- package/src/charts/types.ts +208 -106
- package/src/charts/utils.ts +9 -7
- package/src/charts/wordcloud/__tests__/index.test.tsx +98 -31
- package/src/charts/wordcloud/index.tsx +75 -9
- package/src/charts/wordcloud/types.ts +6 -0
- package/src/components/DataFilter/index.tsx +32 -10
- package/src/core/animation/types.ts +6 -6
- package/src/core/components/Annotation.tsx +6 -7
- package/src/core/components/BaseChart.tsx +110 -168
- package/src/core/components/ErrorBoundary.tsx +17 -4
- package/src/core/components/LazyChart.tsx +54 -55
- package/src/core/components/hooks/index.ts +6 -2
- package/src/core/components/hooks/useChartInit.ts +6 -3
- package/src/core/components/hooks/usePerformance.ts +8 -2
- package/src/core/components/hooks/useVirtualScroll.ts +2 -1
- package/src/core/index.ts +1 -1
- package/src/core/themes/ThemeManager.ts +1 -1
- package/src/core/types/common.ts +2 -1
- package/src/core/types/index.ts +0 -12
- package/src/core/types/platform.ts +3 -5
- package/src/core/utils/__tests__/deepClone.test.ts +317 -0
- package/src/core/utils/__tests__/index.test.ts +2 -1
- package/src/core/utils/chartInstances.ts +13 -0
- package/src/core/utils/common.ts +20 -29
- package/src/core/utils/deepClone.ts +114 -0
- package/src/core/utils/download.ts +128 -0
- package/src/core/utils/drillDown.ts +34 -353
- package/src/core/utils/drillDownHelpers.ts +426 -0
- package/src/core/utils/events.ts +12 -0
- package/src/core/utils/export/ExportUtils.ts +36 -67
- package/src/core/utils/format.ts +44 -0
- package/src/core/utils/index.ts +21 -154
- package/src/core/utils/merge.ts +25 -0
- package/src/core/utils/performance/PerformanceAnalyzer.ts +38 -21
- package/src/core/utils/performance/hooks.ts +7 -0
- package/src/core/utils/performance/index.ts +2 -0
- package/src/{hooks → core/utils/performance}/useAnimation.ts +45 -41
- package/src/core/utils/performance/useDataZoom.ts +324 -0
- package/src/{hooks → core/utils/performance}/usePerformance.ts +49 -41
- package/src/core/utils/performance/usePerformanceHooks.ts +278 -0
- package/src/core/utils/performanceUtils.ts +310 -0
- package/src/core/utils/runtime.ts +190 -0
- package/src/core/utils/setOptionUtils.ts +59 -0
- package/src/core/version.ts +14 -0
- package/src/editor/EnhancedThemeEditor.tsx +362 -540
- package/src/editor/ThemeEditor.tsx +55 -321
- package/src/editor/components/ThemeBasicSettings.tsx +113 -0
- package/src/editor/components/ThemeColorEditor.tsx +105 -0
- package/src/editor/components/ThemeSelector.tsx +70 -0
- package/src/editor/hooks/useThemeEditorState.ts +201 -0
- package/src/editor/index.ts +10 -2
- package/src/hooks/__tests__/index.test.tsx +3 -1
- package/src/hooks/chartConnectHelpers.ts +341 -0
- package/src/hooks/index.ts +55 -660
- package/src/hooks/types.ts +189 -0
- package/src/hooks/useChartAutoResize.ts +73 -0
- package/src/hooks/useChartConnect.ts +92 -238
- package/src/hooks/useChartDownload.ts +25 -27
- package/src/hooks/useChartHistory.ts +34 -49
- package/src/hooks/useChartInit.ts +59 -0
- package/src/hooks/useChartOptions.ts +259 -0
- package/src/hooks/useChartPerformance.ts +109 -0
- package/src/hooks/useChartSelection.ts +52 -49
- package/src/hooks/useChartTheme.ts +51 -0
- package/src/hooks/useDataTransform.ts +19 -4
- package/src/hooks/utils/chartDownloadUtils.ts +40 -53
- package/src/hooks/utils/dataTransformUtils.ts +22 -0
- package/src/index.ts +48 -34
- package/src/main.tsx +4 -9
- package/src/react-dom.d.ts +3 -3
- package/src/themes/index.ts +30 -855
- package/src/themes/palettes/blue-green.ts +13 -0
- package/src/themes/palettes/chalk.ts +13 -0
- package/src/themes/palettes/cyber.ts +44 -0
- package/src/themes/palettes/dark.ts +52 -0
- package/src/themes/palettes/default.ts +52 -0
- package/src/themes/palettes/elegant.ts +34 -0
- package/src/themes/palettes/forest.ts +13 -0
- package/src/themes/palettes/glass.ts +49 -0
- package/src/themes/palettes/golden.ts +13 -0
- package/src/themes/palettes/neon.ts +43 -0
- package/src/themes/palettes/ocean.ts +39 -0
- package/src/themes/palettes/pastel.ts +37 -0
- package/src/themes/palettes/purple-passion.ts +13 -0
- package/src/themes/palettes/retro.ts +33 -0
- package/src/themes/palettes/sunset.ts +40 -0
- package/src/themes/palettes/walden.ts +13 -0
- package/src/themes/registry.ts +184 -0
- package/src/themes/types.ts +213 -0
- package/src/charts/bar/__tests__/index.test.tsx +0 -113
- package/src/charts/bar/index.tsx +0 -14
- package/src/charts/candlestick/__tests__/index.test.tsx +0 -40
- package/src/charts/candlestick/index.tsx +0 -13
- package/src/charts/gauge/index.tsx +0 -14
- package/src/charts/line/__tests__/index.test.tsx +0 -107
- package/src/charts/line/index.tsx +0 -15
- package/src/charts/pie/__tests__/index.test.tsx +0 -112
- package/src/charts/pie/index.tsx +0 -14
- package/src/charts/scatter/index.tsx +0 -14
- package/src/charts/sunburst/index.tsx +0 -18
- package/src/charts/treemap/index.tsx +0 -18
- package/src/core/utils/codeGenerator/CodeGenerator.ts +0 -669
- package/src/core/utils/codeGenerator/index.ts +0 -13
- package/src/core/utils/codeGenerator/types.ts +0 -198
- package/src/core/utils/configGenerator/ConfigGenerator.ts +0 -583
- package/src/core/utils/configGenerator/index.ts +0 -13
- package/src/core/utils/configGenerator/types.ts +0 -445
- package/src/core/utils/debug/DebugPanel.tsx +0 -637
- package/src/core/utils/debug/debugger.ts +0 -322
- package/src/core/utils/debug/index.ts +0 -21
- package/src/core/utils/debug/types.ts +0 -142
- package/src/hooks/useDataZoom.ts +0 -323
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hooks 共享类型定义
|
|
3
|
+
*/
|
|
4
|
+
import type { EChartsOption } from 'echarts';
|
|
5
|
+
|
|
6
|
+
// ============================================================================
|
|
7
|
+
// 事件参数类型
|
|
8
|
+
// ============================================================================
|
|
9
|
+
|
|
10
|
+
/** click/hover 事件参数 */
|
|
11
|
+
export interface ChartPointerEventParams {
|
|
12
|
+
seriesIndex?: number;
|
|
13
|
+
dataIndex?: number;
|
|
14
|
+
name?: string | number;
|
|
15
|
+
value?: unknown;
|
|
16
|
+
[key: string]: unknown;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** select 事件参数 */
|
|
20
|
+
export interface ChartSelectEventParams {
|
|
21
|
+
seriesIndex?: number;
|
|
22
|
+
dataIndex?: number;
|
|
23
|
+
[key: string]: unknown;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** dataZoom 事件参数 */
|
|
27
|
+
export interface ChartDataZoomEventParams {
|
|
28
|
+
start?: number;
|
|
29
|
+
end?: number;
|
|
30
|
+
dataZoomIndex?: number;
|
|
31
|
+
dataZoomIndexs?: number[];
|
|
32
|
+
[key: string]: unknown;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** 事件处理器 */
|
|
36
|
+
export type EventHandler = (params?: unknown) => void;
|
|
37
|
+
|
|
38
|
+
// ============================================================================
|
|
39
|
+
// useChartConnect 类型
|
|
40
|
+
// ============================================================================
|
|
41
|
+
|
|
42
|
+
/** 联动事件类型 */
|
|
43
|
+
export type ConnectEventType = 'click' | 'hover' | 'select' | 'dataZoom';
|
|
44
|
+
|
|
45
|
+
/** 联动事件参数(联合类型) */
|
|
46
|
+
export type ConnectEventParams =
|
|
47
|
+
| ({ eventType: 'click' } & ChartPointerEventParams)
|
|
48
|
+
| ({ eventType: 'hover' } & ChartPointerEventParams)
|
|
49
|
+
| ({ eventType: 'select' } & ChartSelectEventParams)
|
|
50
|
+
| ({ eventType: 'dataZoom' } & ChartDataZoomEventParams);
|
|
51
|
+
|
|
52
|
+
/** 联动配置选项 */
|
|
53
|
+
export interface UseChartConnectOptions {
|
|
54
|
+
chartIds?: string[];
|
|
55
|
+
events?: ConnectEventType[];
|
|
56
|
+
autoBind?: boolean;
|
|
57
|
+
groupName?: string;
|
|
58
|
+
disabled?: boolean;
|
|
59
|
+
onConnect?: (
|
|
60
|
+
sourceId: string,
|
|
61
|
+
targetId: string,
|
|
62
|
+
payload: { eventType: ConnectEventType; params: unknown }
|
|
63
|
+
) => void;
|
|
64
|
+
eventFilter?: (event: string, params: unknown) => boolean;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** 联动返回值 */
|
|
68
|
+
export interface UseChartConnectReturn {
|
|
69
|
+
connect: (chartInstance: ChartInstance, chartId?: string) => void;
|
|
70
|
+
disconnect: (chartInstance: ChartInstance, chartId?: string) => void;
|
|
71
|
+
dispatchConnect: (
|
|
72
|
+
sourceId: string,
|
|
73
|
+
payload: {
|
|
74
|
+
eventType: ConnectEventType;
|
|
75
|
+
params: ChartPointerEventParams | ChartSelectEventParams | ChartDataZoomEventParams;
|
|
76
|
+
}
|
|
77
|
+
) => void;
|
|
78
|
+
connectAll: (charts: Array<{ instance: ChartInstance; id: string }>) => void;
|
|
79
|
+
disconnectAll: () => void;
|
|
80
|
+
isConnected: boolean;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// ============================================================================
|
|
84
|
+
// useDataZoom 类型
|
|
85
|
+
// ============================================================================
|
|
86
|
+
|
|
87
|
+
/** dataZoom 类型 */
|
|
88
|
+
export type DataZoomType = 'inside' | 'slider';
|
|
89
|
+
|
|
90
|
+
/** dataZoom 配置选项 */
|
|
91
|
+
export interface UseDataZoomOptions {
|
|
92
|
+
type?: DataZoomType;
|
|
93
|
+
start?: number;
|
|
94
|
+
end?: number;
|
|
95
|
+
minSpan?: number;
|
|
96
|
+
maxSpan?: number;
|
|
97
|
+
zoomLock?: boolean;
|
|
98
|
+
throttle?: number;
|
|
99
|
+
disabled?: boolean;
|
|
100
|
+
brushSelect?: boolean;
|
|
101
|
+
zoomMode?: 'scale' | 'mix';
|
|
102
|
+
resetOnUnmount?: boolean;
|
|
103
|
+
onZoomChange?: (range: { start: number; end: number }) => void;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** 缩放范围 */
|
|
107
|
+
export interface ZoomRange {
|
|
108
|
+
start: number;
|
|
109
|
+
end: number;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** dataZoom 返回值 */
|
|
113
|
+
export interface UseDataZoomReturn {
|
|
114
|
+
bindDataZoom: (chartInstance: ChartInstance) => void;
|
|
115
|
+
setZoomRange: (start: number, end: number) => void;
|
|
116
|
+
resetZoom: () => void;
|
|
117
|
+
getZoomRange: () => ZoomRange;
|
|
118
|
+
startValue: import('react').RefObject<number | string | Date | undefined>;
|
|
119
|
+
endValue: import('react').RefObject<number | string | Date | undefined>;
|
|
120
|
+
bindEvents: (chartInstance: ChartInstance) => void;
|
|
121
|
+
onZoomChange?: (range: ZoomRange) => void;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// ============================================================================
|
|
125
|
+
// ChartInstance
|
|
126
|
+
// ============================================================================
|
|
127
|
+
|
|
128
|
+
/** 图表实例类型 */
|
|
129
|
+
export interface ChartInstance {
|
|
130
|
+
setOption: (option: EChartsOption, notMerge?: boolean, lazyUpdate?: boolean) => void;
|
|
131
|
+
getOption: () => EChartsOption;
|
|
132
|
+
resize: (option?: { width?: number | string; height?: number | string }) => void;
|
|
133
|
+
on: (event: string, handler: EventHandler) => void;
|
|
134
|
+
off: (event: string, handler?: EventHandler) => void;
|
|
135
|
+
showLoading: (opts?: LoadingOptions) => void;
|
|
136
|
+
hideLoading: () => void;
|
|
137
|
+
dispose: () => void;
|
|
138
|
+
isDisposed: () => boolean;
|
|
139
|
+
getWidth: () => number;
|
|
140
|
+
getHeight: () => number;
|
|
141
|
+
getDom: () => HTMLElement;
|
|
142
|
+
getDataURL?: (options?: {
|
|
143
|
+
type?: string;
|
|
144
|
+
pixelRatio?: number;
|
|
145
|
+
backgroundColor?: string;
|
|
146
|
+
}) => string;
|
|
147
|
+
getSvgData?: () => string;
|
|
148
|
+
getCompressedDataURL?: (options?: { seriesIndex?: number; dimension?: number }) => string;
|
|
149
|
+
clear?: () => void;
|
|
150
|
+
dispatchAction?: (action: { type: string; [key: string]: unknown }) => void;
|
|
151
|
+
group?: string;
|
|
152
|
+
[key: string]: unknown;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/** 加载选项 */
|
|
156
|
+
export interface LoadingOptions {
|
|
157
|
+
text?: string;
|
|
158
|
+
color?: string;
|
|
159
|
+
textColor?: string;
|
|
160
|
+
maskColor?: string;
|
|
161
|
+
zlevel?: number;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// ============================================================================
|
|
165
|
+
// 图表配置类型
|
|
166
|
+
// ============================================================================
|
|
167
|
+
|
|
168
|
+
/** 图表配置 */
|
|
169
|
+
export interface ChartConfig {
|
|
170
|
+
width?: number | string;
|
|
171
|
+
height?: number | string;
|
|
172
|
+
renderer?: 'canvas' | 'svg';
|
|
173
|
+
theme?: string | Record<string, unknown>;
|
|
174
|
+
[key: string]: unknown;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/** 数据转换器 */
|
|
178
|
+
export type DataTransformer<T = unknown> = (data: T) => EChartsOption;
|
|
179
|
+
|
|
180
|
+
/** 响应式断点 */
|
|
181
|
+
export type Breakpoint = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
182
|
+
|
|
183
|
+
/** 断点配置 */
|
|
184
|
+
export interface BreakpointConfig {
|
|
185
|
+
width: number;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/** 主题切换回调 */
|
|
189
|
+
export type ThemeChangeCallback = (theme: string | Record<string, unknown>) => void;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useChartAutoResize - 图表自适应 Hook
|
|
3
|
+
* 监听容器尺寸变化并自动调整图表大小
|
|
4
|
+
*/
|
|
5
|
+
import { useEffect, useRef } from 'react';
|
|
6
|
+
import type { ChartInstance } from './types';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 图表自适应 Hook
|
|
10
|
+
* @param instance 图表实例
|
|
11
|
+
* @param options 配置选项
|
|
12
|
+
*/
|
|
13
|
+
export function useResize(
|
|
14
|
+
instance: ChartInstance | null,
|
|
15
|
+
options?: {
|
|
16
|
+
/** 延迟时间 (ms) */
|
|
17
|
+
delay?: number;
|
|
18
|
+
/** 最小宽度 */
|
|
19
|
+
minWidth?: number;
|
|
20
|
+
/** 最小高度 */
|
|
21
|
+
minHeight?: number;
|
|
22
|
+
/** 是否启用 */
|
|
23
|
+
enabled?: boolean;
|
|
24
|
+
}
|
|
25
|
+
) {
|
|
26
|
+
const { delay = 300, minWidth, minHeight, enabled = true } = options || {};
|
|
27
|
+
const timeoutRef = useRef<ReturnType<typeof setTimeout>>();
|
|
28
|
+
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
if (!instance || !enabled) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const handleResize = () => {
|
|
35
|
+
if (timeoutRef.current) {
|
|
36
|
+
clearTimeout(timeoutRef.current);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
timeoutRef.current = setTimeout(() => {
|
|
40
|
+
try {
|
|
41
|
+
const dom = instance.getDom?.();
|
|
42
|
+
if (dom) {
|
|
43
|
+
const { clientWidth, clientHeight } = dom;
|
|
44
|
+
if (minWidth && clientWidth < minWidth) return;
|
|
45
|
+
if (minHeight && clientHeight < minHeight) return;
|
|
46
|
+
}
|
|
47
|
+
instance.resize?.();
|
|
48
|
+
} catch (e) {
|
|
49
|
+
console.warn('Failed to resize chart:', e);
|
|
50
|
+
}
|
|
51
|
+
}, delay);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
window.addEventListener('resize', handleResize);
|
|
55
|
+
|
|
56
|
+
// 创建一个 ResizeObserver 来监听容器大小变化
|
|
57
|
+
const dom = instance.getDom?.();
|
|
58
|
+
if (dom && typeof ResizeObserver !== 'undefined') {
|
|
59
|
+
const observer = new ResizeObserver(handleResize);
|
|
60
|
+
observer.observe(dom);
|
|
61
|
+
return () => {
|
|
62
|
+
observer.disconnect();
|
|
63
|
+
window.removeEventListener('resize', handleResize);
|
|
64
|
+
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return () => {
|
|
69
|
+
window.removeEventListener('resize', handleResize);
|
|
70
|
+
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
|
71
|
+
};
|
|
72
|
+
}, [instance, delay, minWidth, minHeight, enabled]);
|
|
73
|
+
}
|
|
@@ -1,57 +1,36 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* useChartConnect - 图表联动 Hook
|
|
3
3
|
* 实现多个图表之间的联动(chartConnect),当一个图表被操作时,其他联动图表同步变化
|
|
4
|
+
*
|
|
5
|
+
* @refactor 已拆分为多个辅助函数,详见 chartConnectHelpers.ts
|
|
4
6
|
*/
|
|
5
|
-
import { useRef, useCallback, useEffect } from 'react';
|
|
6
|
-
import type {
|
|
7
|
+
import { useRef, useCallback, useEffect, useMemo } from 'react';
|
|
8
|
+
import type {
|
|
9
|
+
ChartInstance,
|
|
10
|
+
UseChartConnectOptions,
|
|
11
|
+
UseChartConnectReturn,
|
|
12
|
+
ConnectEventType,
|
|
13
|
+
} from './types';
|
|
14
|
+
import {
|
|
15
|
+
createConnectHandler,
|
|
16
|
+
dispatchToOthers,
|
|
17
|
+
bindChartEvents,
|
|
18
|
+
unbindChartEvents,
|
|
19
|
+
connectChart,
|
|
20
|
+
disconnectChart,
|
|
21
|
+
connectAllCharts,
|
|
22
|
+
disconnectAllCharts,
|
|
23
|
+
dispatchConnectEvent,
|
|
24
|
+
type ChartConnectItem,
|
|
25
|
+
type EventHandlersMap,
|
|
26
|
+
} from './chartConnectHelpers';
|
|
7
27
|
|
|
8
28
|
// ============================================================================
|
|
9
|
-
//
|
|
29
|
+
// 导出共享类型(从 types.ts re-export)
|
|
10
30
|
// ============================================================================
|
|
11
31
|
|
|
12
|
-
/**
|
|
13
|
-
export type
|
|
14
|
-
|
|
15
|
-
/** 联动配置选项 */
|
|
16
|
-
export interface UseChartConnectOptions {
|
|
17
|
-
/** 要绑定的图表 ID 列表 */
|
|
18
|
-
chartIds: string[];
|
|
19
|
-
/** 联动触发的事件类型 */
|
|
20
|
-
events?: ConnectEventType[];
|
|
21
|
-
/** 是否自动绑定/解绑 */
|
|
22
|
-
autoBind?: boolean;
|
|
23
|
-
/** 联动组名称 */
|
|
24
|
-
groupName?: string;
|
|
25
|
-
/** 是否禁用 */
|
|
26
|
-
disabled?: boolean;
|
|
27
|
-
/** 联动回调 */
|
|
28
|
-
onConnect?: (sourceId: string, targetId: string, payload: any) => void;
|
|
29
|
-
/** 事件过滤函数 */
|
|
30
|
-
eventFilter?: (event: string, params: any) => boolean;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/** 图表联动项 */
|
|
34
|
-
interface ChartConnectItem {
|
|
35
|
-
instance: ChartInstance;
|
|
36
|
-
id: string;
|
|
37
|
-
handlers: Map<string, any>;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/** 联动返回值 */
|
|
41
|
-
export interface UseChartConnectReturn {
|
|
42
|
-
/** 绑定图表到联动组 */
|
|
43
|
-
connect: (chartInstance: ChartInstance, chartId?: string) => void;
|
|
44
|
-
/** 解除图表联动 */
|
|
45
|
-
disconnect: (chartInstance: ChartInstance, chartId?: string) => void;
|
|
46
|
-
/** 触发联动事件 */
|
|
47
|
-
dispatchConnect: (sourceId: string, payload: any) => void;
|
|
48
|
-
/** 批量连接图表 */
|
|
49
|
-
connectAll: (charts: Array<{ instance: ChartInstance; id: string }>) => void;
|
|
50
|
-
/** 批量断开图表 */
|
|
51
|
-
disconnectAll: () => void;
|
|
52
|
-
/** 联动组是否已连接 */
|
|
53
|
-
isConnected: boolean;
|
|
54
|
-
}
|
|
32
|
+
/** 联动配置选项(从 types.ts 导出) */
|
|
33
|
+
export type { UseChartConnectOptions, UseChartConnectReturn } from './types';
|
|
55
34
|
|
|
56
35
|
// ============================================================================
|
|
57
36
|
// Hook 实现
|
|
@@ -63,9 +42,13 @@ export interface UseChartConnectReturn {
|
|
|
63
42
|
* @returns 图表联动操作接口
|
|
64
43
|
*/
|
|
65
44
|
export function useChartConnect(options: UseChartConnectOptions): UseChartConnectReturn {
|
|
45
|
+
const defaultEvents = useMemo<ConnectEventType[]>(
|
|
46
|
+
() => ['click', 'hover', 'select', 'dataZoom'],
|
|
47
|
+
[]
|
|
48
|
+
);
|
|
66
49
|
const {
|
|
67
50
|
chartIds = [],
|
|
68
|
-
events =
|
|
51
|
+
events = defaultEvents,
|
|
69
52
|
autoBind = false,
|
|
70
53
|
groupName,
|
|
71
54
|
disabled = false,
|
|
@@ -74,180 +57,93 @@ export function useChartConnect(options: UseChartConnectOptions): UseChartConnec
|
|
|
74
57
|
} = options;
|
|
75
58
|
|
|
76
59
|
// Refs
|
|
77
|
-
|
|
60
|
+
// 使用 useMemo 缓存初始值,避免每次渲染都创建新 Map
|
|
61
|
+
const chartsRef = useRef<Map<string, ChartConnectItem>>(
|
|
62
|
+
(() => {
|
|
63
|
+
const initialMap = new Map();
|
|
64
|
+
return initialMap;
|
|
65
|
+
})()
|
|
66
|
+
);
|
|
78
67
|
const connectedRef = useRef(false);
|
|
79
68
|
const optionsRef = useRef(options);
|
|
80
69
|
optionsRef.current = options;
|
|
81
70
|
|
|
82
|
-
|
|
83
|
-
|
|
71
|
+
const eventHandlersRef = useRef<EventHandlersMap>(
|
|
72
|
+
(() => {
|
|
73
|
+
const initialMap = new Map();
|
|
74
|
+
return initialMap;
|
|
75
|
+
})()
|
|
76
|
+
);
|
|
84
77
|
|
|
85
78
|
/**
|
|
86
79
|
* 创建联动事件处理器
|
|
87
80
|
*/
|
|
88
|
-
const
|
|
81
|
+
const createConnectHandlerCallback = useCallback(
|
|
89
82
|
(sourceId: string, eventType: ConnectEventType) => {
|
|
90
|
-
return (
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
// 分发联动事件到所有其他图表
|
|
99
|
-
dispatchToOthers(sourceId, eventType, params);
|
|
100
|
-
|
|
101
|
-
// 触发回调
|
|
102
|
-
const currentOptions = optionsRef.current;
|
|
103
|
-
if (currentOptions.onConnect) {
|
|
104
|
-
chartsRef.current.forEach((item, targetId) => {
|
|
105
|
-
if (targetId !== sourceId) {
|
|
106
|
-
currentOptions.onConnect?.(sourceId, targetId, { eventType, params });
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
};
|
|
83
|
+
return createConnectHandler(
|
|
84
|
+
sourceId,
|
|
85
|
+
eventType,
|
|
86
|
+
disabled,
|
|
87
|
+
eventFilter,
|
|
88
|
+
chartsRef,
|
|
89
|
+
optionsRef
|
|
90
|
+
);
|
|
111
91
|
},
|
|
112
|
-
[disabled, eventFilter]
|
|
92
|
+
[disabled, eventFilter, chartsRef, optionsRef]
|
|
113
93
|
);
|
|
114
94
|
|
|
115
95
|
/**
|
|
116
96
|
* 分发事件到其他图表
|
|
117
97
|
*/
|
|
118
|
-
const
|
|
119
|
-
(sourceId: string, eventType: ConnectEventType, params:
|
|
120
|
-
|
|
121
|
-
if (targetId === sourceId) return;
|
|
122
|
-
|
|
123
|
-
try {
|
|
124
|
-
switch (eventType) {
|
|
125
|
-
case 'click':
|
|
126
|
-
item.instance.dispatchAction?.({
|
|
127
|
-
type: 'showTip',
|
|
128
|
-
seriesIndex: params?.seriesIndex,
|
|
129
|
-
dataIndex: params?.dataIndex,
|
|
130
|
-
});
|
|
131
|
-
break;
|
|
132
|
-
|
|
133
|
-
case 'hover':
|
|
134
|
-
item.instance.dispatchAction?.({
|
|
135
|
-
type: 'showTip',
|
|
136
|
-
seriesIndex: params?.seriesIndex,
|
|
137
|
-
dataIndex: params?.dataIndex,
|
|
138
|
-
});
|
|
139
|
-
break;
|
|
140
|
-
|
|
141
|
-
case 'select':
|
|
142
|
-
item.instance.dispatchAction?.({
|
|
143
|
-
type: 'toggleSelect',
|
|
144
|
-
seriesIndex: params?.seriesIndex,
|
|
145
|
-
dataIndex: params?.dataIndex,
|
|
146
|
-
});
|
|
147
|
-
break;
|
|
148
|
-
|
|
149
|
-
case 'dataZoom':
|
|
150
|
-
item.instance.dispatchAction?.({
|
|
151
|
-
type: 'dataZoom',
|
|
152
|
-
start: params?.start,
|
|
153
|
-
end: params?.end,
|
|
154
|
-
dataZoomIndex: params?.dataZoomIndex,
|
|
155
|
-
dataZoomIndexs: params?.dataZoomIndexs,
|
|
156
|
-
});
|
|
157
|
-
break;
|
|
158
|
-
|
|
159
|
-
default:
|
|
160
|
-
break;
|
|
161
|
-
}
|
|
162
|
-
} catch (e) {
|
|
163
|
-
console.warn(`[useChartConnect] Failed to dispatch ${eventType} to ${targetId}:`, e);
|
|
164
|
-
}
|
|
165
|
-
});
|
|
98
|
+
const dispatchToOthersCallback = useCallback(
|
|
99
|
+
(sourceId: string, eventType: ConnectEventType, params: unknown) => {
|
|
100
|
+
dispatchToOthers(sourceId, eventType, params, chartsRef);
|
|
166
101
|
},
|
|
167
|
-
[]
|
|
102
|
+
[chartsRef]
|
|
168
103
|
);
|
|
169
104
|
|
|
170
105
|
/**
|
|
171
106
|
* 绑定单个图表的联动事件
|
|
172
107
|
*/
|
|
173
|
-
const
|
|
108
|
+
const bindChartEventsCallback = useCallback(
|
|
174
109
|
(chartInstance: ChartInstance, chartId: string) => {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
handlers.set(eventType, handler);
|
|
183
|
-
|
|
184
|
-
try {
|
|
185
|
-
chartInstance.on(eventType, handler);
|
|
186
|
-
} catch (e) {
|
|
187
|
-
console.warn(`[useChartConnect] Failed to bind ${eventType} event:`, e);
|
|
188
|
-
}
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
eventHandlersRef.current.set(chartId, handlers);
|
|
110
|
+
bindChartEvents(
|
|
111
|
+
chartInstance,
|
|
112
|
+
chartId,
|
|
113
|
+
events,
|
|
114
|
+
createConnectHandlerCallback,
|
|
115
|
+
eventHandlersRef
|
|
116
|
+
);
|
|
192
117
|
},
|
|
193
|
-
[events,
|
|
118
|
+
[events, createConnectHandlerCallback, eventHandlersRef]
|
|
194
119
|
);
|
|
195
120
|
|
|
196
121
|
/**
|
|
197
122
|
* 解绑单个图表的联动事件
|
|
198
123
|
*/
|
|
199
|
-
const
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
handlers.forEach((handler, eventType) => {
|
|
207
|
-
try {
|
|
208
|
-
chartItem.instance.off(eventType, handler);
|
|
209
|
-
} catch (e) {
|
|
210
|
-
console.warn(`[useChartConnect] Failed to unbind ${eventType} event:`, e);
|
|
211
|
-
}
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
eventHandlersRef.current.delete(chartId);
|
|
215
|
-
}, []);
|
|
124
|
+
const unbindChartEventsCallback = useCallback(
|
|
125
|
+
(chartId: string) => {
|
|
126
|
+
unbindChartEvents(chartId, eventHandlersRef, chartsRef);
|
|
127
|
+
},
|
|
128
|
+
[eventHandlersRef, chartsRef]
|
|
129
|
+
);
|
|
216
130
|
|
|
217
131
|
/**
|
|
218
132
|
* 绑定图表到联动组
|
|
219
133
|
*/
|
|
220
134
|
const connect = useCallback(
|
|
221
135
|
(chartInstance: ChartInstance, chartId?: string) => {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
chartsRef.current.set(id, {
|
|
232
|
-
instance: chartInstance,
|
|
233
|
-
id,
|
|
234
|
-
handlers: new Map(),
|
|
235
|
-
});
|
|
236
|
-
|
|
237
|
-
// 绑定事件
|
|
238
|
-
bindChartEvents(chartInstance, id);
|
|
239
|
-
connectedRef.current = true;
|
|
240
|
-
|
|
241
|
-
// 如果有 groupName,设置图表组
|
|
242
|
-
if (groupName && chartInstance.group !== undefined) {
|
|
243
|
-
try {
|
|
244
|
-
(chartInstance as any).group = groupName;
|
|
245
|
-
} catch (e) {
|
|
246
|
-
console.warn('[useChartConnect] Failed to set chart group:', e);
|
|
247
|
-
}
|
|
248
|
-
}
|
|
136
|
+
connectChart(
|
|
137
|
+
chartInstance,
|
|
138
|
+
chartId,
|
|
139
|
+
groupName,
|
|
140
|
+
chartsRef,
|
|
141
|
+
connectedRef,
|
|
142
|
+
eventHandlersRef,
|
|
143
|
+
bindChartEventsCallback
|
|
144
|
+
);
|
|
249
145
|
},
|
|
250
|
-
[
|
|
146
|
+
[groupName, chartsRef, connectedRef, eventHandlersRef, bindChartEventsCallback]
|
|
251
147
|
);
|
|
252
148
|
|
|
253
149
|
/**
|
|
@@ -255,56 +151,19 @@ export function useChartConnect(options: UseChartConnectOptions): UseChartConnec
|
|
|
255
151
|
*/
|
|
256
152
|
const disconnect = useCallback(
|
|
257
153
|
(chartInstance: ChartInstance, chartId?: string) => {
|
|
258
|
-
|
|
259
|
-
let targetId = chartId;
|
|
260
|
-
if (!targetId) {
|
|
261
|
-
chartsRef.current.forEach((item, id) => {
|
|
262
|
-
if (item.instance === chartInstance) {
|
|
263
|
-
targetId = id;
|
|
264
|
-
}
|
|
265
|
-
});
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
if (!targetId || !chartsRef.current.has(targetId)) {
|
|
269
|
-
console.warn(`[useChartConnect] Chart ${targetId} not found in connection group`);
|
|
270
|
-
return;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
// 解绑事件
|
|
274
|
-
unbindChartEvents(targetId);
|
|
275
|
-
|
|
276
|
-
// 移除图表
|
|
277
|
-
chartsRef.current.delete(targetId);
|
|
278
|
-
|
|
279
|
-
// 更新连接状态
|
|
280
|
-
connectedRef.current = chartsRef.current.size > 0;
|
|
154
|
+
disconnectChart(chartInstance, chartId, chartsRef, connectedRef, unbindChartEventsCallback);
|
|
281
155
|
},
|
|
282
|
-
[
|
|
156
|
+
[chartsRef, connectedRef, unbindChartEventsCallback]
|
|
283
157
|
);
|
|
284
158
|
|
|
285
159
|
/**
|
|
286
160
|
* 触发联动事件
|
|
287
161
|
*/
|
|
288
162
|
const dispatchConnect = useCallback(
|
|
289
|
-
(sourceId: string, payload:
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
const chartItem = chartsRef.current.get(sourceId);
|
|
293
|
-
if (!chartItem) {
|
|
294
|
-
console.warn(`[useChartConnect] Source chart ${sourceId} not found`);
|
|
295
|
-
return;
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
const { eventType, params } = payload || {};
|
|
299
|
-
if (!eventType) {
|
|
300
|
-
console.warn('[useChartConnect] Payload must include eventType');
|
|
301
|
-
return;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
// 分发事件到其他图表
|
|
305
|
-
dispatchToOthers(sourceId, eventType, params);
|
|
163
|
+
(sourceId: string, payload: { eventType: ConnectEventType; params: unknown }) => {
|
|
164
|
+
dispatchConnectEvent(sourceId, payload, disabled, chartsRef, dispatchToOthersCallback);
|
|
306
165
|
},
|
|
307
|
-
[disabled,
|
|
166
|
+
[disabled, chartsRef, dispatchToOthersCallback]
|
|
308
167
|
);
|
|
309
168
|
|
|
310
169
|
/**
|
|
@@ -312,9 +171,7 @@ export function useChartConnect(options: UseChartConnectOptions): UseChartConnec
|
|
|
312
171
|
*/
|
|
313
172
|
const connectAll = useCallback(
|
|
314
173
|
(charts: Array<{ instance: ChartInstance; id: string }>) => {
|
|
315
|
-
charts
|
|
316
|
-
connect(instance, id);
|
|
317
|
-
});
|
|
174
|
+
connectAllCharts(charts, connect);
|
|
318
175
|
},
|
|
319
176
|
[connect]
|
|
320
177
|
);
|
|
@@ -323,12 +180,8 @@ export function useChartConnect(options: UseChartConnectOptions): UseChartConnec
|
|
|
323
180
|
* 批量断开所有图表
|
|
324
181
|
*/
|
|
325
182
|
const disconnectAll = useCallback(() => {
|
|
326
|
-
chartsRef
|
|
327
|
-
|
|
328
|
-
});
|
|
329
|
-
chartsRef.current.clear();
|
|
330
|
-
connectedRef.current = false;
|
|
331
|
-
}, [unbindChartEvents]);
|
|
183
|
+
disconnectAllCharts(chartsRef, connectedRef, unbindChartEventsCallback);
|
|
184
|
+
}, [chartsRef, connectedRef, unbindChartEventsCallback]);
|
|
332
185
|
|
|
333
186
|
// 自动绑定
|
|
334
187
|
useEffect(() => {
|
|
@@ -359,4 +212,5 @@ export function useChartConnect(options: UseChartConnectOptions): UseChartConnec
|
|
|
359
212
|
// 导出
|
|
360
213
|
// ============================================================================
|
|
361
214
|
|
|
362
|
-
|
|
215
|
+
/** 导出共享事件类型 */
|
|
216
|
+
export type { ConnectEventType, ChartConnectItem, EventHandlersMap } from './chartConnectHelpers';
|