@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
@@ -1,221 +1,272 @@
1
1
  /**
2
2
  * 水球图组件
3
- * ECharts 没有内置水球图,使用 echarts-liquidfill 库实现
3
+ *
4
+ * 使用 ECharts 5.x 自定义系列实现水球图功能,
5
+ * 不依赖有 zrender 兼容性问题的 echarts-liquidfill。
4
6
  */
5
- import React, { memo, useEffect, useRef, useMemo } from 'react';
6
- import type { EChartsType, ECElementEvent } from 'echarts';
7
- import { getAdapter } from '../../adapters';
8
- import { uuid } from '../../core/utils';
9
- import { processAdapterConfig } from '../utils';
7
+ import React, { memo, useMemo } from 'react';
8
+ import type { EChartsOption, CustomSeriesRenderItem, CustomSeriesRenderItemReturn } from 'echarts';
10
9
  import { LiquidChartProps } from './types';
10
+ import type { BaseChartProps } from '../types';
11
+ import BaseChartWrapper from '../common/BaseChartWrapper';
12
+
13
+ /** 包装容器的最大半径(px),用于归一化半径 */
14
+ const MAX_RADIUS = 100;
11
15
 
12
16
  /**
13
- * 水球图组件
14
- * 使用 echarts-liquidfill 实现
17
+ * 解析百分比字符串为像素值
15
18
  */
