@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.
- package/CHANGELOG.md +245 -0
- package/README.md +104 -302
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/vendors.js +1 -0
- package/dist/cjs/vendors~echarts.js +1 -0
- package/dist/esm/index.js +1 -58151
- package/dist/esm/vendors.js +1 -0
- package/dist/esm/vendors~echarts.js +1 -0
- package/package.json +19 -25
- package/src/adapters/MiniAppAdapter.ts +136 -0
- package/src/adapters/__tests__/index.test.ts +1 -1
- package/src/adapters/h5/__tests__/index.test.ts +4 -2
- package/src/adapters/h5/index.ts +63 -64
- package/src/adapters/harmony/index.ts +23 -245
- package/src/adapters/index.ts +49 -45
- package/src/adapters/swan/index.ts +6 -69
- package/src/adapters/tt/index.ts +7 -70
- package/src/adapters/types.ts +25 -58
- package/src/adapters/weapp/index.ts +6 -69
- package/src/charts/__tests__/testUtils.tsx +87 -0
- package/src/charts/boxplot/__tests__/index.test.tsx +49 -103
- package/src/charts/boxplot/index.tsx +2 -1
- package/src/charts/boxplot/types.ts +17 -16
- package/src/charts/common/BaseChartWrapper.tsx +90 -82
- package/src/charts/common/__mocks__/BaseChartWrapper.tsx +17 -0
- package/src/charts/createChartComponent.tsx +36 -0
- package/src/charts/createOptionChartComponent.tsx +32 -0
- package/src/charts/funnel/__tests__/index.test.tsx +99 -0
- package/src/charts/funnel/index.tsx +60 -10
- package/src/charts/funnel/types.ts +6 -0
- package/src/charts/graph/__tests__/index.test.tsx +102 -33
- package/src/charts/graph/index.tsx +66 -9
- package/src/charts/graph/types.ts +6 -0
- package/src/charts/heatmap/__tests__/index.test.tsx +139 -0
- package/src/charts/heatmap/index.tsx +103 -10
- package/src/charts/heatmap/types.ts +6 -0
- package/src/charts/index.ts +74 -26
- package/src/charts/liquid/__tests__/index.test.tsx +52 -0
- package/src/charts/liquid/index.tsx +239 -182
- package/src/charts/liquid/types.ts +11 -11
- package/src/charts/parallel/__tests__/index.test.tsx +40 -67
- package/src/charts/parallel/index.tsx +2 -1
- package/src/charts/parallel/types.ts +19 -18
- package/src/charts/radar/__tests__/index.test.tsx +210 -0
- package/src/charts/radar/index.tsx +143 -10
- package/src/charts/radar/types.ts +13 -0
- package/src/charts/sankey/__tests__/index.test.tsx +124 -0
- package/src/charts/sankey/index.tsx +62 -10
- package/src/charts/sankey/types.ts +6 -0
- package/src/charts/tree/__tests__/index.test.tsx +71 -0
- package/src/charts/tree/index.tsx +5 -2
- package/src/charts/tree/types.ts +9 -9
- package/src/charts/types.ts +208 -106
- package/src/charts/utils.ts +9 -7
- package/src/charts/wordcloud/__tests__/index.test.tsx +98 -31
- package/src/charts/wordcloud/index.tsx +75 -9
- package/src/charts/wordcloud/types.ts +6 -0
- package/src/components/DataFilter/index.tsx +32 -10
- package/src/core/animation/types.ts +6 -6
- package/src/core/components/Annotation.tsx +6 -7
- package/src/core/components/BaseChart.tsx +110 -168
- package/src/core/components/ErrorBoundary.tsx +17 -4
- package/src/core/components/LazyChart.tsx +54 -55
- package/src/core/components/hooks/index.ts +6 -2
- package/src/core/components/hooks/useChartInit.ts +6 -3
- package/src/core/components/hooks/usePerformance.ts +8 -2
- package/src/core/components/hooks/useVirtualScroll.ts +2 -1
- package/src/core/index.ts +1 -1
- package/src/core/themes/ThemeManager.ts +1 -1
- package/src/core/types/common.ts +2 -1
- package/src/core/types/index.ts +0 -12
- package/src/core/types/platform.ts +3 -5
- package/src/core/utils/__tests__/deepClone.test.ts +317 -0
- package/src/core/utils/__tests__/index.test.ts +2 -1
- package/src/core/utils/chartInstances.ts +13 -0
- package/src/core/utils/common.ts +20 -29
- package/src/core/utils/deepClone.ts +114 -0
- package/src/core/utils/download.ts +128 -0
- package/src/core/utils/drillDown.ts +34 -353
- package/src/core/utils/drillDownHelpers.ts +426 -0
- package/src/core/utils/events.ts +12 -0
- package/src/core/utils/export/ExportUtils.ts +36 -67
- package/src/core/utils/format.ts +44 -0
- package/src/core/utils/index.ts +21 -154
- package/src/core/utils/merge.ts +25 -0
- package/src/core/utils/performance/PerformanceAnalyzer.ts +38 -21
- package/src/core/utils/performance/hooks.ts +7 -0
- package/src/core/utils/performance/index.ts +2 -0
- package/src/{hooks → core/utils/performance}/useAnimation.ts +45 -41
- package/src/core/utils/performance/useDataZoom.ts +324 -0
- package/src/{hooks → core/utils/performance}/usePerformance.ts +49 -41
- package/src/core/utils/performance/usePerformanceHooks.ts +278 -0
- package/src/core/utils/performanceUtils.ts +310 -0
- package/src/core/utils/runtime.ts +190 -0
- package/src/core/utils/setOptionUtils.ts +59 -0
- package/src/core/version.ts +14 -0
- package/src/editor/EnhancedThemeEditor.tsx +362 -540
- package/src/editor/ThemeEditor.tsx +55 -321
- package/src/editor/components/ThemeBasicSettings.tsx +113 -0
- package/src/editor/components/ThemeColorEditor.tsx +105 -0
- package/src/editor/components/ThemeSelector.tsx +70 -0
- package/src/editor/hooks/useThemeEditorState.ts +201 -0
- package/src/editor/index.ts +10 -2
- package/src/hooks/__tests__/index.test.tsx +3 -1
- package/src/hooks/chartConnectHelpers.ts +341 -0
- package/src/hooks/index.ts +55 -660
- package/src/hooks/types.ts +189 -0
- package/src/hooks/useChartAutoResize.ts +73 -0
- package/src/hooks/useChartConnect.ts +92 -238
- package/src/hooks/useChartDownload.ts +25 -27
- package/src/hooks/useChartHistory.ts +34 -49
- package/src/hooks/useChartInit.ts +59 -0
- package/src/hooks/useChartOptions.ts +259 -0
- package/src/hooks/useChartPerformance.ts +109 -0
- package/src/hooks/useChartSelection.ts +52 -49
- package/src/hooks/useChartTheme.ts +51 -0
- package/src/hooks/useDataTransform.ts +19 -4
- package/src/hooks/utils/chartDownloadUtils.ts +40 -53
- package/src/hooks/utils/dataTransformUtils.ts +22 -0
- package/src/index.ts +48 -34
- package/src/main.tsx +4 -9
- package/src/react-dom.d.ts +3 -3
- package/src/themes/index.ts +30 -855
- package/src/themes/palettes/blue-green.ts +13 -0
- package/src/themes/palettes/chalk.ts +13 -0
- package/src/themes/palettes/cyber.ts +44 -0
- package/src/themes/palettes/dark.ts +52 -0
- package/src/themes/palettes/default.ts +52 -0
- package/src/themes/palettes/elegant.ts +34 -0
- package/src/themes/palettes/forest.ts +13 -0
- package/src/themes/palettes/glass.ts +49 -0
- package/src/themes/palettes/golden.ts +13 -0
- package/src/themes/palettes/neon.ts +43 -0
- package/src/themes/palettes/ocean.ts +39 -0
- package/src/themes/palettes/pastel.ts +37 -0
- package/src/themes/palettes/purple-passion.ts +13 -0
- package/src/themes/palettes/retro.ts +33 -0
- package/src/themes/palettes/sunset.ts +40 -0
- package/src/themes/palettes/walden.ts +13 -0
- package/src/themes/registry.ts +184 -0
- package/src/themes/types.ts +213 -0
- package/src/charts/bar/__tests__/index.test.tsx +0 -113
- package/src/charts/bar/index.tsx +0 -14
- package/src/charts/candlestick/__tests__/index.test.tsx +0 -40
- package/src/charts/candlestick/index.tsx +0 -13
- package/src/charts/gauge/index.tsx +0 -14
- package/src/charts/line/__tests__/index.test.tsx +0 -107
- package/src/charts/line/index.tsx +0 -15
- package/src/charts/pie/__tests__/index.test.tsx +0 -112
- package/src/charts/pie/index.tsx +0 -14
- package/src/charts/scatter/index.tsx +0 -14
- package/src/charts/sunburst/index.tsx +0 -18
- package/src/charts/treemap/index.tsx +0 -18
- package/src/core/utils/codeGenerator/CodeGenerator.ts +0 -669
- package/src/core/utils/codeGenerator/index.ts +0 -13
- package/src/core/utils/codeGenerator/types.ts +0 -198
- package/src/core/utils/configGenerator/ConfigGenerator.ts +0 -583
- package/src/core/utils/configGenerator/index.ts +0 -13
- package/src/core/utils/configGenerator/types.ts +0 -445
- package/src/core/utils/debug/DebugPanel.tsx +0 -637
- package/src/core/utils/debug/debugger.ts +0 -322
- package/src/core/utils/debug/index.ts +0 -21
- package/src/core/utils/debug/types.ts +0 -142
- package/src/hooks/useDataZoom.ts +0 -323
|
@@ -1,13 +1,70 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* TaroViz 关系图组件
|
|
3
|
+
*
|
|
4
|
+
* 基于 ECharts graph 系列实现关系图/力导向图可视化
|
|
3
5
|
*/
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
import { createOptionChartComponent } from '@/charts/createOptionChartComponent';
|
|
7
|
+
import type { GraphChartProps } from './types';
|
|
8
|
+
// 类型 GraphNode、GraphLink 通过下方 export type 导出供外部使用
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 构建关系图 ECharts option
|
|
12
|
+
*/
|
|
13
|
+
function buildGraphOption(props: GraphChartProps) {
|
|
14
|
+
const { nodes, links, layout, force, draggable, optionMerge } = props;
|
|
15
|
+
|
|
16
|
+
// 验证数据
|
|
17
|
+
if (!nodes || nodes.length === 0) {
|
|
18
|
+
console.warn('[TaroViz] GraphChart: nodes is required');
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// 构建关系图 series
|
|
23
|
+
const series: any = {
|
|
24
|
+
type: 'graph' as const,
|
|
25
|
+
layout: layout || 'force',
|
|
26
|
+
data: nodes,
|
|
27
|
+
links: links || [],
|
|
28
|
+
draggable: draggable !== false,
|
|
29
|
+
label: {
|
|
30
|
+
show: true,
|
|
31
|
+
position: 'right',
|
|
32
|
+
},
|
|
33
|
+
emphasis: {
|
|
34
|
+
focus: 'adjacency',
|
|
35
|
+
lineStyle: {
|
|
36
|
+
width: 4,
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// 添加力导向布局配置
|
|
42
|
+
if (layout === 'force' && force) {
|
|
43
|
+
series.force = force;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const option: any = {
|
|
47
|
+
tooltip: {
|
|
48
|
+
trigger: 'item',
|
|
49
|
+
formatter: (params: any) => {
|
|
50
|
+
if (!params || !params.data) return '';
|
|
51
|
+
return `<b>${params.data.name}</b>`;
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
legend: {
|
|
55
|
+
data: nodes.map((n) => n.name),
|
|
56
|
+
},
|
|
57
|
+
series,
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// 合并自定义配置
|
|
61
|
+
if (optionMerge) {
|
|
62
|
+
Object.assign(option, optionMerge);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return option;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const GraphChart = createOptionChartComponent<GraphChartProps>('GraphChart', buildGraphOption);
|
|
12
69
|
|
|
13
70
|
export default GraphChart;
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HeatmapChart 组件测试
|
|
3
|
+
*/
|
|
4
|
+
import React from 'react';
|
|
5
|
+
import { render, screen } from '@testing-library/react';
|
|
6
|
+
import '@testing-library/jest-dom';
|
|
7
|
+
import HeatmapChart from '../index';
|
|
8
|
+
|
|
9
|
+
// 使用正确的 mock 方式,参考 parallel 图表的测试
|
|
10
|
+
jest.mock('../../common/BaseChartWrapper');
|
|
11
|
+
jest.mock('echarts/charts', () => ({ HeatmapChart: jest.fn() }));
|
|
12
|
+
|
|
13
|
+
describe('HeatmapChart', () => {
|
|
14
|
+
const mockXData = ['周一', '周二', '周三', '周四', '周五'];
|
|
15
|
+
const mockYData = ['A', 'B', 'C', 'D'];
|
|
16
|
+
const mockData = [
|
|
17
|
+
{ x: 0, y: 0, value: 10 },
|
|
18
|
+
{ x: 1, y: 0, value: 20 },
|
|
19
|
+
{ x: 2, y: 0, value: 30 },
|
|
20
|
+
{ x: 3, y: 0, value: 40 },
|
|
21
|
+
{ x: 4, y: 0, value: 50 },
|
|
22
|
+
{ x: 0, y: 1, value: 15 },
|
|
23
|
+
{ x: 1, y: 1, value: 25 },
|
|
24
|
+
{ x: 2, y: 1, value: 35 },
|
|
25
|
+
{ x: 3, y: 1, value: 45 },
|
|
26
|
+
{ x: 4, y: 1, value: 55 },
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
it('应该渲染热力图组件', () => {
|
|
30
|
+
render(
|
|
31
|
+
<HeatmapChart xData={mockXData} yData={mockYData} data={mockData} width={600} height={400} />
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
expect(screen.getByTestId('base-chart-wrapper')).toBeInTheDocument();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('应该传递正确的 option 到 BaseChart', () => {
|
|
38
|
+
render(
|
|
39
|
+
<HeatmapChart xData={mockXData} yData={mockYData} data={mockData} width={600} height={400} />
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
const baseChartWrapper = screen.getByTestId('base-chart-wrapper');
|
|
43
|
+
const optionElement = baseChartWrapper.querySelector('[data-testid="chart-option"]');
|
|
44
|
+
const option = JSON.parse(optionElement?.textContent || '{}');
|
|
45
|
+
|
|
46
|
+
expect(option.xAxis).toBeDefined();
|
|
47
|
+
expect(option.xAxis.data).toEqual(mockXData);
|
|
48
|
+
expect(option.yAxis).toBeDefined();
|
|
49
|
+
expect(option.yAxis.data).toEqual(mockYData);
|
|
50
|
+
expect(option.series).toBeDefined();
|
|
51
|
+
expect(option.series.type).toBe('heatmap');
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('当 xData 为空时应该返回 null', () => {
|
|
55
|
+
const { container } = render(
|
|
56
|
+
<HeatmapChart xData={[]} yData={mockYData} data={mockData} width={600} height={400} />
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
expect(container.firstChild).toBeNull();
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('当 yData 为空时应该返回 null', () => {
|
|
63
|
+
const { container } = render(
|
|
64
|
+
<HeatmapChart xData={mockXData} yData={[]} data={mockData} width={600} height={400} />
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
expect(container.firstChild).toBeNull();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('当 data 为空时应该返回 null', () => {
|
|
71
|
+
const { container } = render(
|
|
72
|
+
<HeatmapChart xData={mockXData} yData={mockYData} data={[]} width={600} height={400} />
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
expect(container.firstChild).toBeNull();
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('应该支持自定义 visualMap', () => {
|
|
79
|
+
render(
|
|
80
|
+
<HeatmapChart
|
|
81
|
+
xData={mockXData}
|
|
82
|
+
yData={mockYData}
|
|
83
|
+
data={mockData}
|
|
84
|
+
visualMap={{
|
|
85
|
+
min: 5,
|
|
86
|
+
max: 60,
|
|
87
|
+
orient: 'vertical',
|
|
88
|
+
right: 10,
|
|
89
|
+
top: 'center',
|
|
90
|
+
}}
|
|
91
|
+
width={600}
|
|
92
|
+
height={400}
|
|
93
|
+
/>
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
const baseChartWrapper = screen.getByTestId('base-chart-wrapper');
|
|
97
|
+
const optionElement = baseChartWrapper.querySelector('[data-testid="chart-option"]');
|
|
98
|
+
const option = JSON.parse(optionElement?.textContent || '{}');
|
|
99
|
+
|
|
100
|
+
expect(option.visualMap.min).toBe(5);
|
|
101
|
+
expect(option.visualMap.max).toBe(60);
|
|
102
|
+
expect(option.visualMap.orient).toBe('vertical');
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('应该支持 optionMerge 自定义配置', () => {
|
|
106
|
+
const customTitle = { title: { text: '热力图标题', left: 'center' } };
|
|
107
|
+
|
|
108
|
+
render(
|
|
109
|
+
<HeatmapChart
|
|
110
|
+
xData={mockXData}
|
|
111
|
+
yData={mockYData}
|
|
112
|
+
data={mockData}
|
|
113
|
+
optionMerge={customTitle}
|
|
114
|
+
width={600}
|
|
115
|
+
height={400}
|
|
116
|
+
/>
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
const baseChartWrapper = screen.getByTestId('base-chart-wrapper');
|
|
120
|
+
const optionElement = baseChartWrapper.querySelector('[data-testid="chart-option"]');
|
|
121
|
+
const option = JSON.parse(optionElement?.textContent || '{}');
|
|
122
|
+
|
|
123
|
+
expect(option.title).toEqual(customTitle.title);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it('应该正确转换数据格式', () => {
|
|
127
|
+
render(
|
|
128
|
+
<HeatmapChart xData={mockXData} yData={mockYData} data={mockData} width={600} height={400} />
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
const baseChartWrapper = screen.getByTestId('base-chart-wrapper');
|
|
132
|
+
const optionElement = baseChartWrapper.querySelector('[data-testid="chart-option"]');
|
|
133
|
+
const option = JSON.parse(optionElement?.textContent || '{}');
|
|
134
|
+
|
|
135
|
+
// 验证数据被正确转换为 [x, y, value] 格式
|
|
136
|
+
expect(option.series.data[0]).toEqual([0, 0, 10]);
|
|
137
|
+
expect(option.series.data[4]).toEqual([4, 0, 50]);
|
|
138
|
+
});
|
|
139
|
+
});
|
|
@@ -1,14 +1,107 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* TaroViz 热力图组件
|
|
3
|
+
*
|
|
4
|
+
* 基于 ECharts heatmap 系列实现二维数据密度可视化
|
|
3
5
|
*/
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
)
|
|
12
|
-
|
|
6
|
+
import { createOptionChartComponent } from '@/charts/createOptionChartComponent';
|
|
7
|
+
import type { HeatmapChartProps } from './types';
|
|
8
|
+
// 类型 HeatmapDataItem、HeatmapAxis 通过下方 export type 导出供外部使用
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* 构建热力图 ECharts option
|
|
12
|
+
*/
|
|
13
|
+
function buildHeatmapOption(props: HeatmapChartProps) {
|
|
14
|
+
const { xData, yData, data, visualMap, optionMerge } = props;
|
|
15
|
+
|
|
16
|
+
// 验证数据
|
|
17
|
+
if (!xData || xData.length === 0) {
|
|
18
|
+
console.warn('[TaroViz] HeatmapChart: xData is required');
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (!yData || yData.length === 0) {
|
|
23
|
+
console.warn('[TaroViz] HeatmapChart: yData is required');
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (!data || data.length === 0) {
|
|
28
|
+
console.warn('[TaroViz] HeatmapChart: data is required');
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// 构建热力图 series
|
|
33
|
+
const series = {
|
|
34
|
+
type: 'heatmap' as const,
|
|
35
|
+
data: data.map((item) => [item.x, item.y, item.value]),
|
|
36
|
+
label: {
|
|
37
|
+
show: true,
|
|
38
|
+
formatter: (params: any) => {
|
|
39
|
+
if (!params || params.value?.length !== 3) return '';
|
|
40
|
+
return params.value[2];
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
emphasis: {
|
|
44
|
+
itemStyle: {
|
|
45
|
+
shadowBlur: 10,
|
|
46
|
+
shadowColor: 'rgba(0, 0, 0, 0.5)',
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// 构建坐标轴
|
|
52
|
+
const xAxis: any = {
|
|
53
|
+
type: 'category',
|
|
54
|
+
data: xData,
|
|
55
|
+
axisLabel: {
|
|
56
|
+
rotate: xData.length > 10 ? 45 : 0,
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const yAxis: any = {
|
|
61
|
+
type: 'category',
|
|
62
|
+
data: yData,
|
|
63
|
+
axisLabel: {
|
|
64
|
+
rotate: yData.length > 10 ? 45 : 0,
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// 构建 visualMap
|
|
69
|
+
const visualMapConfig = visualMap || {
|
|
70
|
+
min: 0,
|
|
71
|
+
max: Math.max(...data.map((d) => d.value)),
|
|
72
|
+
calculable: true,
|
|
73
|
+
orient: 'horizontal',
|
|
74
|
+
left: 'center',
|
|
75
|
+
top: 'bottom',
|
|
76
|
+
text: ['高', '低'],
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const option: any = {
|
|
80
|
+
tooltip: {
|
|
81
|
+
position: 'top',
|
|
82
|
+
formatter: (params: any) => {
|
|
83
|
+
if (!params || !params.data) return '';
|
|
84
|
+
const [x, y, value] = params.data;
|
|
85
|
+
return `<b>${x} × ${y}</b><br/>值: ${value}`;
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
xAxis,
|
|
89
|
+
yAxis,
|
|
90
|
+
series,
|
|
91
|
+
visualMap: visualMapConfig,
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
// 合并自定义配置
|
|
95
|
+
if (optionMerge) {
|
|
96
|
+
Object.assign(option, optionMerge);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return option;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const HeatmapChart = createOptionChartComponent<HeatmapChartProps>(
|
|
103
|
+
'HeatmapChart',
|
|
104
|
+
buildHeatmapOption
|
|
105
|
+
);
|
|
13
106
|
|
|
14
107
|
export default HeatmapChart;
|
package/src/charts/index.ts
CHANGED
|
@@ -1,39 +1,87 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* TaroViz 图表组件集合
|
|
3
|
+
* 使用工厂函数消除重复代码
|
|
3
4
|
*/
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
import { createChartComponent } from './createChartComponent';
|
|
7
|
+
import type {
|
|
8
|
+
LineChartProps,
|
|
9
|
+
BarChartProps,
|
|
10
|
+
PieChartProps,
|
|
11
|
+
ScatterChartProps,
|
|
12
|
+
TreeMapChartProps,
|
|
13
|
+
SunburstChartProps,
|
|
14
|
+
} from './types';
|
|
15
|
+
|
|
16
|
+
// ===== 标准图表(用工厂函数创建)=====
|
|
17
|
+
|
|
18
|
+
/** 基础图表 */
|
|
19
|
+
export const LineChart = createChartComponent<LineChartProps>('LineChart', 'line-chart');
|
|
20
|
+
export const BarChart = createChartComponent<BarChartProps>('BarChart', 'bar-chart');
|
|
21
|
+
export const PieChart = createChartComponent<PieChartProps>('PieChart', 'pie-chart');
|
|
22
|
+
export const ScatterChart = createChartComponent<ScatterChartProps>(
|
|
23
|
+
'ScatterChart',
|
|
24
|
+
'scatter-chart'
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
/** 扩展图表 */
|
|
28
|
+
export const TreeMapChart = createChartComponent<TreeMapChartProps>(
|
|
29
|
+
'TreeMapChart',
|
|
30
|
+
'treemap-chart'
|
|
31
|
+
);
|
|
32
|
+
export const SunburstChart = createChartComponent<SunburstChartProps>(
|
|
33
|
+
'SunburstChart',
|
|
34
|
+
'sunburst-chart'
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
// ===== 特殊图表(自定义实现)=====
|
|
38
|
+
|
|
39
|
+
/** 热力图 - 使用自定义实现 */
|
|
11
40
|
export { default as HeatmapChart } from './heatmap';
|
|
12
|
-
export { default as GaugeChart } from './gauge';
|
|
13
|
-
export { default as FunnelChart } from './funnel';
|
|
14
41
|
|
|
15
|
-
|
|
16
|
-
export { default as
|
|
17
|
-
export { default as SunburstChart } from './sunburst';
|
|
18
|
-
export { default as SankeyChart } from './sankey';
|
|
42
|
+
/** 漏斗图 - 使用自定义实现 */
|
|
43
|
+
export { default as FunnelChart } from './funnel';
|
|
19
44
|
|
|
20
|
-
|
|
21
|
-
export { default as
|
|
22
|
-
export { default as CandlestickChart } from './candlestick';
|
|
23
|
-
export { default as WordCloudChart } from './wordcloud';
|
|
45
|
+
/** 平行坐标图 - 使用自定义实现 */
|
|
46
|
+
export { default as ParallelChart } from './parallel';
|
|
24
47
|
|
|
25
|
-
|
|
48
|
+
/** 箱线图 - 使用自定义实现 */
|
|
26
49
|
export { default as BoxplotChart } from './boxplot';
|
|
27
|
-
export { default as ParallelChart } from './parallel';
|
|
28
50
|
|
|
29
|
-
|
|
30
|
-
export { default as LiquidChart } from './liquid';
|
|
51
|
+
/** 树图 - 使用自定义实现 */
|
|
31
52
|
export { default as TreeChart } from './tree';
|
|
32
53
|
|
|
33
|
-
|
|
34
|
-
export
|
|
54
|
+
/** 雷达图 - 使用自定义实现 */
|
|
55
|
+
export { default as RadarChartCustom } from './radar';
|
|
35
56
|
|
|
36
|
-
/**
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
57
|
+
/** 关系图 - 使用自定义实现 */
|
|
58
|
+
export { default as GraphChart } from './graph';
|
|
59
|
+
|
|
60
|
+
/** 桑基图 - 使用自定义实现 */
|
|
61
|
+
export { default as SankeyChart } from './sankey';
|
|
62
|
+
|
|
63
|
+
/** 词云图 - 使用自定义实现 */
|
|
64
|
+
export { default as WordCloudChart } from './wordcloud';
|
|
65
|
+
|
|
66
|
+
// ===== 类型导出 =====
|
|
67
|
+
|
|
68
|
+
export type {
|
|
69
|
+
BaseChartProps,
|
|
70
|
+
LineChartProps,
|
|
71
|
+
BarChartProps,
|
|
72
|
+
PieChartProps,
|
|
73
|
+
ScatterChartProps,
|
|
74
|
+
RadarChartProps,
|
|
75
|
+
FunnelChartProps,
|
|
76
|
+
HeatmapChartProps,
|
|
77
|
+
SunburstChartProps,
|
|
78
|
+
TreeMapChartProps,
|
|
79
|
+
SankeyChartProps,
|
|
80
|
+
GraphChartProps,
|
|
81
|
+
WordCloudChartProps,
|
|
82
|
+
BoxplotChartProps,
|
|
83
|
+
TreeChartProps,
|
|
84
|
+
} from './types';
|
|
85
|
+
|
|
86
|
+
// 特殊图表类型(从独立目录导出)
|
|
87
|
+
export type { ParallelChartProps } from './parallel/types';
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LiquidChart 测试
|
|
3
|
+
*/
|
|
4
|
+
import React from 'react';
|
|
5
|
+
import { render, screen } from '@testing-library/react';
|
|
6
|
+
import LiquidChart from '../index';
|
|
7
|
+
|
|
8
|
+
// Mock BaseChartWrapper
|
|
9
|
+
jest.mock('../../common/BaseChartWrapper');
|
|
10
|
+
|
|
11
|
+
describe('LiquidChart', () => {
|
|
12
|
+
const mockProps = {
|
|
13
|
+
width: 200,
|
|
14
|
+
height: 200,
|
|
15
|
+
waveData: [0.6],
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
it('should render without crashing', () => {
|
|
19
|
+
render(<LiquidChart {...mockProps} />);
|
|
20
|
+
expect(screen.getByTestId('base-chart-wrapper')).toBeInTheDocument();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('should render with different wave data', () => {
|
|
24
|
+
render(<LiquidChart {...mockProps} waveData={[0.3, 0.5, 0.7]} />);
|
|
25
|
+
expect(screen.getByTestId('base-chart-wrapper')).toBeInTheDocument();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('should handle shape prop', () => {
|
|
29
|
+
render(<LiquidChart {...mockProps} shape="rect" />);
|
|
30
|
+
expect(screen.getByTestId('base-chart-wrapper')).toBeInTheDocument();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('should handle amplitude prop', () => {
|
|
34
|
+
render(<LiquidChart {...mockProps} amplitude={50} />);
|
|
35
|
+
expect(screen.getByTestId('base-chart-wrapper')).toBeInTheDocument();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('should handle color prop', () => {
|
|
39
|
+
render(<LiquidChart {...mockProps} color={['#ff0000', '#00ff00']} />);
|
|
40
|
+
expect(screen.getByTestId('base-chart-wrapper')).toBeInTheDocument();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('should handle backgroundColor prop', () => {
|
|
44
|
+
render(<LiquidChart {...mockProps} backgroundColor="#f0f0f0" />);
|
|
45
|
+
expect(screen.getByTestId('base-chart-wrapper')).toBeInTheDocument();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should handle showLabel prop', () => {
|
|
49
|
+
render(<LiquidChart {...mockProps} showLabel={true} />);
|
|
50
|
+
expect(screen.getByTestId('base-chart-wrapper')).toBeInTheDocument();
|
|
51
|
+
});
|
|
52
|
+
});
|