@agions/taroviz 1.3.1 → 1.6.0

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 (64) hide show
  1. package/README.md +4 -4
  2. package/dist/cjs/index.js +1 -1
  3. package/dist/esm/index.js +3814 -2724
  4. package/package.json +1 -1
  5. package/src/__tests__/integration.test.tsx +12 -10
  6. package/src/adapters/BaseAdapter.ts +116 -0
  7. package/src/adapters/__tests__/index.test.ts +10 -10
  8. package/src/adapters/index.ts +63 -74
  9. package/src/adapters/swan/index.ts +26 -223
  10. package/src/adapters/tt/index.ts +28 -225
  11. package/src/adapters/types.ts +36 -0
  12. package/src/adapters/weapp/index.ts +29 -189
  13. package/src/charts/bar/index.tsx +5 -9
  14. package/src/charts/boxplot/__tests__/index.test.tsx +130 -0
  15. package/src/charts/boxplot/index.tsx +18 -0
  16. package/src/charts/boxplot/types.ts +46 -0
  17. package/src/charts/candlestick/__tests__/index.test.tsx +37 -0
  18. package/src/charts/candlestick/index.tsx +13 -0
  19. package/src/charts/common/BaseChartWrapper.tsx +47 -38
  20. package/src/charts/funnel/index.tsx +5 -9
  21. package/src/charts/gauge/index.tsx +5 -9
  22. package/src/charts/graph/__tests__/index.test.tsx +41 -0
  23. package/src/charts/graph/index.tsx +13 -0
  24. package/src/charts/heatmap/index.tsx +5 -9
  25. package/src/charts/index.ts +10 -1
  26. package/src/charts/line/index.tsx +4 -7
  27. package/src/charts/parallel/__tests__/index.test.tsx +164 -0
  28. package/src/charts/parallel/index.tsx +18 -0
  29. package/src/charts/parallel/types.ts +73 -0
  30. package/src/charts/pie/index.tsx +5 -10
  31. package/src/charts/radar/index.tsx +5 -9
  32. package/src/charts/scatter/index.tsx +5 -9
  33. package/src/charts/types.ts +48 -4
  34. package/src/charts/wordcloud/__tests__/index.test.tsx +36 -0
  35. package/src/charts/wordcloud/index.tsx +13 -0
  36. package/src/core/animation/AnimationManager.ts +15 -0
  37. package/src/core/components/Annotation.tsx +26 -21
  38. package/src/core/components/BaseChart.tsx +280 -1105
  39. package/src/core/components/ErrorBoundary.tsx +4 -1
  40. package/src/core/components/LazyChart.tsx +42 -55
  41. package/src/core/components/hooks/index.ts +20 -0
  42. package/src/core/components/hooks/useChartEvents.ts +143 -0
  43. package/src/core/components/hooks/useChartInit.ts +80 -0
  44. package/src/core/components/hooks/usePerformance.ts +186 -0
  45. package/src/core/components/hooks/useVirtualScroll.ts +156 -0
  46. package/src/core/echarts.ts +1 -1
  47. package/src/core/themes/ThemeManager.ts +31 -15
  48. package/src/core/types/index.ts +2 -2
  49. package/src/core/utils/chartInstances.ts +10 -3
  50. package/src/core/utils/chartUtils.ts +46 -0
  51. package/src/core/utils/common.ts +14 -1
  52. package/src/core/utils/export/ExportUtils.ts +13 -22
  53. package/src/core/utils/performance/PerformanceAnalyzer.ts +32 -5
  54. package/src/core/utils/uuid.ts +1 -1
  55. package/src/editor/EnhancedThemeEditor.tsx +624 -0
  56. package/src/editor/ThemeEditor.tsx +1 -6
  57. package/src/hooks/__tests__/index.test.tsx +14 -11
  58. package/src/hooks/__tests__/useDataTransform.test.ts +159 -0
  59. package/src/hooks/index.ts +54 -19
  60. package/src/hooks/useDataTransform.ts +503 -0
  61. package/src/index.ts +27 -9
  62. package/src/main.tsx +4 -4
  63. package/src/themes/__tests__/index.test.ts +2 -2
  64. package/src/themes/index.ts +13 -0
