@agions/taroviz 1.1.1 → 1.2.1

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 (81) hide show
  1. package/README.md +324 -53
  2. package/dist/cjs/index.js +1 -0
  3. package/dist/esm/index.js +82979 -0
  4. package/package.json +160 -30
  5. package/src/__tests__/integration.test.tsx +168 -0
  6. package/src/adapters/__tests__/index.test.ts +91 -0
  7. package/src/adapters/h5/__tests__/index.test.ts +156 -0
  8. package/src/adapters/h5/index.ts +301 -0
  9. package/src/adapters/harmony/index.ts +274 -0
  10. package/src/adapters/index.ts +166 -0
  11. package/src/adapters/swan/index.ts +274 -0
  12. package/src/adapters/tt/index.ts +274 -0
  13. package/src/adapters/types.ts +162 -0
  14. package/src/adapters/weapp/index.ts +237 -0
  15. package/src/charts/bar/__tests__/index.test.tsx +113 -0
  16. package/src/charts/bar/index.tsx +18 -0
  17. package/src/charts/common/BaseChartWrapper.tsx +136 -0
  18. package/src/charts/funnel/index.tsx +18 -0
  19. package/src/charts/gauge/index.tsx +18 -0
  20. package/src/charts/heatmap/index.tsx +18 -0
  21. package/src/charts/index.ts +21 -0
  22. package/src/charts/line/__tests__/index.test.tsx +107 -0
  23. package/src/charts/line/index.tsx +18 -0
  24. package/src/charts/pie/__tests__/index.test.tsx +112 -0
  25. package/src/charts/pie/index.tsx +19 -0
  26. package/src/charts/radar/index.tsx +18 -0
  27. package/src/charts/scatter/index.tsx +18 -0
  28. package/src/charts/types.ts +619 -0
  29. package/src/charts/utils.ts +56 -0
  30. package/src/core/__tests__/platform.test.ts +48 -0
  31. package/src/core/animation/AnimationManager.ts +391 -0
  32. package/src/core/animation/index.ts +20 -0
  33. package/src/core/animation/types.ts +248 -0
  34. package/src/core/components/BaseChart.tsx +1313 -0
  35. package/src/core/components/ErrorBoundary.tsx +458 -0
  36. package/src/core/echarts.ts +58 -0
  37. package/src/core/index.ts +22 -0
  38. package/src/core/types/chart.ts +66 -0
  39. package/src/core/types/common.ts +224 -0
  40. package/src/core/types/index.ts +281 -0
  41. package/src/core/types/platform.ts +325 -0
  42. package/src/core/utils/__tests__/common.test.ts +52 -0
  43. package/src/core/utils/__tests__/environment.test.ts +94 -0
  44. package/src/core/utils/__tests__/i18n.test.ts +247 -0
  45. package/src/core/utils/__tests__/index.test.ts +219 -0
  46. package/src/core/utils/__tests__/uuid.test.ts +78 -0
  47. package/src/core/utils/chartInstances.ts +69 -0
  48. package/src/core/utils/codeGenerator/CodeGenerator.ts +655 -0
  49. package/src/core/utils/codeGenerator/index.ts +13 -0
  50. package/src/core/utils/codeGenerator/types.ts +198 -0
  51. package/src/core/utils/common.ts +58 -0
  52. package/src/core/utils/configGenerator/ConfigGenerator.ts +583 -0
  53. package/src/core/utils/configGenerator/index.ts +13 -0
  54. package/src/core/utils/configGenerator/types.ts +445 -0
  55. package/src/core/utils/debug/DebugPanel.tsx +637 -0
  56. package/src/core/utils/debug/debugger.ts +322 -0
  57. package/src/core/utils/debug/index.ts +21 -0
  58. package/src/core/utils/debug/types.ts +142 -0
  59. package/src/core/utils/i18n.ts +452 -0
  60. package/src/core/utils/index.ts +162 -0
  61. package/src/core/utils/performance/PerformanceAnalyzer.ts +586 -0
  62. package/src/core/utils/performance/index.ts +13 -0
  63. package/src/core/utils/performance/types.ts +180 -0
  64. package/src/core/utils/uuid.ts +30 -0
  65. package/src/editor/ThemeEditor.tsx +449 -0
  66. package/src/editor/index.ts +10 -0
  67. package/src/hooks/__tests__/index.test.tsx +333 -0
  68. package/src/hooks/index.ts +594 -0
  69. package/src/index.ts +75 -0
  70. package/src/main.tsx +247 -0
  71. package/src/react-dom.d.ts +7 -0
  72. package/src/themes/__tests__/index.test.ts +91 -0
  73. package/src/themes/index.ts +860 -0
  74. package/dist/389.index.esm.js +0 -1
  75. package/dist/389.index.js +0 -1
  76. package/dist/633.index.esm.js +0 -1
  77. package/dist/633.index.js +0 -1
  78. package/dist/967.index.esm.js +0 -1
  79. package/dist/967.index.js +0 -1
  80. package/dist/index.esm.js +0 -1
  81. package/dist/index.js +0 -1