16
- const LiquidChart: React.FC<LiquidChartProps> = memo((props) => {
19
+ function parsePercentToPx(percent: string | undefined, base: number): number {
20
+ if (percent == null) return base;
21
+ if (typeof percent === 'number') return base * (percent / MAX_RADIUS);
22
+ if (typeof percent === 'string' && percent.endsWith('%')) {
23
+ return (parseFloat(percent) / 100) * base;
24
+ }
25
+ return parseFloat(percent) || base;
26
+ }
27
+
28
+ /**
29
+ * 水球图配置构建函数
30
+ * 返回 ECharts custom series 配置
31
+ */
32
+ function buildLiquidOption(props: {
33
+ waveData: number[];
34
+ shape: string;
35
+ amplitude: number | undefined;
36
+ waveLength: number | string | undefined;
37
+ phase: number | undefined;
38
+ period: number | undefined;
39
+ backgroundColor: string;
40
+ colors: string[];
41
+ showLabel: boolean;
42
+ labelFormatter: ((value: number) => string) | undefined;
43
+ }): { series: Record<string, unknown>[] } {
17
44
  const {
18
- option,
19
- width = '100%',
20
- height = '300px',
21
- theme,
22
- style = {},
23
- className = '',
24
- autoResize = true,
25
- loading = false,
26
- loadingOption,
27
- onChartInit,
28
- onChartReady,
29
- renderer = 'canvas',
30
- onEvents = {},
31
- waveData = [0.6],
32
- shape = 'circle',
45
+ waveData,
46
+ shape: _shape,
33
47
  amplitude,
34
48
  waveLength,
35
49
  phase,
36
- period,
37
- backgroundColor = 'transparent',
38
- color,
39
- showLabel = true,
50
+ period: _period,
51
+ backgroundColor,
52
+ colors,
53
+ showLabel,
40
54
  labelFormatter,
41
55
  } = props;
42
56
 
43
- const chartId = useRef<string>(`liquid-${uuid()}`);
44
- const chartInstance = useRef<EChartsType | null>(null);
45
- const containerRef = useRef<HTMLDivElement>(null);
46
- const extensionRegistered = useRef<boolean>(false);
57
+ const actualPhase = phase ?? 0;
58
+ const actualAmplitude = amplitude ?? 8; // 相对于 MAX_RADIUS 的比例
47
59
 
48
- // 构建水球图配置
49
- const liquidOption = useMemo(() => {
50
- const baseOption = option || {};
60
+ // buildLiquidRenderItem - 使用闭包捕获配置
61
+ const renderItem: CustomSeriesRenderItem = (_params, api) => {
62
+ const width = api.getWidth();
63
+ const height = api.getHeight();
64
+ const size = Math.min(width, height);
65
+ const centerX = width / 2;
66
+ const centerY = height / 2;
67
+ const baseRadius = (size / 2) * 0.8;
51
68
 
52
- // 如果用户提供了 option,直接返回
53
- if (baseOption.series && baseOption.series.length > 0) {
54
- return baseOption;
69
+ const ampPx = baseRadius * (actualAmplitude / MAX_RADIUS);
70
+
71
+ let wlPx: number;
72
+ if (waveLength === undefined) {
73
+ wlPx = baseRadius * 0.8;
74
+ } else if (typeof waveLength === 'string') {
75
+ wlPx = parsePercentToPx(waveLength, size);
76
+ } else {
77
+ wlPx = waveLength;
55
78
  }
56
79
 
57
- // 构建水球图 series
58
- const seriesData = waveData.map((value) => {
59
- const dataItem: Record<string, unknown> = { value };
80
+ const itemWidth = width;
81
+ const itemHeight = height;
82
+
83
+ // 背景圆
84
+ const bgCircle = {
85
+ type: 'circle',
86
+ shape: { cx: centerX, cy: centerY, r: baseRadius },
87
+ style: {
88
+ fill: backgroundColor !== 'transparent' ? backgroundColor : '#e3f7ff',
89
+ stroke: '#294d99',
90
+ lineWidth: 8,
91
+ shadowBlur: 20,
92
+ shadowColor: 'rgba(0,0,0,0.25)',
93
+ },
94
+ z2: 0,
95
+ };
60
96
 
61
- if (showLabel && labelFormatter) {
62
- dataItem.label = {
63
- formatter: labelFormatter(value),
97
+ // 波浪多边形
98
+ const waveElements = waveData.map((value, idx) => {
99
+ if (value < 0 || value > 1) {
100
+ return {
101
+ type: 'polygon',
102
+ shape: {
103
+ points: [
104
+ [centerX - baseRadius, centerY],
105
+ [centerX + baseRadius, centerY],
106
+ [centerX + baseRadius, centerY + baseRadius],
107
+ [centerX - baseRadius, centerY + baseRadius],
108
+ ],
109
+ },
110
+ style: { fill: colors[idx % colors.length], opacity: 0 },
111
+ z2: 2 + idx,
64
112
  };
65
113
  }
66
114
 
67
- return dataItem;
115
+ const waterLevel = centerY + baseRadius - value * baseRadius * 2;
116
+ const color = colors[idx % colors.length];
117
+
118
+ // 生成波浪点
119
+ const curves = Math.max(Math.ceil(((2 * baseRadius) / wlPx) * 4) * 2, 8);
120
+ const phaseOffset = (idx * Math.PI) / 4 + actualPhase;
121
+
122
+ const points: [number, number][] = [];
123
+ const numPoints = curves * 4;
124
+ for (let i = 0; i <= numPoints; i++) {
125
+ const t = (i / numPoints) * Math.PI * 2 + phaseOffset;
126
+ const xPos = (i / numPoints) * (baseRadius * 2 + wlPx) - wlPx / 2;
127
+ const yOffset = Math.sin(t) * ampPx;
128
+ // 只保留圆内的点
129
+ if (Math.abs(xPos) <= baseRadius) {
130
+ points.push([centerX + xPos, waterLevel + yOffset]);
131
+ }
132
+ }
133
+
134
+ // 确保至少有两个点
135
+ if (points.length < 2) {
136
+ points.length = 0;
137
+ points.push([centerX - baseRadius, waterLevel]);
138
+ points.push([centerX + baseRadius, waterLevel]);
139
+ }
140
+
141
+ // 闭合路径
142
+ const lastPoint = points[points.length - 1];
143
+ const closedPoints: [number, number][] = [
144
+ ...points,
145
+ [lastPoint[0], centerY + baseRadius],
146
+ [points[0][0], centerY + baseRadius],
147
+ ];
148
+
149
+ return {
150
+ type: 'polygon',
151
+ shape: { points: closedPoints },
152
+ style: {
153
+ fill: color,
154
+ opacity: 0.95,
155
+ shadowBlur: 50,
156
+ shadowColor: 'rgba(0,0,0,0.4)',
157
+ },
158
+ z2: 2 + idx,
159
+ };
68
160
  });
69
161
 
70
- const seriesConfig: Record<string, unknown> = {
71
- type: 'liquidFill',
72
- data: waveData,
73
- shape,
74
- backgroundColor,
75
- color: color || ['#4cabce', '#4cabce'],
76
- label: showLabel
77
- ? {
78
- show: true,
79
- formatter: labelFormatter
80
- ? (params: ECElementEvent) => labelFormatter(params.value as number)
81
- : '{d}%',
82
- textStyle: {
83
- fontSize: 20,
162
+ // 标签
163
+ const labelChildren = showLabel
164
+ ? [
165
+ {
166
+ type: 'text' as const,
167
+ style: {
168
+ text: labelFormatter
169
+ ? labelFormatter(waveData[0] ?? 0)
170
+ : `${Math.round((waveData[0] ?? 0) * 100)}%`,
171
+ x: centerX,
172
+ y: centerY,
173
+ textAlign: 'center' as const,
174
+ textVerticalAlign: 'middle' as const,
175
+ fontSize: Math.max(baseRadius * 0.3, 16),
84
176
  fontWeight: 'bold',
177
+ fill: '#294d99',
85
178
  },
86
- }
87
- : { show: false },
88
- };
179
+ z2: 10,
180
+ },
181
+ ]
182
+ : [];
89
183
 
90
- // 添加可选参数
91
- if (amplitude !== undefined) {
92
- seriesConfig.amplitude = amplitude;
93
- }
94
- if (waveLength !== undefined) {
95
- seriesConfig.waveLength = waveLength;
96
- }
97
- if (phase !== undefined) {
98
- seriesConfig.phase = phase;
99
- }
100
- if (period !== undefined) {
101
- seriesConfig.period = period;
102
- }
184
+ const groupChildren = [bgCircle, ...waveElements, ...labelChildren];
103
185
 
104
186
  return {
105
- ...baseOption,
106
- series: [seriesConfig],
107
- };
108
- }, [option, waveData, shape, backgroundColor, color, showLabel, labelFormatter, amplitude, waveLength, phase, period]);
109
-
110
- // 处理图表初始化
111
- useEffect(() => {
112
- let mounted = true;
113
-
114
- const initChart = async (): Promise<(() => void) | undefined> => {
115
- // 动态导入 echarts-liquidfill 并注册扩展
116
- if (!extensionRegistered.current) {
117
- try {
118
- // eslint-disable-next-line @typescript-eslint/no-require-imports
119
- const liquidfill = require('echarts-liquidfill');
120
- if (liquidfill && mounted) {
121
- liquidfill.register && liquidfill.register();
122
- extensionRegistered.current = true;
123
- }
124
- } catch (e) {
125
- console.warn('[TaroViz] LiquidChart: Failed to load echarts-liquidfill extension', e);
126
- return undefined;
127
- }
128
- }
187
+ type: 'group',
188
+ width: itemWidth,
189
+ height: itemHeight,
190
+ children: groupChildren,
191
+ } as CustomSeriesRenderItemReturn;
192
+ };
129
193
 
130
- if (!mounted || !containerRef.current) return undefined;
131
-
132
- const initConfig = processAdapterConfig({
133
- canvasId: chartId.current,
134
- containerRef,
135
- width,
136
- height,
137
- theme,
138
- autoResize,
139
- renderer,
140
- option: liquidOption,
141
- onInit: (instance: EChartsType) => {
142
- chartInstance.current = instance;
143
-
144
- // 绑定事件
145
- if (onEvents) {
146
- Object.entries(onEvents).forEach(([eventName, handler]) => {
147
- (instance as unknown as { on: (e: string, h: unknown) => void }).on(eventName, handler);
148
- });
149
- }
150
-
151
- if (onChartInit) {
152
- onChartInit(instance);
153
- }
154
-
155
- if (onChartReady) {
156
- onChartReady(instance);
157
- }
158
- },
159
- });
160
-
161
- const adapter = await getAdapter(initConfig);
162
- adapter.init();
163
-
164
- return () => {
165
- if (chartInstance.current) {
166
- if (onEvents) {
167
- Object.keys(onEvents).forEach((eventName) => {
168
- chartInstance.current?.off(eventName);
169
- });
170
- }
171
- chartInstance.current.dispose();
172
- chartInstance.current = null;
173
- }
174
- };
175
- };
194
+ const customSeries = {
195
+ type: 'custom' as const,
196
+ renderItem,
197
+ data: waveData.map((value) => ({ value })),
198
+ animation: false,
199
+ };
176
200
 
177
- let cleanupFn: (() => void) | undefined;
178
- initChart().then((cleanup) => {
179
- cleanupFn = cleanup;
180
- });
201
+ return {
202
+ series: [customSeries],
203
+ };
204
+ }
181
205
 
182
- return () => {
183
- mounted = false;
184
- cleanupFn?.();
185
- };
186
- }, [liquidOption, width, height, theme, autoResize, renderer, onChartInit, onChartReady, onEvents]);
206
+ /**
207
+ * 水球图组件
208
+ */
209
+ const LiquidChart: React.FC<LiquidChartProps> = memo((props) => {
210
+ const {
211
+ option,
212
+ waveData = [0.6],
213
+ shape,
214
+ amplitude,
215
+ waveLength,
216
+ phase,
217
+ period,
218
+ backgroundColor = 'transparent',
219
+ color,
220
+ showLabel = true,
221
+ labelFormatter,
222
+ ...rest
223
+ } = props;
187
224
 
188
- // 更新配置
189
- useEffect(() => {
190
- if (chartInstance.current && liquidOption) {
191
- chartInstance.current.setOption(liquidOption, true);
192
- }
193
- }, [liquidOption]);
194
-
195
- // 控制加载状态
196
- useEffect(() => {
197
- if (chartInstance.current) {
198
- if (loading) {
199
- chartInstance.current.showLoading(loadingOption);
200
- } else {
201
- chartInstance.current.hideLoading();
202
- }
225
+ const liquidOption = useMemo((): EChartsOption => {
226
+ const baseOption = (option || {}) as EChartsOption;
227
+
228
+ // 如果用户提供了 series 配置,直接返回
229
+ if (baseOption.series && Array.isArray(baseOption.series) && baseOption.series.length > 0) {
230
+ return baseOption;
203
231
  }
204
- }, [loading, loadingOption]);
205
232
 
206
- // 自定义样式
207
- const mergedStyle = {
208
- width: typeof width === 'number' ? `${width}px` : width,
209
- height: typeof height === 'number' ? `${height}px` : height,
210
- ...style,
211
- };
233
+ const colors = color || ['#4cabce', '#4cabce'];
234
+
235
+ const customConfig = buildLiquidOption({
236
+ waveData,
237
+ shape: shape ?? 'circle',
238
+ amplitude,
239
+ waveLength,
240
+ phase,
241
+ period,
242
+ backgroundColor,
243
+ colors,
244
+ showLabel,
245
+ labelFormatter,
246
+ });
247
+
248
+ return {
249
+ ...baseOption,
250
+ series: customConfig.series as EChartsOption['series'],
251
+ };
252
+ }, [
253
+ option,
254
+ waveData,
255
+ shape,
256
+ amplitude,
257
+ waveLength,
258
+ phase,
259
+ period,
260
+ backgroundColor,
261
+ color,
262
+ showLabel,
263
+ labelFormatter,
264
+ ]);
265
+
266
+ if (!liquidOption) return null;
212
267
 
213
268
  return (
214
- <div
215
- className={`taroviz-liquid ${className}`}
216
- style={mergedStyle}
217
- ref={containerRef as React.RefObject<HTMLDivElement>}
218
- />
269
+ <BaseChartWrapper {...(rest as BaseChartProps)} option={liquidOption} chartType="liquid" />
219
270
  );
220
271
  });
221
272
 
@@ -224,4 +275,10 @@ LiquidChart.displayName = 'LiquidChart';
224
275
  export default LiquidChart;
225
276
 
226
277
  // 导出类型
227
- export type { LiquidChartProps, LiquidOption, LiquidShape, LiquidSeries, LiquidSeriesDataItem } from './types';
278
+ export type {
279
+ LiquidChartProps,
280
+ LiquidOption,
281
+ LiquidShape,
282
+ LiquidSeries,
283
+ LiquidSeriesDataItem,
284
+ } from './types';
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * 水球图类型定义
3
- * ECharts 没有内置水球图,使用 echarts-liquidfill 库实现
3
+ * ECharts 没有内置水球图,使用自定义实现
4
4
  */
5
5
  import type React from 'react';
6
6
  import type { EChartsOption, EChartsType, ECElementEvent } from 'echarts';
@@ -12,7 +12,7 @@ import type { EChartsOption, EChartsType, ECElementEvent } from 'echarts';
12
12
  /** 水球图系列数据项 */
13
13
  export interface LiquidSeriesDataItem {
14
14
  /** 数据值,范围 [0, 1] */
15
- value: number;
15
+ _value: number;
16
16
  /** 数据项名称 */
17
17
  name?: string;
18
18
  /** 图形样式 */
@@ -28,15 +28,15 @@ export type LiquidShape = 'circle' | 'rect' | 'roundRect';
28
28
 
29
29
  /** 水球图系列配置 */
30
30
  export interface LiquidSeries {
31
- /** 系列类型 */
32
- type?: 'liquidFill';
31
+ /** 系列类型(仅用于文档,实际渲染使用 custom series) */
32
+ type?: 'liquidFill' | 'custom';
33
33
  /** 系列名称 */
34
34
  name?: string;
35
35
  /** 数据数组 */
36
36
  data?: (number | LiquidSeriesDataItem)[];
37
37
  /** 图形形状 */
38
38
  shape?: LiquidShape;
39
- /** 振幅 (相对于半径的比例) */
39
+ /** 振幅 (相对于半径的比例,0-100) */
40
40
  amplitude?: number;
41
41
  /** 波长 (相对于画布宽度) */
42
42
  waveLength?: number | string;
@@ -53,7 +53,7 @@ export interface LiquidSeries {
53
53
  /** 动画缓动函数 */
54
54
  animationEasing?: string;
55
55
  /** 动画延迟 */
56
- animationDelay?: number | ((idx: number) => number);
56
+ animationDelay?: number | ((_idx: number) => number);
57
57
  /** 颜色数组 */
58
58
  color?: string[];
59
59
  /** 背景色 */
@@ -91,7 +91,7 @@ export interface LiquidChartProps {
91
91
  waveData?: number[];
92
92
  /** 图形形状 */
93
93
  shape?: LiquidShape;
94
- /** 振幅 (相对于半径的比例) */
94
+ /** 振幅 (相对于半径的比例,0-100) */
95
95
  amplitude?: number;
96
96
  /** 波长 (相对于画布宽度) */
97
97
  waveLength?: number | string;
@@ -106,7 +106,7 @@ export interface LiquidChartProps {
106
106
  /** 是否显示标签 */
107
107
  showLabel?: boolean;
108
108
  /** 标签格式化 */
109
- labelFormatter?: (value: number) => string;
109
+ labelFormatter?: (_value: number) => string;
110
110
  /** 主题 */
111
111
  theme?: string | Record<string, unknown>;
112
112
  /** 样式 */
@@ -122,9 +122,9 @@ export interface LiquidChartProps {
122
122
  /** 加载配置 */
123
123
  loadingOption?: Record<string, unknown>;
124
124
  /** 图表初始化回调 */
125
- onChartInit?: (chart: EChartsType) => void;
125
+ onChartInit?: (_chart: EChartsType) => void;
126
126
  /** 图表就绪回调 */
127
- onChartReady?: (chart: EChartsType) => void;
127
+ onChartReady?: (_chart: EChartsType) => void;
128
128
  /** 事件回调 */
129
- onEvents?: Record<string, (params: ECElementEvent) => void>;
129
+ onEvents?: Record<string, (_params: ECElementEvent) => void>;
130
130
  }