@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,109 @@
1
+ /**
2
+ * useChartPerformance - 图表性能相关 Hooks
3
+ * 提供数据轮询等功能
4
+ */
5
+ import { useState, useEffect, useCallback, useRef } from 'react';
6
+
7
+ /**
8
+ * 使用数据轮询
9
+ * @param fetchFn 数据获取函数
10
+ * @param options 配置选项
11
+ * @returns [数据, 加载状态, 错误, 刷新函数]
12
+ */
13
+ export function useDataPolling<T>(
14
+ fetchFn: () => Promise<T>,
15
+ options?: {
16
+ /** 轮询间隔 (ms) */
17
+ interval?: number;
18
+ /** 是否自动开始 */
19
+ autoStart?: boolean;
20
+ /** 错误重试次数 */
21
+ retryCount?: number;
22
+ /** 重试延迟 (ms) */
23
+ retryDelay?: number;
24
+ }
25
+ ) {
26
+ const { interval = 5000, autoStart = false, retryCount = 3, retryDelay = 1000 } = options || {};
27
+
28
+ const [data, setData] = useState<T | null>(null);
29
+ const [loading, setLoading] = useState(autoStart);
30
+ const [error, setError] = useState<Error | null>(null);
31
+
32
+ // 用于取消进行中的请求
33
+ const abortRef = useRef<{ cancelled: boolean }>({ cancelled: false });
34
+
35
+ const fetchData = useCallback(async () => {
36
+ // 取消之前的请求
37
+ abortRef.current.cancelled = true;
38
+ // 创建新的取消标记
39
+ abortRef.current = { cancelled: false };
40
+ const currentAbort = abortRef.current;
41
+
42
+ let retries = retryCount;
43
+ setLoading(true);
44
+ setError(null);
45
+
46
+ // retryCount < 0 表示不重试,直接一次请求
47
+ if (retryCount < 0) {
48
+ try {
49
+ const result = await fetchFn();
50
+ if (!currentAbort.cancelled) {
51
+ setData(result);
52
+ setLoading(false);
53
+ }
54
+ } catch (e) {
55
+ if (!currentAbort.cancelled) {
56
+ setError(e as Error);
57
+ setLoading(false);
58
+ }
59
+ }
60
+ return;
61
+ }
62
+
63
+ // retryCount >= 0:循环重试
64
+ while (retries > 0 && !currentAbort.cancelled) {
65
+ try {
66
+ const result = await fetchFn();
67
+ if (!currentAbort.cancelled) {
68
+ setData(result);
69
+ setLoading(false);
70
+ }
71
+ return;
72
+ } catch (e) {
73
+ retries--;
74
+ if (retries <= 0 || currentAbort.cancelled) {
75
+ if (!currentAbort.cancelled) {
76
+ setError(e as Error);
77
+ }
78
+ setLoading(false);
79
+ return;
80
+ }
81
+ await new Promise((resolve) => setTimeout(resolve, retryDelay));
82
+ }
83
+ }
84
+ }, [fetchFn, retryCount, retryDelay]);
85
+
86
+ useEffect(() => {
87
+ if (autoStart) {
88
+ fetchData();
89
+ }
90
+
91
+ if (interval > 0) {
92
+ const timer = setInterval(fetchData, interval);
93
+ return () => {
94
+ clearInterval(timer);
95
+ abortRef.current.cancelled = true;
96
+ };
97
+ }
98
+
99
+ return () => {
100
+ abortRef.current.cancelled = true;
101
+ };
102
+ }, [interval, autoStart, fetchData]);
103
+
104
+ const refresh = useCallback(() => {
105
+ fetchData();
106
+ }, [fetchData]);
107
+
108
+ return { data, loading, error, refresh };
109
+ }
@@ -1,3 +1,4 @@
1
+ /* eslint-disable @typescript-eslint/no-unused-vars */
1
2
  /**
2
3
  * useChartSelection - 图表数据点选择/高亮 Hook
3
4
  * 支持单个/批量选择、反选、清除选择,配合 ECharts select 事件
@@ -10,7 +11,7 @@
10
11
  * - 自动绑定图表 select/unselect 事件
11
12
  */