@@ -0,0 +1,458 @@
1
+ /**
2
+ * TaroViz Error Boundary
3
+ * 图表组件错误边界,用于捕获子组件错误并显示备用 UI
4
+ */
5
+ import React, { Component, ReactNode } from 'react';
6
+
7
+ // ============================================================================
8
+ // 类型定义
9
+ // ============================================================================
10
+
11
+ /** 错误边界属性 */
12
+ export interface ErrorBoundaryProps {
13
+ /** 子组件 */
14
+ children: ReactNode;
15
+ /** 错误回调 */
16
+ onError?: (error: Error, errorInfo: React.ErrorInfo) => void;
17
+ /** 错误时显示的备用 UI */
18
+ fallback?: ReactNode;
19
+ /** 是否显示错误详情 */
20
+ showDetails?: boolean;
21
+ /** 重试回调 */
22
+ onRetry?: () => void;
23
+ }
24
+
25
+ /** 错误边界状态 */
26
+ export interface ErrorBoundaryState {
27
+ /** 是否发生错误 */
28
+ hasError: boolean;
29
+ /** 错误对象 */
30
+ error: Error | null;
31
+ /** 错误信息 */
32
+ errorInfo: React.ErrorInfo | null;
33
+ }
34
+
35
+ // ============================================================================
36
+ // Error Boundary 组件
37
+ // ============================================================================
38
+
39
+ /**
40
+ * 图表错误边界组件
41
+ * 用于捕获图表渲染过程中的错误,并显示友好的备用 UI
42
+ *
43
+ * @example
44
+ * ```tsx
45
+ * import { ChartErrorBoundary } from '@agions/taroviz'
46
+ *
47
+ * function App() {
48
+ * return (
49
+ * <ChartErrorBoundary
50
+ * onError={(error) => console.error(error)}
51
+ * onRetry={() => console.log('Retrying...')}
52
+ * >
53
+ * <LineChart data={data} />
54
+ * </ChartErrorBoundary>
55
+ * )
56
+ * }
57
+ * ```
58
+ */
59
+ export class ChartErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
60
+ constructor(props: ErrorBoundaryProps) {
61
+ super(props);
62
+ this.state = {
63
+ hasError: false,
64
+ error: null,
65
+ errorInfo: null,
66
+ };
67
+ }
68
+
69
+ static getDerivedStateFromError(error: Error): Partial<ErrorBoundaryState> {
70
+ return {
71
+ hasError: true,
72
+ error,
73
+ };
74
+ }
75
+
76
+ componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void {
77
+ const { onError } = this.props;
78
+
79
+ console.error('Chart Error:', error, errorInfo);
80
+
81
+ this.setState({
82
+ error,
83
+ errorInfo,
84
+ });
85
+
86
+ if (onError) {
87
+ onError(error, errorInfo);
88
+ }
89
+ }
90
+
91
+ handleRetry = (): void => {
92
+ const { onRetry } = this.props;
93
+
94
+ this.setState({
95
+ hasError: false,
96
+ error: null,
97
+ errorInfo: null,
98
+ });
99
+
100
+ if (onRetry) {
101
+ onRetry();
102
+ }
103
+ };
104
+
105
+ render(): ReactNode {
106
+ const { children, fallback, showDetails = false, onRetry } = this.props;
107
+ const { hasError, error, errorInfo } = this.state;
108
+
109
+ if (hasError) {
110
+ // 如果提供了自定义 fallback,使用它
111
+ if (fallback) {
112
+ return fallback;
113
+ }
114
+
115
+ // 默认错误 UI
116
+ return (
117
+ <div style={styles.container}>
118
+ <div style={styles.errorBox}>
119
+ <div style={styles.icon}>⚠️</div>
120
+ <div style={styles.title}>图表渲染出错</div>
121
+
122
+ {showDetails && error && (
123
+ <div style={styles.errorMessage}>{error.message || '未知错误'}</div>
124
+ )}
125
+
126
+ {(onRetry || showDetails) && (
127
+ <div style={styles.actions}>
128
+ {onRetry && (
129
+ <button style={styles.retryButton} onClick={this.handleRetry}>
130
+ 🔄 重试
131
+ </button>
132
+ )}
133
+ {showDetails && errorInfo && (
134
+ <details style={styles.details}>
135
+ <summary style={styles.summary}>查看详情</summary>
136
+ <pre style={styles.pre}>
137
+ {error?.stack || errorInfo.componentStack || '无详细信息'}
138
+ </pre>
139
+ </details>
140
+ )}
141
+ </div>
142
+ )}
143
+ </div>
144
+ </div>
145
+ );
146
+ }
147
+
148
+ return children;
149
+ }
150
+ }
151
+
152
+ // ============================================================================
153
+ // 懒加载组件
154
+ // ============================================================================
155
+
156
+ /** 懒加载属性 */
157
+ export interface LazyChartProps {
158
+ /** 加载时的占位内容 */
159
+ loading?: ReactNode;
160
+ /** 懒加载的图表组件 */
161
+ children: ReactNode;
162
+ /** 加载延迟 (ms),默认 200 */
163
+ delay?: number;
164
+ }
165
+
166
+ /**
167
+ * 图表懒加载组件
168
+ * 用于延迟加载图表组件,优化首屏渲染性能
169
+ *
170
+ * @example
171
+ * ```tsx
172
+ * import { LazyChart } from '@agions/taroviz'
173
+ *
174
+ * function App() {
175
+ * return (
176
+ * <LazyChart loading={<div>加载中...</div>}>
177
+ * <LineChart data={data} />
178
+ * </LazyChart>
179
+ * )
180
+ * }
181
+ * ```
182
+ */
183
+ export function LazyChart({ children, loading = null, delay = 200 }: LazyChartProps) {
184
+ const [show, setShow] = React.useState(false);
185
+
186
+ React.useEffect(() => {
187
+ const timer = setTimeout(() => {
188
+ setShow(true);
189
+ }, delay);
190
+
191
+ return () => clearTimeout(timer);
192
+ }, [delay]);
193
+
194
+ if (!show) {
195
+ return (
196
+ <div style={styles.lazyContainer}>
197
+ {loading || (
198
+ <div style={styles.loading}>
199
+ <div style={styles.spinner}></div>
200
+ <span>加载图表中...</span>
201
+ </div>
202
+ )}
203
+ </div>
204
+ );
205
+ }
206
+
207
+ return <>{children}</>;
208
+ }
209
+
210
+ // ============================================================================
211
+ // 图表 Suspense
212
+ // ============================================================================
213
+
214
+ /**
215
+ * 图表加载状态组件
216
+ * 用于在图表数据加载过程中显示加载动画
217
+ *
218
+ * @example
219
+ * ```tsx
220
+ * import { ChartSkeleton } from '@agions/taroviz'
221
+ *
222
+ * function App() {
223
+ * return (
224
+ * <ChartSkeleton type="line" />
225
+ * )
226
+ * }
227
+ * ```
228
+ */
229
+ export interface ChartSkeletonProps {
230
+ /** 图表类型 */
231
+ type?: 'line' | 'bar' | 'pie' | 'radar' | 'gauge';
232
+ /** 宽度 */
233
+ width?: string | number;
234
+ /** 高度 */
235
+ height?: string | number;
236
+ }
237
+
238
+ /**
239
+ * 图表骨架屏组件
240
+ * 在图表加载时显示占位动画
241
+ */
242
+ export function ChartSkeleton({ type = 'line', width = '100%', height = 400 }: ChartSkeletonProps) {
243
+ const containerStyle: React.CSSProperties = {
244
+ width,
245
+ height,
246
+ display: 'flex',
247
+ flexDirection: 'column',
248
+ gap: '12px',
249
+ padding: '16px',
250
+ };
251
+
252
+ const renderSkeleton = () => {
253
+ switch (type) {
254
+ case 'line':
255
+ case 'bar':
256
+ return (
257
+ <div style={styles.skeletonChart}>
258
+ <div style={styles.skeletonBars}>
259
+ {[40, 65, 45, 80, 55, 70].map((h, i) => (
260
+ <div
261
+ key={i}
262
+ style={{
263
+ ...styles.skeletonBar,
264
+ height: `${h}%`,
265
+ animationDelay: `${i * 0.1}s`,
266
+ }}
267
+ />
268
+ ))}
269
+ </div>
270
+ </div>
271
+ );
272
+ case 'pie':
273
+ return (
274
+ <div style={styles.skeletonChart}>
275
+ <div style={styles.skeletonPie}></div>
276
+ </div>
277
+ );
278
+ case 'radar':
279
+ return (
280
+ <div style={styles.skeletonChart}>
281
+ <div style={styles.skeletonRadar}></div>
282
+ </div>
283
+ );
284
+ case 'gauge':
285
+ return (
286
+ <div style={styles.skeletonChart}>
287
+ <div style={styles.skeletonGauge}></div>
288
+ </div>
289
+ );
290
+ default:
291
+ return null;
292
+ }
293
+ };
294
+
295
+ return (
296
+ <div style={containerStyle}>
297
+ <div style={styles.skeletonTitle}></div>
298
+ {renderSkeleton()}
299
+ </div>
300
+ );
301
+ }
302
+
303
+ // ============================================================================
304
+ // 样式
305
+ // ============================================================================
306
+
307
+ const styles: Record<string, React.CSSProperties> = {
308
+ container: {
309
+ display: 'flex',
310
+ alignItems: 'center',
311
+ justifyContent: 'center',
312
+ minHeight: '200px',
313
+ padding: '20px',
314
+ },
315
+ errorBox: {
316
+ textAlign: 'center',
317
+ padding: '24px',
318
+ background: 'rgba(239, 68, 68, 0.1)',
319
+ border: '1px solid rgba(239, 68, 68, 0.3)',
320
+ borderRadius: '8px',
321
+ maxWidth: '400px',
322
+ },
323
+ icon: {
324
+ fontSize: '32px',
325
+ marginBottom: '8px',
326
+ },
327
+ title: {
328
+ fontSize: '16px',
329
+ fontWeight: 600,
330
+ color: '#dc2626',
331
+ marginBottom: '8px',
332
+ },
333
+ errorMessage: {
334
+ fontSize: '14px',
335
+ color: '#991b1b',
336
+ marginBottom: '16px',
337
+ padding: '8px',
338
+ background: 'rgba(239, 68, 68, 0.1)',
339
+ borderRadius: '4px',
340
+ },
341
+ actions: {
342
+ display: 'flex',
343
+ flexDirection: 'column',
344
+ gap: '12px',
345
+ alignItems: 'center',
346
+ },
347
+ retryButton: {
348
+ padding: '8px 16px',
349
+ background: '#dc2626',
350
+ color: 'white',
351
+ border: 'none',
352
+ borderRadius: '6px',
353
+ cursor: 'pointer',
354
+ fontSize: '14px',
355
+ },
356
+ details: {
357
+ textAlign: 'left',
358
+ width: '100%',
359
+ },
360
+ summary: {
361
+ cursor: 'pointer',
362
+ color: '#666',
363
+ fontSize: '13px',
364
+ marginBottom: '8px',
365
+ },
366
+ pre: {
367
+ fontSize: '12px',
368
+ background: '#1a1a1a',
369
+ color: '#e0e0e0',
370
+ padding: '12px',
371
+ borderRadius: '4px',
372
+ overflow: 'auto',
373
+ maxHeight: '200px',
374
+ },
375
+ lazyContainer: {
376
+ display: 'flex',
377
+ alignItems: 'center',
378
+ justifyContent: 'center',
379
+ minHeight: '200px',
380
+ },
381
+ loading: {
382
+ display: 'flex',
383
+ flexDirection: 'column',
384
+ alignItems: 'center',
385
+ gap: '12px',
386
+ color: '#666',
387
+ },
388
+ spinner: {
389
+ width: '32px',
390
+ height: '32px',
391
+ border: '3px solid #e0e0e0',
392
+ borderTopColor: '#2d8a8a',
393
+ borderRadius: '50%',
394
+ animation: 'spin 1s linear infinite',
395
+ },
396
+ skeletonChart: {
397
+ flex: 1,
398
+ display: 'flex',
399
+ alignItems: 'flex-end',
400
+ justifyContent: 'center',
401
+ },
402
+ skeletonBars: {
403
+ display: 'flex',
404
+ alignItems: 'flex-end',
405
+ gap: '12px',
406
+ height: '100%',
407
+ width: '100%',
408
+ },
409
+ skeletonBar: {
410
+ flex: 1,
411
+ background: 'linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%)',
412
+ backgroundSize: '200% 100%',
413
+ animation: 'shimmer 1.5s infinite',
414
+ borderRadius: '4px 4px 0 0',
415
+ },
416
+ skeletonTitle: {
417
+ width: '40%',
418
+ height: '20px',
419
+ background: 'linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%)',
420
+ backgroundSize: '200% 100%',
421
+ animation: 'shimmer 1.5s infinite',
422
+ borderRadius: '4px',
423
+ },
424
+ skeletonPie: {
425
+ width: '150px',
426
+ height: '150px',
427
+ borderRadius: '50%',
428
+ background: 'linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%)',
429
+ backgroundSize: '200% 100%',
430
+ animation: 'shimmer 1.5s infinite',
431
+ },
432
+ skeletonRadar: {
433
+ width: '150px',
434
+ height: '150px',
435
+ background: 'linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%)',
436
+ backgroundSize: '200% 100%',
437
+ animation: 'shimmer 1.5s infinite',
438
+ clipPath: 'polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)',
439
+ },
440
+ skeletonGauge: {
441
+ width: '200px',
442
+ height: '100px',
443
+ background: 'linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%)',
444
+ backgroundSize: '200% 100%',
445
+ animation: 'shimmer 1.5s infinite',
446
+ borderRadius: '100px 100px 0 0',
447
+ },
448
+ };
449
+
450
+ // ============================================================================
451
+ // 导出
452
+ // ============================================================================
453
+
454
+ export default {
455
+ ChartErrorBoundary,
456
+ LazyChart,
457
+ ChartSkeleton,
458
+ };
@@ -0,0 +1,58 @@
1
+ /**
2
+ * ECharts 组件注册中心
3
+ * 统一管理所有图表组件的注册,避免重复注册
4
+ */
5
+ import * as echarts from 'echarts/core';
6
+
7
+ // 图表类型
8
+ import { PieChart } from 'echarts/charts';
9
+ import { LineChart } from 'echarts/charts';
10
+ import { BarChart } from 'echarts/charts';
11
+ import { GaugeChart } from 'echarts/charts';
12
+ import { ScatterChart } from 'echarts/charts';
13
+ import { RadarChart } from 'echarts/charts';
14
+ import { HeatmapChart } from 'echarts/charts';
15
+ import { FunnelChart } from 'echarts/charts';
16
+
17
+ // 组件
18
+ import {
19
+ TitleComponent,
20
+ TooltipComponent,
21
+ LegendComponent,
22
+ GridComponent,
23
+ DataZoomComponent,
24
+ VisualMapComponent,
25
+ } from 'echarts/components';
26
+
27
+ // 渲染器
28
+ import { CanvasRenderer } from 'echarts/renderers';
29
+
30
+ // 注册渲染器
31
+ echarts.use(CanvasRenderer);
32
+
33
+ // 注册所有图表类型
34
+ const chartTypes = [
35
+ PieChart,
36
+ LineChart,
37
+ BarChart,
38
+ GaugeChart,
39
+ ScatterChart,
40
+ RadarChart,
41
+ HeatmapChart,
42
+ FunnelChart,
43
+ ];
44
+
45
+ // 注册所有组件
46
+ const components = [
47
+ TitleComponent,
48
+ TooltipComponent,
49
+ LegendComponent,
50
+ GridComponent,
51
+ DataZoomComponent,
52
+ VisualMapComponent,
53
+ ];
54
+
55
+ // 统一注册
56
+ echarts.use([...chartTypes, ...components]);
57
+
58
+ export default echarts;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * TaroViz 核心组件库
3
+ * 提供基础组件和工具函数
4
+ */
5
+
6
+ // 类型定义
7
+ export * from './types';
8
+
9
+ // 工具函数
10
+ export * from './utils';
11
+
12
+ // 核心组件
13
+ export type { ChartProps } from './components/BaseChart';
14
+
15
+ // ECharts 统一导出
16
+ export { default as echarts } from './echarts';
17
+
18
+ /**
19
+ * 库信息
20
+ */
21
+ export const name = 'taroviz';
22
+ export const version = '1.2.0';
@@ -0,0 +1,66 @@
1
+ /**
2
+ * 图表类型定义
3
+ */
4
+ import type {
5
+ BarSeriesOption,
6
+ LineSeriesOption,
7
+ PieSeriesOption,
8
+ ScatterSeriesOption,
9
+ RadarSeriesOption,
10
+ } from 'echarts/charts';
11
+ import type {
12
+ TitleComponentOption,
13
+ GridComponentOption,
14
+ LegendComponentOption,
15
+ TooltipComponentOption,
16
+ ToolboxComponentOption,
17
+ DataZoomComponentOption,
18
+ } from 'echarts/components';
19
+ import type { ComposeOption } from 'echarts/core';
20
+
21
+ /**
22
+ * 渲染优化配置
23
+ */
24
+ export interface RenderOptimizationConfig {
25
+ /**
26
+ * 是否启用渐进式渲染
27
+ */
28
+ progressive?: boolean;
29
+
30
+ /**
31
+ * 渐进式渲染阈值
32
+ */
33
+ progressiveThreshold?: number;
34
+
35
+ /**
36
+ * 渐进式渲染模式
37
+ */
38
+ progressiveChunkMode?: 'sequential' | 'mod';
39
+
40
+ /**
41
+ * 是否启用懒更新
42
+ */
43
+ lazyUpdate?: boolean;
44
+
45
+ /**
46
+ * 动画刷新阈值
47
+ */
48
+ animationThreshold?: number;
49
+ }
50
+
51
+ /**
52
+ * 图表配置项类型
53
+ */
54
+ export type ChartOptions = ComposeOption<
55
+ | BarSeriesOption
56
+ | LineSeriesOption
57
+ | PieSeriesOption
58
+ | ScatterSeriesOption
59
+ | RadarSeriesOption
60
+ | TitleComponentOption
61
+ | GridComponentOption
62
+ | LegendComponentOption
63
+ | TooltipComponentOption
64
+ | ToolboxComponentOption
65
+ | DataZoomComponentOption
66
+ >;