@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.
Files changed (164) hide show
  1. package/CHANGELOG.md +245 -0
  2. package/README.md +104 -302
  3. package/dist/cjs/index.js +1 -1
  4. package/dist/cjs/vendors.js +1 -0
  5. package/dist/cjs/vendors~echarts.js +1 -0
  6. package/dist/esm/index.js +1 -58151
  7. package/dist/esm/vendors.js +1 -0
  8. package/dist/esm/vendors~echarts.js +1 -0
  9. package/package.json +19 -25
  10. package/src/adapters/MiniAppAdapter.ts +136 -0
  11. package/src/adapters/__tests__/index.test.ts +1 -1
  12. package/src/adapters/h5/__tests__/index.test.ts +4 -2
  13. package/src/adapters/h5/index.ts +63 -64
  14. package/src/adapters/harmony/index.ts +23 -245
  15. package/src/adapters/index.ts +49 -45
  16. package/src/adapters/swan/index.ts +6 -69
  17. package/src/adapters/tt/index.ts +7 -70
  18. package/src/adapters/types.ts +25 -58
  19. package/src/adapters/weapp/index.ts +6 -69
  20. package/src/charts/__tests__/testUtils.tsx +87 -0
  21. package/src/charts/boxplot/__tests__/index.test.tsx +49 -103
  22. package/src/charts/boxplot/index.tsx +2 -1
  23. package/src/charts/boxplot/types.ts +17 -16
  24. package/src/charts/common/BaseChartWrapper.tsx +90 -82
  25. package/src/charts/common/__mocks__/BaseChartWrapper.tsx +17 -0
  26. package/src/charts/createChartComponent.tsx +36 -0
  27. package/src/charts/createOptionChartComponent.tsx +32 -0
  28. package/src/charts/funnel/__tests__/index.test.tsx +99 -0
  29. package/src/charts/funnel/index.tsx +60 -10
  30. package/src/charts/funnel/types.ts +6 -0
  31. package/src/charts/graph/__tests__/index.test.tsx +102 -33
  32. package/src/charts/graph/index.tsx +66 -9
  33. package/src/charts/graph/types.ts +6 -0
  34. package/src/charts/heatmap/__tests__/index.test.tsx +139 -0
  35. package/src/charts/heatmap/index.tsx +103 -10
  36. package/src/charts/heatmap/types.ts +6 -0
  37. package/src/charts/index.ts +74 -26
  38. package/src/charts/liquid/__tests__/index.test.tsx +52 -0
  39. package/src/charts/liquid/index.tsx +239 -182
  40. package/src/charts/liquid/types.ts +11 -11
  41. package/src/charts/parallel/__tests__/index.test.tsx +40 -67
  42. package/src/charts/parallel/index.tsx +2 -1
  43. package/src/charts/parallel/types.ts +19 -18
  44. package/src/charts/radar/__tests__/index.test.tsx +210 -0
  45. package/src/charts/radar/index.tsx +143 -10
  46. package/src/charts/radar/types.ts +13 -0
  47. package/src/charts/sankey/__tests__/index.test.tsx +124 -0
  48. package/src/charts/sankey/index.tsx +62 -10
  49. package/src/charts/sankey/types.ts +6 -0
  50. package/src/charts/tree/__tests__/index.test.tsx +71 -0
  51. package/src/charts/tree/index.tsx +5 -2
  52. package/src/charts/tree/types.ts +9 -9
  53. package/src/charts/types.ts +208 -106
  54. package/src/charts/utils.ts +9 -7
  55. package/src/charts/wordcloud/__tests__/index.test.tsx +98 -31
  56. package/src/charts/wordcloud/index.tsx +75 -9
  57. package/src/charts/wordcloud/types.ts +6 -0
  58. package/src/components/DataFilter/index.tsx +32 -10
  59. package/src/core/animation/types.ts +6 -6
  60. package/src/core/components/Annotation.tsx +6 -7
  61. package/src/core/components/BaseChart.tsx +110 -168
  62. package/src/core/components/ErrorBoundary.tsx +17 -4
  63. package/src/core/components/LazyChart.tsx +54 -55
  64. package/src/core/components/hooks/index.ts +6 -2
  65. package/src/core/components/hooks/useChartInit.ts +6 -3
  66. package/src/core/components/hooks/usePerformance.ts +8 -2
  67. package/src/core/components/hooks/useVirtualScroll.ts +2 -1
  68. package/src/core/index.ts +1 -1
  69. package/src/core/themes/ThemeManager.ts +1 -1
  70. package/src/core/types/common.ts +2 -1
  71. package/src/core/types/index.ts +0 -12
  72. package/src/core/types/platform.ts +3 -5
  73. package/src/core/utils/__tests__/deepClone.test.ts +317 -0
  74. package/src/core/utils/__tests__/index.test.ts +2 -1
  75. package/src/core/utils/chartInstances.ts +13 -0
  76. package/src/core/utils/common.ts +20 -29
  77. package/src/core/utils/deepClone.ts +114 -0
  78. package/src/core/utils/download.ts +128 -0
  79. package/src/core/utils/drillDown.ts +34 -353
  80. package/src/core/utils/drillDownHelpers.ts +426 -0
  81. package/src/core/utils/events.ts +12 -0
  82. package/src/core/utils/export/ExportUtils.ts +36 -67
  83. package/src/core/utils/format.ts +44 -0
  84. package/src/core/utils/index.ts +21 -154
  85. package/src/core/utils/merge.ts +25 -0
  86. package/src/core/utils/performance/PerformanceAnalyzer.ts +38 -21
  87. package/src/core/utils/performance/hooks.ts +7 -0
  88. package/src/core/utils/performance/index.ts +2 -0
  89. package/src/{hooks → core/utils/performance}/useAnimation.ts +45 -41
  90. package/src/core/utils/performance/useDataZoom.ts +324 -0
  91. package/src/{hooks → core/utils/performance}/usePerformance.ts +49 -41
  92. package/src/core/utils/performance/usePerformanceHooks.ts +278 -0
  93. package/src/core/utils/performanceUtils.ts +310 -0
  94. package/src/core/utils/runtime.ts +190 -0
  95. package/src/core/utils/setOptionUtils.ts +59 -0
  96. package/src/core/version.ts +14 -0
  97. package/src/editor/EnhancedThemeEditor.tsx +362 -540
  98. package/src/editor/ThemeEditor.tsx +55 -321
  99. package/src/editor/components/ThemeBasicSettings.tsx +113 -0
  100. package/src/editor/components/ThemeColorEditor.tsx +105 -0
  101. package/src/editor/components/ThemeSelector.tsx +70 -0
  102. package/src/editor/hooks/useThemeEditorState.ts +201 -0
  103. package/src/editor/index.ts +10 -2
  104. package/src/hooks/__tests__/index.test.tsx +3 -1
  105. package/src/hooks/chartConnectHelpers.ts +341 -0
  106. package/src/hooks/index.ts +55 -660
  107. package/src/hooks/types.ts +189 -0
  108. package/src/hooks/useChartAutoResize.ts +73 -0
  109. package/src/hooks/useChartConnect.ts +92 -238
  110. package/src/hooks/useChartDownload.ts +25 -27
  111. package/src/hooks/useChartHistory.ts +34 -49
  112. package/src/hooks/useChartInit.ts +59 -0
  113. package/src/hooks/useChartOptions.ts +259 -0
  114. package/src/hooks/useChartPerformance.ts +109 -0
  115. package/src/hooks/useChartSelection.ts +52 -49
  116. package/src/hooks/useChartTheme.ts +51 -0
  117. package/src/hooks/useDataTransform.ts +19 -4
  118. package/src/hooks/utils/chartDownloadUtils.ts +40 -53
  119. package/src/hooks/utils/dataTransformUtils.ts +22 -0
  120. package/src/index.ts +48 -34
  121. package/src/main.tsx +4 -9
  122. package/src/react-dom.d.ts +3 -3
  123. package/src/themes/index.ts +30 -855
  124. package/src/themes/palettes/blue-green.ts +13 -0
  125. package/src/themes/palettes/chalk.ts +13 -0
  126. package/src/themes/palettes/cyber.ts +44 -0
  127. package/src/themes/palettes/dark.ts +52 -0
  128. package/src/themes/palettes/default.ts +52 -0
  129. package/src/themes/palettes/elegant.ts +34 -0
  130. package/src/themes/palettes/forest.ts +13 -0
  131. package/src/themes/palettes/glass.ts +49 -0
  132. package/src/themes/palettes/golden.ts +13 -0
  133. package/src/themes/palettes/neon.ts +43 -0
  134. package/src/themes/palettes/ocean.ts +39 -0
  135. package/src/themes/palettes/pastel.ts +37 -0
  136. package/src/themes/palettes/purple-passion.ts +13 -0
  137. package/src/themes/palettes/retro.ts +33 -0
  138. package/src/themes/palettes/sunset.ts +40 -0
  139. package/src/themes/palettes/walden.ts +13 -0
  140. package/src/themes/registry.ts +184 -0
  141. package/src/themes/types.ts +213 -0
  142. package/src/charts/bar/__tests__/index.test.tsx +0 -113
  143. package/src/charts/bar/index.tsx +0 -14
  144. package/src/charts/candlestick/__tests__/index.test.tsx +0 -40
  145. package/src/charts/candlestick/index.tsx +0 -13
  146. package/src/charts/gauge/index.tsx +0 -14
  147. package/src/charts/line/__tests__/index.test.tsx +0 -107
  148. package/src/charts/line/index.tsx +0 -15
  149. package/src/charts/pie/__tests__/index.test.tsx +0 -112
  150. package/src/charts/pie/index.tsx +0 -14
  151. package/src/charts/scatter/index.tsx +0 -14
  152. package/src/charts/sunburst/index.tsx +0 -18
  153. package/src/charts/treemap/index.tsx +0 -18
  154. package/src/core/utils/codeGenerator/CodeGenerator.ts +0 -669
  155. package/src/core/utils/codeGenerator/index.ts +0 -13
  156. package/src/core/utils/codeGenerator/types.ts +0 -198
  157. package/src/core/utils/configGenerator/ConfigGenerator.ts +0 -583
  158. package/src/core/utils/configGenerator/index.ts +0 -13
  159. package/src/core/utils/configGenerator/types.ts +0 -445
  160. package/src/core/utils/debug/DebugPanel.tsx +0 -637
  161. package/src/core/utils/debug/debugger.ts +0 -322
  162. package/src/core/utils/debug/index.ts +0 -21
  163. package/src/core/utils/debug/types.ts +0 -142
  164. 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 { ChartInstance } from './index';
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 ConnectEventType = 'click' | 'hover' | 'select' | 'dataZoom';
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 = ['click', 'hover', 'select', 'dataZoom'],
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
- const chartsRef = useRef<Map<string, ChartConnectItem>>(new Map());
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
- const eventHandlersRef = useRef<Map<string, Map<string, any>>>(new Map());
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 createConnectHandler = useCallback(
81
+ const createConnectHandlerCallback = useCallback(
89
82
  (sourceId: string, eventType: ConnectEventType) => {
90
- return (params: any) => {
91
- if (disabled) return;
92
-
93
- // 应用事件过滤器
94
- if (eventFilter && !eventFilter(eventType, params)) {
95
- return;
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 dispatchToOthers = useCallback(
119
- (sourceId: string, eventType: ConnectEventType, params: any) => {
120
- chartsRef.current.forEach((item, targetId) => {
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 bindChartEvents = useCallback(
108
+ const bindChartEventsCallback = useCallback(
174
109
  (chartInstance: ChartInstance, chartId: string) => {
175
- if (!chartInstance) return;
176
-
177
- const handlers = new Map<string, any>();
178
-
179
- // 为每个事件类型创建并绑定处理器
180
- events.forEach((eventType) => {
181
- const handler = createConnectHandler(chartId, eventType);
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, createConnectHandler]
118
+ [events, createConnectHandlerCallback, eventHandlersRef]
194
119
  );
195
120
 
196
121
  /**
197
122
  * 解绑单个图表的联动事件
198
123
  */
199
- const unbindChartEvents = useCallback((chartId: string) => {
200
- const handlers = eventHandlersRef.current.get(chartId);
201
- if (!handlers) return;
202
-
203
- const chartItem = chartsRef.current.get(chartId);
204
- if (!chartItem) return;
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
- const id = chartId || `chart_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
223
-
224
- // 检查是否已连接
225
- if (chartsRef.current.has(id)) {
226
- console.warn(`[useChartConnect] Chart ${id} is already connected`);
227
- return;
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
- [bindChartEvents, groupName]
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
- // 查找图表 ID
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
- [unbindChartEvents]
156
+ [chartsRef, connectedRef, unbindChartEventsCallback]
283
157
  );
284
158
 
285
159
  /**
286
160
  * 触发联动事件
287
161
  */
288
162
  const dispatchConnect = useCallback(
289
- (sourceId: string, payload: any) => {
290
- if (disabled) return;
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, dispatchToOthers]
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.forEach(({ instance, id }) => {
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.current.forEach((item, id) => {
327
- unbindChartEvents(id);
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
- export default useChartConnect;
215
+ /** 导出共享事件类型 */
216
+ export type { ConnectEventType, ChartConnectItem, EventHandlersMap } from './chartConnectHelpers';