12
13
  import { useEffect, useRef, useCallback, useState } from 'react';
13
- import type { ChartInstance } from './index';
14
+ import type { ChartInstance } from './types';
14
15
 
15
16
  // ============================================================================
16
17
  // 类型定义
@@ -44,7 +45,7 @@ export interface UseChartSelectionOptions {
44
45
  /** 是否启用 Shift+Click 范围选择,默认 true */
45
46
  enableShiftRangeSelect?: boolean;
46
47
  /** 选择变化时的回调 */
47
- onSelectionChange?: (event: SelectionEvent) => void;
48
+ onSelectionChange?: (_event: SelectionEvent) => void;
48
49
  }
49
50
 
50
51
  /** 选择返回值 */
@@ -118,9 +119,6 @@ export function useChartSelection(
118
119
  const chartRef = useRef<ChartInstance | null>(null);
119
120
  chartRef.current = chartInstance;
120
121
 
121
- // 上一次 shift+click 的数据索引(用于范围选择)
122
- const lastShiftIndexRef = useRef<number | null>(null);
123
-
124
122
  // 当前模式 ref(用于事件处理)
125
123
  const modeRef = useRef(mode);
126
124
  modeRef.current = mode;
@@ -130,16 +128,6 @@ export function useChartSelection(
130
128
  const chart = chartRef.current;
131
129
  if (!chart || !chart.on) return;
132
130
 
133
- const handleSelect = (params: { selected: Record<string, boolean>; type: string }) => {
134
- // ECharts 内置 select 会同步更新 legend
135
- // 这里我们用 dispatchAction 来实现纯数据点选择
136
- };
137
-
138
- // 单击 legend 时清除数据点选择(保持一致性)
139
- const handleLegendSelectChanged = (params: { name?: string; selected?: Record<string, boolean> }) => {
140
- // 清除选择时的视觉反馈
141
- };
142
-
143
131
  chart.on('selectchanged', (params: unknown) => {
144
132
  // 当图表内部选择变化时同步状态
145
133
  const p = params as {
@@ -185,18 +173,15 @@ export function useChartSelection(
185
173
  );
186
174
 
187
175
  /** 执行 ECharts dispatchAction */
188
- const dispatchSelect = useCallback(
189
- (key: DataPointKey, select: boolean) => {
190
- const chart = chartRef.current;
191
- if (!chart?.dispatchAction) return;
192
- chart.dispatchAction({
193
- type: select ? 'select' : 'unselect',
194
- seriesIndex: key.seriesIndex,
195
- dataIndex: key.dataIndex,
196
- });
197
- },
198
- []
199
- );
176
+ const dispatchSelect = useCallback((key: DataPointKey, select: boolean) => {
177
+ const chart = chartRef.current;
178
+ if (!chart?.dispatchAction) return;
179
+ chart.dispatchAction({
180
+ type: select ? 'select' : 'unselect',
181
+ seriesIndex: key.seriesIndex,
182
+ dataIndex: key.dataIndex,
183
+ });
184
+ }, []);
200
185
 
201
186
  // ─── Public API ───────────────────────────────────────────────────────────
202
187
 
@@ -230,21 +215,34 @@ export function useChartSelection(
230
215
  const toggle = useCallback(
231
216
  (key: DataPointKey) => {
232
217
  const str = keyToString(key);
233
- if (selectedPoints.some((p) => keyToString(p) === str)) {
234
- deselect(key);
235
- } else {
236
- select(key);
237
- }
218
+ let isCurrentlySelected = false;
219
+ setSelectedPoints((prev) => {
220
+ isCurrentlySelected = prev.some((p) => keyToString(p) === str);
221
+ if (isCurrentlySelected) {
222
+ dispatchSelect(key, false);
223
+ notifyChange([], [key]);
224
+ return prev.filter((p) => keyToString(p) !== str);
225
+ } else {
226
+ dispatchSelect(key, true);
227
+ const next = mode === 'single' ? [key] : [...prev, key];
228
+ notifyChange(next, []);
229
+ return next;
230
+ }
231
+ });
238
232
  },
239
- [selectedPoints, select, deselect]
233
+ [mode, notifyChange, dispatchSelect]
240
234
  );
241
235
 
242
236
  const selectMultiple = useCallback(
243
237
  (keys: DataPointKey[]) => {
244
238
  setSelectedPoints((prev) => {
245
- const newPoints = mode === 'single' ? keys : [...prev, ...keys.filter(
246
- (k) => !prev.some((p) => keyToString(p) === keyToString(k))
247
- )];
239
+ const newPoints =
240
+ mode === 'single'
241
+ ? keys
242
+ : [
243
+ ...prev,
244
+ ...keys.filter((k) => !prev.some((p) => keyToString(p) === keyToString(k))),
245
+ ];
248
246
  notifyChange(newPoints, []);
249
247
  return newPoints;
250
248
  });
@@ -270,7 +268,9 @@ export function useChartSelection(
270
268
  const invertSelection = useCallback(
271
269
  (seriesIndex: number, dataIndices: number[]) => {
272
270
  setSelectedPoints((prev) => {
273
- const selectedSet = new Set(prev.filter((p) => p.seriesIndex === seriesIndex).map((p) => p.dataIndex));
271
+ const selectedSet = new Set(
272
+ prev.filter((p) => p.seriesIndex === seriesIndex).map((p) => p.dataIndex)
273
+ );
274
274
  const toSelect: DataPointKey[] = [];
275
275
  const toDeselect: DataPointKey[] = [];
276
276
 
@@ -287,9 +287,9 @@ export function useChartSelection(
287
287
  toDeselect.forEach((k) => dispatchSelect(k, false));
288
288
  toSelect.forEach((k) => dispatchSelect(k, true));
289
289
 
290
- const newSelected = prev.filter(
291
- (p) => !(p.seriesIndex === seriesIndex && selectedSet.has(p.dataIndex))
292
- ).concat(toSelect);
290
+ const newSelected = prev
291
+ .filter((p) => !(p.seriesIndex === seriesIndex && selectedSet.has(p.dataIndex)))
292
+ .concat(toSelect);
293
293
 
294
294
  notifyChange(toSelect, toDeselect);
295
295
  return newSelected;
@@ -302,9 +302,13 @@ export function useChartSelection(
302
302
  (seriesIndex: number, dataIndices: number[]) => {
303
303
  const keys = dataIndices.map((dataIndex) => ({ seriesIndex, dataIndex }));
304
304
  setSelectedPoints((prev) => {
305
- const newPoints = mode === 'single' ? keys : [...prev, ...keys.filter(
306
- (k) => !prev.some((p) => keyToString(p) === keyToString(k))
307
- )];
305
+ const newPoints =
306
+ mode === 'single'
307
+ ? keys
308
+ : [
309
+ ...prev,
310
+ ...keys.filter((k) => !prev.some((p) => keyToString(p) === keyToString(k))),
311
+ ];
308
312
  notifyChange(newPoints, []);
309
313
  return newPoints;
310
314
  });
@@ -318,10 +322,11 @@ export function useChartSelection(
318
322
  if (chart?.dispatchAction) {
319
323
  chart.dispatchAction({ type: 'unselect' });
320
324
  }
321
- const prev = selectedPoints;
322
- setSelectedPoints([]);
323
- notifyChange([], prev);
324
- }, [selectedPoints, notifyChange]);
325
+ setSelectedPoints((prev) => {
326
+ notifyChange([], prev);
327
+ return [];
328
+ });
329
+ }, [notifyChange]);
325
330
 
326
331
  const isSelected = useCallback(
327
332
  (key: DataPointKey) => {
@@ -346,5 +351,3 @@ export function useChartSelection(
346
351
  isSelected,
347
352
  };
348
353
  }
349
-
350
- export default useChartSelection;
@@ -0,0 +1,51 @@
1
+ /**
2
+ * useChartTheme - 图表主题相关 Hooks
3
+ * 提供主题解析和主题切换功能
4
+ */
5
+ import { useState, useMemo, useCallback } from 'react';
6
+ import { getThemeByName } from '../themes';
7
+
8
+ /**
9
+ * 使用图表主题
10
+ * @param theme 主题名称或配置
11
+ * @param darkMode 是否为暗色模式
12
+ * @returns 处理后的主题
13
+ */
14
+ export function useChartTheme(theme: string | Record<string, unknown>, darkMode = false) {
15
+ return useMemo(() => {
16
+ if (typeof theme === 'string') {
17
+ // 如果是字符串,尝试获取内置主题配置
18
+ try {
19
+ const builtinTheme = getThemeByName(theme);
20
+ return builtinTheme || (darkMode ? 'dark' : theme);
21
+ } catch {
22
+ return darkMode ? 'dark' : theme;
23
+ }
24
+ }
25
+ return theme;
26
+ }, [theme, darkMode]);
27
+ }
28
+
29
+ /**
30
+ * 使用主题切换
31
+ * @param initialTheme 初始主题
32
+ * @returns [当前主题, 切换主题函数]
33
+ */
34
+ export function useThemeSwitcher(initialTheme = 'default') {
35
+ const [theme, setTheme] = useState<string | Record<string, unknown>>(initialTheme);
36
+ const [isDark, setIsDark] = useState(false);
37
+
38
+ const switchTheme = useCallback((newTheme: string | Record<string, unknown>) => {
39
+ setTheme(newTheme);
40
+ if (typeof newTheme === 'string') {
41
+ setIsDark(newTheme === 'dark' || newTheme.includes('dark'));
42
+ }
43
+ }, []);
44
+
45
+ const toggleDark = useCallback(() => {
46
+ setIsDark((prev) => !prev);
47
+ setTheme((prev) => (prev === 'dark' ? 'default' : 'dark'));
48
+ }, []);
49
+
50
+ return { theme, isDark, switchTheme, toggleDark, setTheme };
51
+ }
@@ -63,7 +63,7 @@ export interface TransformOptions {
63
63
  order: 'asc' | 'desc';
64
64
  };
65
65
  /** 过滤配置 */
66
- filter?: (item: Record<string, unknown>) => boolean;
66
+ filter?: (_item: Record<string, unknown>) => boolean;
67
67
  /** 转换后的额外配置 */
68
68
  extraConfig?: Partial<EChartsOption>;
69
69
  }
@@ -109,6 +109,21 @@ export interface TimeSeriesTransformOptions {
109
109
  // 数据转换 Hook
110
110
  // ============================================================================
111
111
 
112
+ /**
113
+ * 使用图表数据变更
114
+ * @param data 数据源
115
+ * @param transformer 数据转换函数
116
+ * @returns 转换后的图表选项
117
+ */
118
+ export function useChartData<T = unknown>(data: T | null, transformer: (data: T) => EChartsOption) {
119
+ return useMemo(() => {
120
+ if (!data || (Array.isArray(data) && data.length === 0)) {
121
+ return {};
122
+ }
123
+ return transformer(data);
124
+ }, [data, transformer]);
125
+ }
126
+
112
127
  /**
113
128
  * 使用数据转换
114
129
  * @param options 转换选项
@@ -174,7 +189,7 @@ export function useTableTransform(options: TableTransformOptions): EChartsOption
174
189
  name: colConfig?.label || key,
175
190
  type: 'bar' as const,
176
191
  data: values,
177
- itemStyle: colConfig?.color ? { color: colConfig.color } : undefined,
192
+ _itemStyle: colConfig?.color ? { color: colConfig.color } : undefined,
178
193
  };
179
194
  });
180
195
 
@@ -217,8 +232,8 @@ export function useTimeSeriesTransform(options: TimeSeriesTransformOptions): ECh
217
232
  const groups = new Set(data.map((d) => String(d[groupField])));
218
233
  const series = Array.from(groups).map((group) => {
219
234
  const groupValues = categories.map((date) => {
220
- const items = groupedData[date]?.filter((d) => String(d[groupField]) === group) || [];
221
- return aggregateValues(items, valueField, aggregation, fillMissing);
235
+ const _items = groupedData[date]?.filter((d) => String(d[groupField]) === group) || [];
236
+ return aggregateValues(_items, valueField, aggregation, fillMissing);
222
237
  });
223
238
  return { name: group, type: 'line', data: groupValues, smooth: true };
224
239
  });
@@ -1,55 +1,19 @@
1
1
  /**
2
2
  * Chart Download Utilities
3
3
  * 图表下载工具函数
4
+ * 使用公共下载工具模块
4
5
  */
5
6
 
6
- /**
7
- * 生成默认文件名
8
- */
9
- export function generateFilename(prefix: string = 'chart'): string {
10
- const timestamp = new Date().toISOString().slice(0, 19).replace(/[:-]/g, '');
11
- return `${prefix}_${timestamp}`;
12
- }
13
-
14
- /**
15
- * 下载 Blob 对象
16
- */
17
- export function downloadBlob(blob: Blob, filename: string): void {
18
- const url = URL.createObjectURL(blob);
19
- const link = document.createElement('a');
20
- link.href = url;
21
- link.download = filename;
22
- document.body.appendChild(link);
23
- link.click();
24
- document.body.removeChild(link);
25
- URL.revokeObjectURL(url);
26
- }
7
+ import {
8
+ generateFilename,
9
+ downloadBlob,
10
+ downloadDataUrl,
11
+ csvToBlob,
12
+ jsonToBlob,
13
+ } from '../../core/utils/download';
27
14
 
28
- /**
29
- * 下载数据 URL
30
- */
31
- export function downloadDataUrl(dataUrl: string, filename: string): void {
32
- const link = document.createElement('a');
33
- link.href = dataUrl;
34
- link.download = filename;
35
- document.body.appendChild(link);
36
- link.click();
37
- document.body.removeChild(link);
38
- }
39
-
40
- /**
41
- * CSV 转 Blob
42
- */
43
- export function csvToBlob(csv: string, _filename: string): Blob {
44
- return new Blob([csv], { type: 'text/csv;charset=utf-8;' });
45
- }
46
-
47
- /**
48
- * JSON 转 Blob
49
- */
50
- export function jsonToBlob(json: string, _filename: string): Blob {
51
- return new Blob([json], { type: 'application/json;charset=utf-8;' });
52
- }
15
+ // 重新导出公共函数
16
+ export { generateFilename, downloadBlob, downloadDataUrl, csvToBlob, jsonToBlob };
53
17
 
54
18
  /**
55
19
  * 将数据转换为 CSV 格式
@@ -59,7 +23,14 @@ export function convertToCSV(data: unknown, options?: { includeLabels?: boolean
59
23
 
60
24
  // 处理 ECharts 格式的数据
61
25
  if (typeof data === 'object' && (data as { series?: unknown }).series) {
62
- return convertSeriesToCSV(data as { series?: unknown[]; xAxis?: { data?: unknown[] }; dataset?: { dimensions?: string[]; source?: unknown[][] } }, options);
26
+ return convertSeriesToCSV(
27
+ data as {
28
+ series?: unknown[];
29
+ xAxis?: { data?: unknown[] };
30
+ dataset?: { dimensions?: string[]; source?: unknown[][] };
31
+ },
32
+ options
33
+ );
63
34
  }
64
35
 
65
36
  // 处理数组数据
@@ -79,7 +50,11 @@ export function convertToCSV(data: unknown, options?: { includeLabels?: boolean
79
50
  * 将 ECharts series 数据转换为 CSV
80
51
  */
81
52
  function convertSeriesToCSV(
82
- chartData: { series?: unknown[]; xAxis?: { data?: unknown[] }; dataset?: { dimensions?: string[]; source?: unknown[][] } },
53
+ chartData: {
54
+ series?: unknown[];
55
+ xAxis?: { data?: unknown[] };
56
+ dataset?: { dimensions?: string[]; source?: unknown[][] };
57
+ },
83
58
  options?: { includeLabels?: boolean }
84
59
  ): string {
85
60
  const { series = [], xAxis, dataset } = chartData;
@@ -102,7 +77,14 @@ function convertSeriesToCSV(
102
77
 
103
78
  // 构建 CSV 头
104
79
  const headers = includeLabels
105
- ? ['Category', ...series.map((s: unknown) => (s as { name?: string; seriesIndex?: number }).name || (s as { seriesIndex?: number }).seriesIndex)]
80
+ ? [
81
+ 'Category',
82
+ ...series.map(
83
+ (s: unknown) =>
84
+ (s as { name?: string; seriesIndex?: number }).name ||
85
+ (s as { seriesIndex?: number }).seriesIndex
86
+ ),
87
+ ]
106
88
  : [];
107
89
 
108
90
  // 构建 CSV 行
@@ -175,7 +157,12 @@ function convertObjectToCSV(data: Record<string, unknown>): string {
175
157
  export function convertToJSON(data: unknown): string {
176
158
  if (!data) return '{}';
177
159
 
178
- const dataObj = data as { series?: unknown[]; title?: { text?: string }; legend?: { data?: unknown }; xAxis?: { data?: unknown[] } };
160
+ const dataObj = data as {
161
+ series?: unknown[];
162
+ title?: { text?: string };
163
+ legend?: { data?: unknown };
164
+ xAxis?: { data?: unknown[] };
165
+ };
179
166
 
180
167
  // 如果是 ECharts 格式,简化数据
181
168
  if (dataObj.series) {
@@ -234,7 +221,7 @@ export async function createPdfFromImage(
234
221
  // 计算图片位置和尺寸(居中)
235
222
  const imgRatio = img.width / img.height;
236
223
  const canvasRatio = pdfWidth / pdfHeight;
237
- let drawWidth: number, drawHeight: number, offsetX: number, offsetY: number;
224
+ let drawWidth: number, drawHeight: number;
238
225
 
239
226
  if (imgRatio > canvasRatio) {
240
227
  drawWidth = pdfWidth * 0.8;
@@ -244,8 +231,8 @@ export async function createPdfFromImage(
244
231
  drawWidth = drawHeight * imgRatio;
245
232
  }
246
233
 
247
- offsetX = (pdfWidth - drawWidth) / 2;
248
- offsetY = (pdfHeight - drawHeight) / 2;
234
+ const offsetX = (pdfWidth - drawWidth) / 2;
235
+ const offsetY = (pdfHeight - drawHeight) / 2;
249
236
 
250
237
  // 绘制图片
251
238
  ctx.drawImage(img, offsetX, offsetY, drawWidth, drawHeight);
@@ -44,6 +44,14 @@ export interface TransformMapping {
44
44
  // 转换函数
45
45
  // ============================================================================
46
46
 
47
+ /**
48
+ * 将数据转换为折线图或柱状图配置
49
+ * @param data 数据源
50
+ * @param chartType 图表类型 (line 或 bar)
51
+ * @param mapping 字段映射
52
+ * @param extraConfig 额外配置
53
+ * @returns ECharts 配置
54
+ */
47
55
  export function transformLineOrBar(
48
56
  data: DataSource,
49
57
  chartType: 'line' | 'bar',
@@ -90,6 +98,13 @@ export function transformLineOrBar(
90
98
  };
91
99
  }
92
100
 
101
+ /**
102
+ * 将数据转换为饼图配置
103
+ * @param data 数据源
104
+ * @param mapping 字段映射
105
+ * @param extraConfig 额外配置
106
+ * @returns ECharts 配置
107
+ */
93
108
  export function transformPie(
94
109
  data: DataSource,
95
110
  mapping: TransformMapping,
@@ -110,6 +125,13 @@ export function transformPie(
110
125
  };
111
126
  }
112
127
 
128
+ /**
129
+ * 将数据转换为散点图配置
130
+ * @param data 数据源
131
+ * @param mapping 字段映射
132
+ * @param extraConfig 额外配置
133
+ * @returns ECharts 配置
134
+ */
113
135
  export function transformScatter(
114
136
  data: DataSource,
115
137
  mapping: TransformMapping,
package/src/index.ts CHANGED
@@ -35,38 +35,54 @@ export {
35
35
  prefixedId,
36
36
  } from './core/utils';
37
37
 
38
- // 图表组件
39
- export { default as LineChart } from './charts/line';
40
- export { default as BarChart } from './charts/bar';
41
- export { default as PieChart } from './charts/pie';
42
- export { default as ScatterChart } from './charts/scatter';
43
- export { default as RadarChart } from './charts/radar';
44
- export { default as HeatmapChart } from './charts/heatmap';
45
- export { default as GaugeChart } from './charts/gauge';
46
- export { default as FunnelChart } from './charts/funnel';
47
-
48
- // 扩展图表组件
49
- export { default as TreeMapChart } from './charts/treemap';
50
- export { default as SunburstChart } from './charts/sunburst';
51
- export { default as SankeyChart } from './charts/sankey';
52
-
53
- // 新增图表组件
54
- export { default as GraphChart } from './charts/graph';
55
- export { default as CandlestickChart } from './charts/candlestick';
56
- export { default as WordCloudChart } from './charts/wordcloud';
57
-
58
- // v1.6.0 新增图表组件
59
- export { default as BoxplotChart } from './charts/boxplot';
60
- export { default as ParallelChart } from './charts/parallel';
38
+ // 图表组件(统一从 charts/index.ts 导入)
39
+ export {
40
+ // 基础图表
41
+ LineChart,
42
+ BarChart,
43
+ PieChart,
44
+ ScatterChart,
45
+ RadarChartCustom as RadarChart,
46
+ HeatmapChart,
47
+ FunnelChart,
48
+ // 扩展图表
49
+ TreeMapChart,
50
+ SunburstChart,
51
+ SankeyChart,
52
+ GraphChart,
53
+ WordCloudChart,
54
+ // 特殊图表
55
+ BoxplotChart,
56
+ ParallelChart,
57
+ TreeChart,
58
+ // 类型
59
+ type BaseChartProps,
60
+ type LineChartProps,
61
+ type BarChartProps,
62
+ type PieChartProps,
63
+ type ScatterChartProps,
64
+ type RadarChartProps,
65
+ type FunnelChartProps,
66
+ type HeatmapChartProps,
67
+ type SunburstChartProps,
68
+ type TreeMapChartProps,
69
+ type SankeyChartProps,
70
+ type GraphChartProps,
71
+ type WordCloudChartProps,
72
+ type BoxplotChartProps,
73
+ type ParallelChartProps,
74
+ type TreeChartProps,
75
+ } from './charts';
61
76
 
62
77
  // v1.7.0 新增组件
63
- export { DataFilter, type DataFilterProps, type FilterField, type FilterValues } from './components/DataFilter';
78
+ export {
79
+ DataFilter,
80
+ type DataFilterProps,
81
+ type FilterField,
82
+ type FilterValues,
83
+ } from './components/DataFilter';
64
84
  export {
65
85
  createDrillDown,
66
- canDrillDown,
67
- buildHierarchy,
68
- createRegionDrillDown,
69
- createCategoryDrillDown,
70
86
  type DrillDownConfig,
71
87
  type DrillDownSource,
72
88
  type DrillDownReturn,
@@ -74,15 +90,15 @@ export {
74
90
  type DrillUpEventParams,
75
91
  } from './core/utils/drillDown';
76
92
 
77
- // v1.7.0 新增图表组件
78
- export { default as LiquidChart } from './charts/liquid';
79
- export { default as TreeChart } from './charts/tree';
80
-
81
93
  // 适配器
82
94
  export { getAdapter, detectPlatform, getEnv } from './adapters';
83
95
  export { default as H5Adapter } from './adapters/h5';
84
96
  export { default as WeappAdapter } from './adapters/weapp';
85
97
 
98
+ // 统一运行时检测
99
+ export { detectRuntime, resetRuntimeCache } from './core/utils/runtime';
100
+ export type { RuntimeInfo, MiniAppType } from './core/utils/runtime';
101
+
86
102
  // 主题系统
87
103
  export type { BuiltinTheme, ThemeOptions } from './themes';
88
104
  export {
@@ -172,7 +188,6 @@ export {
172
188
  useTableTransform,
173
189
  useTimeSeriesTransform,
174
190
  // v1.7.0 新增 Hooks
175
- useDataZoom,
176
191
  useChartConnect,
177
192
  useChartDownload,
178
193
  } from './hooks';
@@ -181,4 +196,3 @@ export {
181
196
  * 库信息
182
197
  */
183
198
  export const name = 'taroviz';
184
- export const version = '1.7.0';