@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
package/src/adapters/types.ts
CHANGED
|
@@ -20,10 +20,9 @@ export interface AdapterOptions {
|
|
|
20
20
|
width?: number | string;
|
|
21
21
|
height?: number | string;
|
|
22
22
|
theme?: string | object;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
option?: EChartsOption;
|
|
23
|
+
option?: unknown;
|
|
24
|
+
|
|
25
|
+
onInit?: (_instance: EChartsType) => void;
|
|
27
26
|
style?: CSSProperties;
|
|
28
27
|
autoResize?: boolean;
|
|
29
28
|
devicePixelRatio?: number;
|
|
@@ -50,57 +49,25 @@ export interface WeappAdapterOptions extends AdapterOptions {
|
|
|
50
49
|
component?: object;
|
|
51
50
|
}
|
|
52
51
|
|
|
53
|
-
/**
|
|
54
|
-
|
|
55
|
-
*/
|
|
56
|
-
export
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
|
|
65
|
-
*/
|
|
66
|
-
export
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
|
|
75
|
-
*/
|
|
76
|
-
export interface TTAdapterOptions extends AdapterOptions {}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* QQ小程序适配器选项
|
|
80
|
-
*/
|
|
81
|
-
export interface QQAdapterOptions extends AdapterOptions {}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* 京东小程序适配器选项
|
|
85
|
-
*/
|
|
86
|
-
export interface JDAdapterOptions extends AdapterOptions {}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* 快手小程序适配器选项
|
|
90
|
-
*/
|
|
91
|
-
export interface KwaiAdapterOptions extends AdapterOptions {}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* 企业微信小程序适配器选项
|
|
95
|
-
*/
|
|
96
|
-
export interface QywxAdapterOptions extends AdapterOptions {}
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* 飞书小程序适配器选项
|
|
100
|
-
*/
|
|
101
|
-
export interface LarkAdapterOptions extends AdapterOptions {}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* 小程序通用适配器选项
|
|
105
|
-
*/
|
|
106
|
-
export interface MiniAppAdapterOptions extends AdapterOptions {}
|
|
52
|
+
/** 支付宝小程序适配器选项 */
|
|
53
|
+
export type AlipayAdapterOptions = AdapterOptions;
|
|
54
|
+
/** 百度小程序适配器选项 */
|
|
55
|
+
export type SwanAdapterOptions = AdapterOptions;
|
|
56
|
+
/** 鸿蒙OS适配器选项 */
|
|
57
|
+
export type HarmonyAdapterOptions = AdapterOptions;
|
|
58
|
+
/** 钉钉小程序适配器选项 */
|
|
59
|
+
export type DDAdapterOptions = AdapterOptions;
|
|
60
|
+
/** 抖音小程序适配器选项 */
|
|
61
|
+
export type TTAdapterOptions = AdapterOptions;
|
|
62
|
+
/** QQ小程序适配器选项 */
|
|
63
|
+
export type QQAdapterOptions = AdapterOptions;
|
|
64
|
+
/** 京东小程序适配器选项 */
|
|
65
|
+
export type JDAdapterOptions = AdapterOptions;
|
|
66
|
+
/** 快手小程序适配器选项 */
|
|
67
|
+
export type KwaiAdapterOptions = AdapterOptions;
|
|
68
|
+
/** 企业微信小程序适配器选项 */
|
|
69
|
+
export type QywxAdapterOptions = AdapterOptions;
|
|
70
|
+
/** 飞书小程序适配器选项 */
|
|
71
|
+
export type LarkAdapterOptions = AdapterOptions;
|
|
72
|
+
/** 小程序通用适配器选项 */
|
|
73
|
+
export type MiniAppAdapterOptions = AdapterOptions;
|
|
@@ -1,77 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* TaroViz 微信小程序适配器
|
|
3
|
-
* 基于微信小程序canvas组件实现图表渲染
|
|
4
3
|
*/
|
|
4
|
+
import { MiniAppAdapter, createMiniAppAdapter } from '../MiniAppAdapter';
|
|
5
|
+
import type { WeappAdapterOptions } from '../types';
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
export class WeappAdapter extends BaseAdapter {
|
|
10
|
-
private component: unknown = null;
|
|
11
|
-
|
|
12
|
-
constructor(config: WeappAdapterOptions) {
|
|
13
|
-
super(config);
|
|
14
|
-
this.component = config.component;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
static create(options: WeappAdapterOptions): Adapter {
|
|
18
|
-
return new WeappAdapter(options) as unknown as Adapter;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
init(): unknown {
|
|
22
|
-
const config = this.config as WeappAdapterOptions & { canvasId?: string };
|
|
23
|
-
const { canvasId, width, height, theme, option } = config;
|
|
24
|
-
|
|
25
|
-
if (!this.component) {
|
|
26
|
-
console.error('[TaroViz] WeappAdapter: component is required');
|
|
27
|
-
return null;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
if (!canvasId) {
|
|
31
|
-
console.error('[TaroViz] WeappAdapter: canvasId is required');
|
|
32
|
-
return null;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const chart = (this.component as { createChart: (config: unknown) => unknown }).createChart({
|
|
36
|
-
id: canvasId,
|
|
37
|
-
width,
|
|
38
|
-
height,
|
|
39
|
-
theme,
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
if (option) {
|
|
43
|
-
(chart as { setOption: (o: unknown) => void }).setOption(option);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
this.chartInstance = chart;
|
|
47
|
-
|
|
48
|
-
const onInit = this.config['onInit'] as ((instance: unknown) => void) | undefined;
|
|
49
|
-
if (onInit) {
|
|
50
|
-
onInit(chart);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
return chart;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
getWidth(): number {
|
|
57
|
-
return this.parseSize((this.config as WeappAdapterOptions).width, 300);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
getHeight(): number {
|
|
61
|
-
return this.parseSize((this.config as WeappAdapterOptions).height, 300);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
setComponent(component: unknown): void {
|
|
65
|
-
this.component = component;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
dispatchAction(action: unknown): void {
|
|
69
|
-
(this.chartInstance as { dispatchAction?: (a: unknown) => void })?.dispatchAction?.(action);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
getDataURL(opts?: unknown): string | undefined {
|
|
73
|
-
return (this.chartInstance as { getDataURL?: (o?: unknown) => string })?.getDataURL?.(opts);
|
|
7
|
+
export class WeappAdapter extends MiniAppAdapter {
|
|
8
|
+
protected get platformName(): string {
|
|
9
|
+
return 'Weapp';
|
|
74
10
|
}
|
|
75
11
|
}
|
|
76
12
|
|
|
13
|
+
export const createWeappAdapter = createMiniAppAdapter(WeappAdapter);
|
|
77
14
|
export default WeappAdapter;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TaroViz 图表测试工具函数
|
|
3
|
+
* 消除各图表组件测试文件中的重复测试逻辑
|
|
4
|
+
*
|
|
5
|
+
* 使用方式:
|
|
6
|
+
* 1. 测试文件顶层写:jest.mock('../common/BaseChartWrapper');
|
|
7
|
+
* Jest 会自动使用 src/charts/common/__mocks__/BaseChartWrapper.tsx
|
|
8
|
+
* 2. 图表特定 mock:jest.mock('echarts/charts', () => ({ XxxChart: jest.fn() }));
|
|
9
|
+
* 3. import { runStandardChartTests } from '../../__tests__/testUtils';
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { render } from '@testing-library/react';
|
|
13
|
+
import React from 'react';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 标准图表测试用例
|
|
17
|
+
* 所有基础图表共享的测试逻辑
|
|
18
|
+
*/
|
|
19
|
+
export function runStandardChartTests(
|
|
20
|
+
ChartComponent: React.ComponentType<any>,
|
|
21
|
+
chartType: string,
|
|
22
|
+
mockOption: Record<string, unknown>
|
|
23
|
+
): void {
|
|
24
|
+
describe(`${chartType} Component`, () => {
|
|
25
|
+
it('should render correctly with default props', () => {
|
|
26
|
+
const { getByTestId } = render(
|
|
27
|
+
React.createElement(ChartComponent, { option: mockOption } as any)
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
const chartWrapper = getByTestId('base-chart-wrapper');
|
|
31
|
+
expect(chartWrapper).toBeInTheDocument();
|
|
32
|
+
expect(chartWrapper).toHaveClass(`taroviz-${chartType}`);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('should pass the correct option to BaseChartWrapper', () => {
|
|
36
|
+
const { getByTestId } = render(
|
|
37
|
+
React.createElement(ChartComponent, { option: mockOption } as any)
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
const chartOption = getByTestId('chart-option');
|
|
41
|
+
expect(JSON.parse(chartOption.textContent || '')).toEqual(mockOption);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('should render with custom width and height', () => {
|
|
45
|
+
const customWidth = '500px';
|
|
46
|
+
const customHeight = '400px';
|
|
47
|
+
|
|
48
|
+
const { getByTestId } = render(
|
|
49
|
+
React.createElement(ChartComponent, {
|
|
50
|
+
option: mockOption,
|
|
51
|
+
width: customWidth,
|
|
52
|
+
height: customHeight,
|
|
53
|
+
} as any)
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const chartWrapper = getByTestId('base-chart-wrapper');
|
|
57
|
+
expect(chartWrapper).toHaveStyle(`width: ${customWidth}`);
|
|
58
|
+
expect(chartWrapper).toHaveStyle(`height: ${customHeight}`);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('should render with custom className', () => {
|
|
62
|
+
const customClass = `custom-${chartType}`;
|
|
63
|
+
|
|
64
|
+
const { getByTestId } = render(
|
|
65
|
+
React.createElement(ChartComponent, {
|
|
66
|
+
option: mockOption,
|
|
67
|
+
className: customClass,
|
|
68
|
+
} as any)
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
const chartWrapper = getByTestId('base-chart-wrapper');
|
|
72
|
+
expect(chartWrapper).toHaveClass(customClass);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('should render with loading state', () => {
|
|
76
|
+
const { getByTestId } = render(
|
|
77
|
+
React.createElement(ChartComponent, {
|
|
78
|
+
option: mockOption,
|
|
79
|
+
loading: true,
|
|
80
|
+
} as any)
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
const chartWrapper = getByTestId('base-chart-wrapper');
|
|
84
|
+
expect(chartWrapper).toBeInTheDocument();
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
}
|
|
@@ -1,130 +1,76 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* BoxplotChart 组件测试
|
|
3
3
|
*/
|
|
4
4
|
import React from 'react';
|
|
5
5
|
import { render } from '@testing-library/react';
|
|
6
6
|
import '@testing-library/jest-dom';
|
|
7
|
-
import BoxplotChart from '../index';
|
|
8
|
-
|
|
9
|
-
// Mock ECharts and adapters
|
|
10
|
-
jest.mock('echarts/core', () => ({
|
|
11
|
-
use: jest.fn(),
|
|
12
|
-
init: jest.fn(() => ({
|
|
13
|
-
setOption: jest.fn(),
|
|
14
|
-
showLoading: jest.fn(),
|
|
15
|
-
hideLoading: jest.fn(),
|
|
16
|
-
on: jest.fn(),
|
|
17
|
-
off: jest.fn(),
|
|
18
|
-
dispose: jest.fn(),
|
|
19
|
-
resize: jest.fn(),
|
|
20
|
-
})),
|
|
21
|
-
getInstanceByDom: jest.fn(),
|
|
22
|
-
}));
|
|
23
7
|
|
|
24
|
-
|
|
25
|
-
jest.mock('echarts/components', () => ({
|
|
26
|
-
GridComponent: jest.fn(),
|
|
27
|
-
TooltipComponent: jest.fn(),
|
|
28
|
-
TitleComponent: jest.fn(),
|
|
29
|
-
LegendComponent: jest.fn(),
|
|
30
|
-
}));
|
|
8
|
+
import BoxplotChart from '../index';
|
|
31
9
|
|
|
32
|
-
//
|
|
33
|
-
jest.mock('../../common/BaseChartWrapper'
|
|
34
|
-
|
|
35
|
-
default: (props: any) => (
|
|
36
|
-
<div
|
|
37
|
-
data-testid="boxplot-chart"
|
|
38
|
-
className={`taroviz-boxplot ${props.className || ''}`}
|
|
39
|
-
style={{ width: props.width || '100%', height: props.height || 300, ...props.style }}
|
|
40
|
-
>
|
|
41
|
-
<div data-testid="chart-option">{JSON.stringify(props.option)}</div>
|
|
42
|
-
</div>
|
|
43
|
-
),
|
|
44
|
-
}));
|
|
10
|
+
// 自动使用 src/charts/common/__mocks__/BaseChartWrapper.tsx
|
|
11
|
+
jest.mock('../../common/BaseChartWrapper');
|
|
12
|
+
jest.mock('echarts/charts', () => ({ BoxplotChart: jest.fn() }));
|
|
45
13
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
14
|
+
const basicOption = {
|
|
15
|
+
title: { text: '箱线图测试' },
|
|
16
|
+
xAxis: { type: 'category' as const, data: ['A', 'B', 'C'] },
|
|
17
|
+
yAxis: { type: 'value' as const },
|
|
18
|
+
series: [
|
|
19
|
+
{
|
|
52
20
|
type: 'boxplot' as const,
|
|
53
21
|
data: [
|
|
54
22
|
[850, 940, 980, 1050, 1130],
|
|
55
23
|
[920, 1000, 1050, 1150, 1200],
|
|
56
24
|
[780, 850, 920, 1050, 1150],
|
|
57
25
|
],
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
describe('Basic Rendering', () => {
|
|
62
|
-
it('should render without crashing', () => {
|
|
63
|
-
const { getByTestId } = render(<BoxplotChart option={basicOption} />);
|
|
64
|
-
expect(getByTestId('boxplot-chart')).toBeInTheDocument();
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it('should render with custom width and height', () => {
|
|
68
|
-
const { getByTestId } = render(<BoxplotChart option={basicOption} width={600} height={500} />);
|
|
69
|
-
expect(getByTestId('boxplot-chart')).toBeInTheDocument();
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it('should have correct display name', () => {
|
|
73
|
-
expect(BoxplotChart.displayName).toBe('BoxplotChart');
|
|
74
|
-
});
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
};
|
|
75
29
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
30
|
+
describe('BoxplotChart', () => {
|
|
31
|
+
it('should render without crashing', () => {
|
|
32
|
+
const { getByTestId } = render(<BoxplotChart option={basicOption} />);
|
|
33
|
+
expect(getByTestId('base-chart-wrapper')).toBeInTheDocument();
|
|
80
34
|
});
|
|
81
35
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
expect(getByTestId('boxplot-chart')).toHaveClass('test-class');
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
it('should accept style prop', () => {
|
|
89
|
-
const { getByTestId } = render(<BoxplotChart option={basicOption} style={{ padding: '10px' }} />);
|
|
90
|
-
expect(getByTestId('boxplot-chart')).toBeInTheDocument();
|
|
91
|
-
});
|
|
36
|
+
it('should have correct display name', () => {
|
|
37
|
+
expect(BoxplotChart.displayName).toBe('BoxplotChart');
|
|
38
|
+
});
|
|
92
39
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
40
|
+
it('should accept className prop', () => {
|
|
41
|
+
const { getByTestId } = render(<BoxplotChart option={basicOption} className="test-class" />);
|
|
42
|
+
expect(getByTestId('base-chart-wrapper')).toHaveClass('test-class');
|
|
43
|
+
});
|
|
97
44
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
});
|
|
45
|
+
it('should accept loading prop', () => {
|
|
46
|
+
const { getByTestId } = render(<BoxplotChart option={basicOption} loading={true} />);
|
|
47
|
+
expect(getByTestId('base-chart-wrapper')).toBeInTheDocument();
|
|
102
48
|
});
|
|
103
49
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
});
|
|
50
|
+
it('should render with multiple data series', () => {
|
|
51
|
+
const multiOption = {
|
|
52
|
+
...basicOption,
|
|
53
|
+
series: [
|
|
54
|
+
{ type: 'boxplot' as const, name: '2024', data: [[850, 940, 980, 1050, 1130]] },
|
|
55
|
+
{ type: 'boxplot' as const, name: '2025', data: [[920, 1000, 1050, 1150, 1200]] },
|
|
56
|
+
],
|
|
57
|
+
};
|
|
58
|
+
const { getByTestId } = render(<BoxplotChart option={multiOption} />);
|
|
59
|
+
expect(getByTestId('base-chart-wrapper')).toBeInTheDocument();
|
|
60
|
+
});
|
|
116
61
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
62
|
+
it('should render with custom itemStyle', () => {
|
|
63
|
+
const optionWithStyle = {
|
|
64
|
+
...basicOption,
|
|
65
|
+
series: [
|
|
66
|
+
{
|
|
121
67
|
type: 'boxplot' as const,
|
|
122
68
|
data: [[850, 940, 980, 1050, 1130]],
|
|
123
69
|
itemStyle: { color: '#1890ff', borderColor: '#000' },
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
};
|
|
73
|
+
const { getByTestId } = render(<BoxplotChart option={optionWithStyle} />);
|
|
74
|
+
expect(getByTestId('base-chart-wrapper')).toBeInTheDocument();
|
|
129
75
|
});
|
|
130
76
|
});
|
|
@@ -3,11 +3,12 @@
|
|
|
3
3
|
* 用于展示数据的分布情况,包括最小值、Q1、中位数、Q3、最大值
|
|
4
4
|
*/
|
|
5
5
|
import React, { memo } from 'react';
|
|
6
|
+
import type { EChartsOption } from 'echarts';
|
|
6
7
|
import BaseChartWrapper from '../common/BaseChartWrapper';
|
|
7
8
|
import { BoxplotChartProps } from './types';
|
|
8
9
|
|
|
9
10
|
const BoxplotChart: React.FC<BoxplotChartProps> = memo((props) => (
|
|
10
|
-
<BaseChartWrapper {...props} chartType="boxplot" />
|
|
11
|
+
<BaseChartWrapper {...props} option={props.option as EChartsOption} chartType="boxplot" />
|
|
11
12
|
));
|
|
12
13
|
|
|
13
14
|
BoxplotChart.displayName = 'BoxplotChart';
|
|
@@ -10,11 +10,11 @@ export type BoxplotChartProps = {
|
|
|
10
10
|
height?: string | number;
|
|
11
11
|
className?: string;
|
|
12
12
|
style?: React.CSSProperties;
|
|
13
|
-
onEvents?: Record<string, (
|
|
13
|
+
onEvents?: Record<string, (_params: ECElementEvent) => void>;
|
|
14
14
|
loading?: boolean;
|
|
15
15
|
loadingOption?: LoadingOptions;
|
|
16
16
|
theme?: string;
|
|
17
|
-
onChartReady?: (
|
|
17
|
+
onChartReady?: (_chart: EChartsType) => void;
|
|
18
18
|
opts?: {
|
|
19
19
|
devicePixelRatio?: number;
|
|
20
20
|
renderer?: 'canvas' | 'svg';
|
|
@@ -23,26 +23,27 @@ export type BoxplotChartProps = {
|
|
|
23
23
|
};
|
|
24
24
|
|
|
25
25
|
export interface BoxplotOption {
|
|
26
|
-
title?:
|
|
27
|
-
legend?:
|
|
28
|
-
grid?:
|
|
29
|
-
xAxis?:
|
|
30
|
-
yAxis?:
|
|
31
|
-
tooltip?:
|
|
26
|
+
title?: unknown;
|
|
27
|
+
legend?: unknown;
|
|
28
|
+
grid?: unknown;
|
|
29
|
+
xAxis?: unknown;
|
|
30
|
+
yAxis?: unknown;
|
|
31
|
+
tooltip?: unknown;
|
|
32
32
|
series: BoxplotSeriesItem[];
|
|
33
|
-
dataset?:
|
|
33
|
+
dataset?: unknown;
|
|
34
34
|
color?: string[];
|
|
35
|
-
backgroundColor?:
|
|
36
|
-
textStyle?:
|
|
37
|
-
[key: string]:
|
|
35
|
+
backgroundColor?: unknown;
|
|
36
|
+
textStyle?: unknown;
|
|
37
|
+
[key: string]: unknown;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
export interface BoxplotSeriesItem {
|
|
41
41
|
type: 'boxplot';
|
|
42
42
|
name?: string;
|
|
43
|
-
data?:
|
|
44
|
-
itemStyle?:
|
|
45
|
-
emphasis?:
|
|
43
|
+
data?: unknown[];
|
|
44
|
+
itemStyle?: unknown;
|
|
45
|
+
emphasis?: unknown;
|
|
46
46
|
dimensions?: string[];
|
|
47
|
-
encode?:
|
|
47
|
+
encode?: Record<string, number | string>;
|
|
48
|
+
[key: string]: unknown;
|
|
48
49
|
}
|