@@ -0,0 +1,159 @@
1
+ /**
2
+ * @version v1.5.0
3
+ */
4
+
5
+ import { renderHook } from '@testing-library/react';
6
+ import { useDataTransform, useTableTransform, useTimeSeriesTransform } from '../useDataTransform';
7
+
8
+ describe('useDataTransform', () => {
9
+ describe('useDataTransform - line/bar chart', () => {
10
+ it('transforms simple line chart data', () => {
11
+ const { result } = renderHook(() =>
12
+ useDataTransform({
13
+ data: {
14
+ categories: ['周一', '周二', '周三'],
15
+ series: [
16
+ { name: '销量', value: 120 },
17
+ { name: '销量', value: 200 },
18
+ { name: '销量', value: 150 },
19
+ ],
20
+ },
21
+ chartType: 'line',
22
+ mapping: { xField: 'name', yField: 'value' },
23
+ })
24
+ );
25
+
26
+ expect(result.current.xAxis).toBeTruthy();
27
+ expect(result.current.series).toBeTruthy();
28
+ });
29
+
30
+ it('transforms bar chart data with series', () => {
31
+ const { result } = renderHook(() =>
32
+ useDataTransform({
33
+ data: {
34
+ categories: ['周一', '周二', '周三'],
35
+ series: [
36
+ { name: 'A', value: 100 },
37
+ { name: 'A', value: 200 },
38
+ { name: 'A', value: 150 },
39
+ ],
40
+ },
41
+ chartType: 'bar',
42
+ mapping: { xField: 'name', yField: 'value', seriesField: 'name' },
43
+ })
44
+ );
45
+
46
+ // All data points have name='A', so they should be grouped into 1 series
47
+ expect(result.current.series).toHaveLength(1);
48
+ const series = result.current.series as unknown as Array<{ data: unknown[] }>;
49
+ expect(series[0].data).toHaveLength(3);
50
+ });
51
+ });
52
+
53
+ describe('useDataTransform - pie chart', () => {
54
+ it('transforms pie chart data', () => {
55
+ const { result } = renderHook(() =>
56
+ useDataTransform({
57
+ data: {
58
+ series: [
59
+ { name: '直接访问', value: 335 },
60
+ { name: '邮件营销', value: 310 },
61
+ ],
62
+ },
63
+ chartType: 'pie',
64
+ mapping: { nameField: 'name', valueField: 'value' },
65
+ })
66
+ );
67
+
68
+ expect(result.current.series).toBeTruthy();
69
+ const series = result.current.series as unknown as Array<{ data: unknown[] }>;
70
+ expect(series[0].data).toHaveLength(2);
71
+ });
72
+ });
73
+
74
+ describe('useDataTransform - scatter chart', () => {
75
+ it('transforms scatter chart data', () => {
76
+ const { result } = renderHook(() =>
77
+ useDataTransform({
78
+ data: {
79
+ series: [
80
+ { x: 10, y: 20, size: 5 },
81
+ { x: 30, y: 40, size: 10 },
82
+ ],
83
+ },
84
+ chartType: 'scatter',
85
+ mapping: { xField: 'x', yField: 'y', sizeField: 'size' },
86
+ })
87
+ );
88
+
89
+ expect(result.current.series).toBeTruthy();
90
+ });
91
+ });
92
+
93
+ describe('useTableTransform', () => {
94
+ it('transforms table data to bar chart config', () => {
95
+ const { result } = renderHook(() =>
96
+ useTableTransform({
97
+ data: [
98
+ { month: '一月', sales: 1200, profit: 300 },
99
+ { month: '二月', sales: 2000, profit: 500 },
100
+ ],
101
+ columns: [
102
+ { field: 'month', label: '月份' },
103
+ { field: 'sales', label: '销量' },
104
+ ],
105
+ })
106
+ );
107
+
108
+ expect(result.current.xAxis).toBeTruthy();
109
+ expect(result.current.series).toBeTruthy();
110
+ });
111
+
112
+ it('handles empty data', () => {
113
+ const { result } = renderHook(() =>
114
+ useTableTransform({
115
+ data: [],
116
+ })
117
+ );
118
+
119
+ expect(result.current).toEqual({});
120
+ });
121
+ });
122
+
123
+ describe('useTimeSeriesTransform', () => {
124
+ it('transforms time series data', () => {
125
+ const { result } = renderHook(() =>
126
+ useTimeSeriesTransform({
127
+ data: [
128
+ { date: '2024-01-01', value: 100 },
129
+ { date: '2024-01-02', value: 200 },
130
+ { date: '2024-01-03', value: 150 },
131
+ ],
132
+ dateField: 'date',
133
+ valueField: 'value',
134
+ period: 'day',
135
+ })
136
+ );
137
+
138
+ expect(result.current.xAxis).toBeTruthy();
139
+ expect(result.current.series).toBeTruthy();
140
+ });
141
+
142
+ it('handles grouped time series', () => {
143
+ const { result } = renderHook(() =>
144
+ useTimeSeriesTransform({
145
+ data: [
146
+ { date: '2024-01-01', value: 100, category: 'A' },
147
+ { date: '2024-01-01', value: 150, category: 'B' },
148
+ ],
149
+ dateField: 'date',
150
+ valueField: 'value',
151
+ groupField: 'category',
152
+ period: 'day',
153
+ })
154
+ );
155
+
156
+ expect(result.current.series).toHaveLength(2);
157
+ });
158
+ });
159
+ });
@@ -4,6 +4,7 @@
4
4
  */
5
5
  import { useState, useEffect, useMemo, useCallback, useRef } from 'react';
6
6
  import { getAdapter } from '../adapters';
7
+ import { getThemeByName } from '../themes';
7
8
  import type { EChartsOption } from 'echarts';
8
9
 
9
10
  // ============================================================================
@@ -94,14 +95,18 @@ export function useChart(
94
95
  return;
95
96
  }
96
97
 
97
- try {
98
- const adapter = getAdapter(configRef.current || {});
99
- const chartInstance = adapter as unknown as ChartInstance;
100
- setInstance(chartInstance);
101
- setInitialized(true);
102
- } catch (error) {
103
- console.error('Failed to initialize chart:', error);
104
- }
98
+ const initAdapter = async () => {
99
+ try {
100
+ const adapter = await getAdapter(configRef.current || {});
101
+ const chartInstance = adapter as unknown as ChartInstance;
102
+ setInstance(chartInstance);
103
+ setInitialized(true);
104
+ } catch (error) {
105
+ console.error('Failed to initialize chart:', error);
106
+ }
107
+ };
108
+
109
+ initAdapter();
105
110
 
106
111
  return () => {
107
112
  if (instance) {
@@ -294,9 +299,9 @@ export function useLoading(
294
299
  export function useChartTheme(theme: string | Record<string, unknown>, darkMode = false) {
295
300
  return useMemo(() => {
296
301
  if (typeof theme === 'string') {
297
- // 如果是字符串,尝试获取内置主题
302
+ // 如果是字符串,尝试获取内置主题配置
298
303
  try {
299
- const builtinTheme = getTheme(theme);
304
+ const builtinTheme = getThemeByName(theme);
300
305
  return builtinTheme || (darkMode ? 'dark' : theme);
301
306
  } catch {
302
307
  return darkMode ? 'dark' : theme;
@@ -410,7 +415,7 @@ export function useDataPolling<T>(
410
415
  const [data, setData] = useState<T | null>(null);
411
416
  const [loading, setLoading] = useState(autoStart);
412
417
  const [error, setError] = useState<Error | null>(null);
413
-
418
+
414
419
  // 用于取消进行中的请求
415
420
  const abortRef = useRef<{ cancelled: boolean }>({ cancelled: false });
416
421
 
@@ -420,12 +425,12 @@ export function useDataPolling<T>(
420
425
  // 创建新的取消标记
421
426
  abortRef.current = { cancelled: false };
422
427
  const currentAbort = abortRef.current;
423
-
428
+
424
429
  let retries = retryCount;
425
430
  setLoading(true);
426
431
  setError(null);
427
432
 
428
- while (retries >= 0 && !currentAbort.cancelled) {
433
+ while (retries > 0 && !currentAbort.cancelled) {
429
434
  try {
430
435
  const result = await fetchFn();
431
436
  if (!currentAbort.cancelled) {
@@ -435,16 +440,40 @@ export function useDataPolling<T>(
435
440
  return;
436
441
  } catch (e) {
437
442
  retries--;
438
- if (retries < 0 || currentAbort.cancelled) {
443
+ if (retries <= 0 || currentAbort.cancelled) {
439
444
  if (!currentAbort.cancelled) {
440
445
  setError(e as Error);
441
446
  }
442
447
  setLoading(false);
448
+ return;
443
449
  } else {
444
450
  await new Promise((resolve) => setTimeout(resolve, retryDelay));
445
451
  }
446
452
  }
447
453
  }
454
+
455
+ // No retries configured — if fetch fails immediately, that's an error
456
+ if (retryCount <= 0 && !currentAbort.cancelled) {
457
+ try {
458
+ const result = await fetchFn();
459
+ if (!currentAbort.cancelled) {
460
+ setData(result);
461
+ setLoading(false);
462
+ }
463
+ } catch (e) {
464
+ if (!currentAbort.cancelled) {
465
+ setError(e as Error);
466
+ setLoading(false);
467
+ }
468
+ }
469
+ return;
470
+ }
471
+
472
+ // All retries exhausted without success (caught in loop already handled above)
473
+ if (!currentAbort.cancelled) {
474
+ setError(new Error('All retries failed'));
475
+ setLoading(false);
476
+ }
448
477
  }, [fetchFn, retryCount, retryDelay]);
449
478
 
450
479
  useEffect(() => {
@@ -459,7 +488,7 @@ export function useDataPolling<T>(
459
488
  abortRef.current.cancelled = true;
460
489
  };
461
490
  }
462
-
491
+
463
492
  return () => {
464
493
  abortRef.current.cancelled = true;
465
494
  };
@@ -591,9 +620,17 @@ export function useChartTools(instance: ChartInstance | null) {
591
620
  // 导出
592
621
  // ============================================================================
593
622
 
594
- export const version = '1.2.0';
623
+ export const version = '1.4.0';
624
+
625
+ // 新增数据转换 hooks
626
+ export {
627
+ useDataTransform,
628
+ useTableTransform,
629
+ useTimeSeriesTransform,
630
+ useTransform,
631
+ } from './useDataTransform';
595
632
 
596
- const hooks = {
633
+ export default {
597
634
  useChart,
598
635
  useOption,
599
636
  useResize,
@@ -608,5 +645,3 @@ const hooks = {
608
645
  useExport,
609
646
  useChartTools,
610
647
  };
611
-
612
- export default hooks;