@agions/taroviz 1.9.0 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.js +1 -1
- package/dist/esm/index.js +576 -33
- package/package.json +1 -1
- package/src/charts/boxplot/types.ts +5 -3
- package/src/charts/parallel/types.ts +6 -3
- package/src/charts/tree/types.ts +4 -4
- package/src/core/components/Annotation.tsx +12 -10
- package/src/core/components/BaseChart.tsx +3 -3
- package/src/core/components/ErrorBoundary.tsx +30 -17
- package/src/core/components/LazyChart.tsx +14 -9
- package/src/core/themes/ThemeManager.ts +33 -0
- package/src/core/utils/chartUtils.ts +8 -3
- package/src/hooks/index.ts +21 -0
- package/src/hooks/useChartHistory.ts +273 -0
- package/src/hooks/useChartSelection.ts +350 -0
package/package.json
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 箱线图类型定义
|
|
3
3
|
*/
|
|
4
|
+
import type { EChartsType, ECElementEvent } from 'echarts';
|
|
5
|
+
import type { LoadingOptions } from '../types';
|
|
4
6
|
|
|
5
7
|
export type BoxplotChartProps = {
|
|
6
8
|
option?: BoxplotOption;
|
|
@@ -8,11 +10,11 @@ export type BoxplotChartProps = {
|
|
|
8
10
|
height?: string | number;
|
|
9
11
|
className?: string;
|
|
10
12
|
style?: React.CSSProperties;
|
|
11
|
-
onEvents?: Record<string, (params:
|
|
13
|
+
onEvents?: Record<string, (params: ECElementEvent) => void>;
|
|
12
14
|
loading?: boolean;
|
|
13
|
-
loadingOption?:
|
|
15
|
+
loadingOption?: LoadingOptions;
|
|
14
16
|
theme?: string;
|
|
15
|
-
onChartReady?: (chart:
|
|
17
|
+
onChartReady?: (chart: EChartsType) => void;
|
|
16
18
|
opts?: {
|
|
17
19
|
devicePixelRatio?: number;
|
|
18
20
|
renderer?: 'canvas' | 'svg';
|
|
@@ -2,17 +2,20 @@
|
|
|
2
2
|
* 平行坐标图类型定义
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
import type { EChartsType, ECElementEvent } from 'echarts';
|
|
6
|
+
import type { LoadingOptions } from '../types';
|
|
7
|
+
|
|
5
8
|
export type ParallelChartProps = {
|
|
6
9
|
option?: ParallelOption;
|
|
7
10
|
width?: string | number;
|
|
8
11
|
height?: string | number;
|
|
9
12
|
className?: string;
|
|
10
13
|
style?: React.CSSProperties;
|
|
11
|
-
onEvents?: Record<string, (params:
|
|
14
|
+
onEvents?: Record<string, (params: ECElementEvent) => void>;
|
|
12
15
|
loading?: boolean;
|
|
13
|
-
loadingOption?:
|
|
16
|
+
loadingOption?: LoadingOptions;
|
|
14
17
|
theme?: string;
|
|
15
|
-
onChartReady?: (chart:
|
|
18
|
+
onChartReady?: (chart: EChartsType) => void;
|
|
16
19
|
opts?: {
|
|
17
20
|
devicePixelRatio?: number;
|
|
18
21
|
renderer?: 'canvas' | 'svg';
|
package/src/charts/tree/types.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* 树图类型定义
|
|
3
3
|
* ECharts 内置 tree 类型
|
|
4
4
|
*/
|
|
5
|
-
import type { EChartsOption } from 'echarts';
|
|
5
|
+
import type { EChartsOption, EChartsType, ECElementEvent } from 'echarts';
|
|
6
6
|
|
|
7
7
|
// ============================================================================
|
|
8
8
|
// 树图数据节点
|
|
@@ -166,9 +166,9 @@ export interface TreeChartProps {
|
|
|
166
166
|
/** 加载配置 */
|
|
167
167
|
loadingOption?: Record<string, unknown>;
|
|
168
168
|
/** 图表初始化回调 */
|
|
169
|
-
onChartInit?: (chart:
|
|
169
|
+
onChartInit?: (chart: EChartsType) => void;
|
|
170
170
|
/** 图表就绪回调 */
|
|
171
|
-
onChartReady?: (chart:
|
|
171
|
+
onChartReady?: (chart: EChartsType) => void;
|
|
172
172
|
/** 事件回调 */
|
|
173
|
-
onEvents?: Record<string, (params:
|
|
173
|
+
onEvents?: Record<string, (params: ECElementEvent) => void>;
|
|
174
174
|
}
|
|
@@ -32,7 +32,7 @@ export interface MarkAreaStyle {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
/**
|
|
35
|
-
* 标记线数据点
|
|
35
|
+
* 标记线数据点 — 支持常规坐标和 ECharts 统计类型
|
|
36
36
|
*/
|
|
37
37
|
export interface MarkLineDataPoint {
|
|
38
38
|
/** X轴值 */
|
|
@@ -41,6 +41,8 @@ export interface MarkLineDataPoint {
|
|
|
41
41
|
yAxis?: string | number;
|
|
42
42
|
/** 数据点名称 */
|
|
43
43
|
name?: string;
|
|
44
|
+
/** ECharts 统计/特殊类型('average' | 'max' | 'min' | 'median') */
|
|
45
|
+
type?: string;
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
/**
|
|
@@ -97,7 +99,7 @@ export interface ScatterAnnotationConfig {
|
|
|
97
99
|
data: Array<{
|
|
98
100
|
coord: [number | string, number];
|
|
99
101
|
value?: number;
|
|
100
|
-
name
|
|
102
|
+
name: string;
|
|
101
103
|
}>;
|
|
102
104
|
/** 符号类型 */
|
|
103
105
|
symbol?: string;
|
|
@@ -109,7 +111,7 @@ export interface ScatterAnnotationConfig {
|
|
|
109
111
|
label?: {
|
|
110
112
|
show?: boolean;
|
|
111
113
|
position?: string;
|
|
112
|
-
formatter?: string | ((value:
|
|
114
|
+
formatter?: string | ((value: unknown) => string);
|
|
113
115
|
color?: string;
|
|
114
116
|
};
|
|
115
117
|
}
|
|
@@ -223,14 +225,14 @@ export function convertAnnotationToScatter(
|
|
|
223
225
|
itemStyle,
|
|
224
226
|
label: {
|
|
225
227
|
show: label?.show !== false,
|
|
226
|
-
position: label?.position || 'top',
|
|
228
|
+
position: label?.position || ('top' as const),
|
|
227
229
|
formatter: label?.formatter,
|
|
228
230
|
color: label?.color || '#333',
|
|
229
231
|
},
|
|
230
232
|
data,
|
|
231
233
|
},
|
|
232
|
-
}
|
|
233
|
-
];
|
|
234
|
+
},
|
|
235
|
+
] as unknown as EChartsOption['series'];
|
|
234
236
|
}
|
|
235
237
|
|
|
236
238
|
/**
|
|
@@ -269,28 +271,28 @@ export function useAnnotation(props: AnnotationProps): EChartsOption {
|
|
|
269
271
|
export const AnnotationPresets = {
|
|
270
272
|
/** 平均线 */
|
|
271
273
|
averageLine: (color = '#1890ff'): MarkLineConfig => ({
|
|
272
|
-
data: [{ type: 'average', name: '平均值' }]
|
|
274
|
+
data: [{ type: 'average', name: '平均值' }],
|
|
273
275
|
lineStyle: { color, type: 'dashed', width: 2 },
|
|
274
276
|
label: { show: true, position: 'end', color },
|
|
275
277
|
}),
|
|
276
278
|
|
|
277
279
|
/** 最大值线 */
|
|
278
280
|
maxLine: (color = '#f5222d'): MarkLineConfig => ({
|
|
279
|
-
data: [{ type: 'max', name: '最大值' }]
|
|
281
|
+
data: [{ type: 'max', name: '最大值' }],
|
|
280
282
|
lineStyle: { color, type: 'dashed', width: 2 },
|
|
281
283
|
label: { show: true, position: 'end', color },
|
|
282
284
|
}),
|
|
283
285
|
|
|
284
286
|
/** 最小值线 */
|
|
285
287
|
minLine: (color = '#52c41a'): MarkLineConfig => ({
|
|
286
|
-
data: [{ type: 'min', name: '最小值' }]
|
|
288
|
+
data: [{ type: 'min', name: '最小值' }],
|
|
287
289
|
lineStyle: { color, type: 'dashed', width: 2 },
|
|
288
290
|
label: { show: true, position: 'end', color },
|
|
289
291
|
}),
|
|
290
292
|
|
|
291
293
|
/** 警戒线 */
|
|
292
294
|
thresholdLine: (value: number, color = '#faad14'): MarkLineConfig => ({
|
|
293
|
-
data: [{ yAxis: value, name: '警戒线' }]
|
|
295
|
+
data: [{ yAxis: value, name: '警戒线' }],
|
|
294
296
|
lineStyle: { color, type: 'solid', width: 2 },
|
|
295
297
|
label: { show: true, position: 'start', color },
|
|
296
298
|
}),
|
|
@@ -95,8 +95,8 @@ export interface ChartProps {
|
|
|
95
95
|
enableZoom?: boolean;
|
|
96
96
|
onZoom?: (data: { start: number; end: number; dataZoomIndex: number }) => void;
|
|
97
97
|
enableDataFiltering?: boolean;
|
|
98
|
-
filters?: Record<string,
|
|
99
|
-
onDataFiltered?: (filteredData:
|
|
98
|
+
filters?: Record<string, string | number | boolean | string[] | null>;
|
|
99
|
+
onDataFiltered?: (filteredData: unknown[], filters: Record<string, unknown>) => void;
|
|
100
100
|
enableLegendInteraction?: boolean;
|
|
101
101
|
legendInteractionMode?: 'single' | 'multiple' | 'all';
|
|
102
102
|
onLegendSelect?: (params: { name: string; selected: Record<string, boolean> }) => void;
|
|
@@ -485,7 +485,7 @@ const BaseChart: React.FC<ChartProps> = (props) => {
|
|
|
485
485
|
};
|
|
486
486
|
|
|
487
487
|
const wrapperProps: BaseChartProps & { chartType: string } = {
|
|
488
|
-
option: wrappedOption as
|
|
488
|
+
option: wrappedOption as unknown as Record<string, unknown>,
|
|
489
489
|
width,
|
|
490
490
|
height,
|
|
491
491
|
theme: typeof theme === 'string' ? theme : (theme as Record<string, unknown>),
|
|
@@ -65,25 +65,30 @@ export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundarySt
|
|
|
65
65
|
return fallback(error, this.handleReset);
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
//
|
|
68
|
+
// 默认错误展示(使用 CSS 变量,与 ThemeManager 对齐)
|
|
69
69
|
return (
|
|
70
70
|
<div
|
|
71
|
+
role="alert"
|
|
72
|
+
aria-live="assertive"
|
|
71
73
|
style={{
|
|
72
74
|
display: 'flex',
|
|
73
75
|
flexDirection: 'column',
|
|
74
76
|
alignItems: 'center',
|
|
75
77
|
justifyContent: 'center',
|
|
76
|
-
padding: '
|
|
77
|
-
backgroundColor: '#fff',
|
|
78
|
-
border: '1px solid #ff4d4f',
|
|
79
|
-
borderRadius: '8px',
|
|
80
|
-
color: '#333',
|
|
78
|
+
padding: 'var(--tv-border-radius, 16px)',
|
|
79
|
+
backgroundColor: 'var(--tv-bg-color, #fff)',
|
|
80
|
+
border: '1px solid var(--tv-error-color, #ff4d4f)',
|
|
81
|
+
borderRadius: 'var(--tv-border-radius, 8px)',
|
|
82
|
+
color: 'var(--tv-text-color, #333)',
|
|
81
83
|
minHeight: '200px',
|
|
84
|
+
fontFamily: 'var(--tv-font-family, sans-serif)',
|
|
82
85
|
}}
|
|
83
86
|
>
|
|
84
|
-
<div style={{ fontSize: '48px', marginBottom: '16px' }}>⚠️</div>
|
|
85
|
-
<h3 style={{ margin: '0 0 12px', color: '#ff4d4f' }}
|
|
86
|
-
|
|
87
|
+
<div style={{ fontSize: '48px', marginBottom: '16px' }} aria-hidden="true">⚠️</div>
|
|
88
|
+
<h3 style={{ margin: '0 0 12px', color: 'var(--tv-error-color, #ff4d4f)', fontWeight: 700 }}>
|
|
89
|
+
图表渲染失败
|
|
90
|
+
</h3>
|
|
91
|
+
<p style={{ margin: '0 0 16px', color: 'var(--tv-text-color-secondary, #666)', textAlign: 'center', maxWidth: '320px' }}>
|
|
87
92
|
图表在渲染过程中遇到错误,请检查数据配置是否正确
|
|
88
93
|
</p>
|
|
89
94
|
{showDetails && (
|
|
@@ -91,15 +96,15 @@ export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundarySt
|
|
|
91
96
|
style={{
|
|
92
97
|
width: '100%',
|
|
93
98
|
padding: '12px',
|
|
94
|
-
backgroundColor: '#f5f5f5',
|
|
95
|
-
borderRadius: '4px',
|
|
96
|
-
fontSize: '12px',
|
|
97
|
-
fontFamily: 'monospace',
|
|
99
|
+
backgroundColor: 'var(--tv-bg-color-secondary, #f5f5f5)',
|
|
100
|
+
borderRadius: 'var(--tv-border-radius-small, 4px)',
|
|
101
|
+
fontSize: 'var(--tv-font-size-small, 12px)',
|
|
102
|
+
fontFamily: 'var(--tv-font-family, monospace)',
|
|
98
103
|
overflow: 'auto',
|
|
99
104
|
maxHeight: '150px',
|
|
100
105
|
}}
|
|
101
106
|
>
|
|
102
|
-
<summary style={{ cursor: 'pointer', marginBottom: '8px' }}>错误详情</summary>
|
|
107
|
+
<summary style={{ cursor: 'pointer', marginBottom: '8px', fontWeight: 600 }}>错误详情</summary>
|
|
103
108
|
<pre style={{ margin: 0, whiteSpace: 'pre-wrap', wordBreak: 'break-all' }}>
|
|
104
109
|
{error.message}
|
|
105
110
|
{'\n\n'}
|
|
@@ -112,12 +117,20 @@ export class ErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundarySt
|
|
|
112
117
|
style={{
|
|
113
118
|
marginTop: '16px',
|
|
114
119
|
padding: '8px 24px',
|
|
115
|
-
backgroundColor: '#1890ff',
|
|
120
|
+
backgroundColor: 'var(--tv-primary-color, #1890ff)',
|
|
116
121
|
color: '#fff',
|
|
117
122
|
border: 'none',
|
|
118
|
-
borderRadius: '4px',
|
|
123
|
+
borderRadius: 'var(--tv-border-radius-small, 4px)',
|
|
119
124
|
cursor: 'pointer',
|
|
120
|
-
fontSize: '14px',
|
|
125
|
+
fontSize: 'var(--tv-font-size, 14px)',
|
|
126
|
+
fontWeight: 600,
|
|
127
|
+
transition: 'background-color var(--tv-transition-duration, 0.3s)',
|
|
128
|
+
}}
|
|
129
|
+
onMouseEnter={(e) => {
|
|
130
|
+
e.currentTarget.style.backgroundColor = 'var(--tv-primary-color-hover, #40a9ff)';
|
|
131
|
+
}}
|
|
132
|
+
onMouseLeave={(e) => {
|
|
133
|
+
e.currentTarget.style.backgroundColor = 'var(--tv-primary-color, #1890ff)';
|
|
121
134
|
}}
|
|
122
135
|
>
|
|
123
136
|
重试
|
|
@@ -18,7 +18,7 @@ const LazySunburstChart = lazy(() => import('../../charts/sunburst'));
|
|
|
18
18
|
const LazySankeyChart = lazy(() => import('../../charts/sankey'));
|
|
19
19
|
|
|
20
20
|
// 统一的图表类型到懒加载组件映射
|
|
21
|
-
const LAZY_CHART_MODULES: Record<string, () => Promise<{ default: ComponentType<
|
|
21
|
+
const LAZY_CHART_MODULES: Record<string, () => Promise<{ default: ComponentType<Record<string, unknown>> }>> = {
|
|
22
22
|
line: () => import('../../charts/line'),
|
|
23
23
|
bar: () => import('../../charts/bar'),
|
|
24
24
|
pie: () => import('../../charts/pie'),
|
|
@@ -35,10 +35,12 @@ const LAZY_CHART_MODULES: Record<string, () => Promise<{ default: ComponentType<
|
|
|
35
35
|
export const LAZY_CHART_TYPES = Object.keys(LAZY_CHART_MODULES);
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
|
-
*
|
|
38
|
+
* 默认加载状态组件(使用 CSS 变量,与 ThemeManager 对齐)
|
|
39
39
|
*/
|
|
40
40
|
const DefaultLoadingFallback: React.FC<{ text?: string }> = ({ text = '加载中...' }) => (
|
|
41
41
|
<div
|
|
42
|
+
role="status"
|
|
43
|
+
aria-label={text}
|
|
42
44
|
style={{
|
|
43
45
|
display: 'flex',
|
|
44
46
|
alignItems: 'center',
|
|
@@ -46,8 +48,8 @@ const DefaultLoadingFallback: React.FC<{ text?: string }> = ({ text = '加载中
|
|
|
46
48
|
width: '100%',
|
|
47
49
|
height: '100%',
|
|
48
50
|
minHeight: '200px',
|
|
49
|
-
backgroundColor: '#f5f5f5',
|
|
50
|
-
borderRadius: '8px',
|
|
51
|
+
backgroundColor: 'var(--tv-bg-color-secondary, #f5f5f5)',
|
|
52
|
+
borderRadius: 'var(--tv-border-radius, 8px)',
|
|
51
53
|
}}
|
|
52
54
|
>
|
|
53
55
|
<div style={{ textAlign: 'center' }}>
|
|
@@ -55,12 +57,13 @@ const DefaultLoadingFallback: React.FC<{ text?: string }> = ({ text = '加载中
|
|
|
55
57
|
style={{
|
|
56
58
|
width: '40px',
|
|
57
59
|
height: '40px',
|
|
58
|
-
border: '3px solid #1890ff',
|
|
60
|
+
border: '3px solid var(--tv-primary-color, #1890ff)',
|
|
59
61
|
borderTopColor: 'transparent',
|
|
60
62
|
borderRadius: '50%',
|
|
61
63
|
animation: 'taroviz-spin 1s linear infinite',
|
|
62
64
|
margin: '0 auto 12px',
|
|
63
65
|
}}
|
|
66
|
+
aria-hidden="true"
|
|
64
67
|
/>
|
|
65
68
|
<style>
|
|
66
69
|
{`
|
|
@@ -69,7 +72,9 @@ const DefaultLoadingFallback: React.FC<{ text?: string }> = ({ text = '加载中
|
|
|
69
72
|
}
|
|
70
73
|
`}
|
|
71
74
|
</style>
|
|
72
|
-
<span style={{ color: '#666', fontSize: '14px' }}>
|
|
75
|
+
<span style={{ color: 'var(--tv-text-color-secondary, #666)', fontSize: 'var(--tv-font-size, 14px)' }}>
|
|
76
|
+
{text}
|
|
77
|
+
</span>
|
|
73
78
|
</div>
|
|
74
79
|
</div>
|
|
75
80
|
);
|
|
@@ -136,8 +141,8 @@ export function preloadAllCharts(): Promise<void[]> {
|
|
|
136
141
|
* 创建懒加载图表映射
|
|
137
142
|
* 用于动态导入图表
|
|
138
143
|
*/
|
|
139
|
-
export function createLazyChart(chartType: string): ComponentType<
|
|
140
|
-
const lazyCharts: Record<string, ComponentType<
|
|
144
|
+
export function createLazyChart(chartType: string): ComponentType<Record<string, unknown>> | null {
|
|
145
|
+
const lazyCharts: Record<string, ComponentType<Record<string, unknown>>> = {
|
|
141
146
|
line: LazyLineChart,
|
|
142
147
|
bar: LazyBarChart,
|
|
143
148
|
pie: LazyPieChart,
|
|
@@ -159,7 +164,7 @@ export function createLazyChart(chartType: string): ComponentType<any> | null {
|
|
|
159
164
|
* 用于按名称动态获取懒加载图表组件
|
|
160
165
|
*/
|
|
161
166
|
export const LazyChartRegistry = {
|
|
162
|
-
get(chartType: string): ComponentType<
|
|
167
|
+
get(chartType: string): ComponentType<Record<string, unknown>> | null {
|
|
163
168
|
return createLazyChart(chartType);
|
|
164
169
|
},
|
|
165
170
|
|
|
@@ -578,6 +578,39 @@ class ThemeManager {
|
|
|
578
578
|
return this.currentTheme.isDark || this.currentTheme.type === 'dark';
|
|
579
579
|
}
|
|
580
580
|
|
|
581
|
+
/**
|
|
582
|
+
* 检测系统 prefers-color-scheme 是否为暗色
|
|
583
|
+
*/
|
|
584
|
+
public getSystemPrefersDark(): boolean {
|
|
585
|
+
if (typeof window === 'undefined') return false;
|
|
586
|
+
return window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* 订阅系统主题变化,自动切换匹配的主题
|
|
591
|
+
* @returns 取消订阅的函数
|
|
592
|
+
*/
|
|
593
|
+
public watchSystemTheme(): () => void {
|
|
594
|
+
if (typeof window === 'undefined') return () => {};
|
|
595
|
+
|
|
596
|
+
const mq = window.matchMedia('(prefers-color-scheme: dark)');
|
|
597
|
+
const handler = (e: MediaQueryListEvent) => {
|
|
598
|
+
// 当系统主题切换时,自动应用对应主题
|
|
599
|
+
this.setTheme(e.matches ? 'dark' : 'default');
|
|
600
|
+
};
|
|
601
|
+
mq.addEventListener('change', handler);
|
|
602
|
+
return () => mq.removeEventListener('change', handler);
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
/**
|
|
606
|
+
* 应用初始主题(根据系统偏好自动选择 dark/default)
|
|
607
|
+
* 必须在 DOM 加载后调用
|
|
608
|
+
*/
|
|
609
|
+
public applyInitialTheme(): void {
|
|
610
|
+
const prefersDark = this.getSystemPrefersDark();
|
|
611
|
+
this.setTheme(prefersDark ? 'dark' : 'default');
|
|
612
|
+
}
|
|
613
|
+
|
|
581
614
|
/**
|
|
582
615
|
* 注册主题变更监听器
|
|
583
616
|
*/
|
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import type { EChartsOption } from 'echarts';
|
|
5
5
|
|
|
6
|
+
interface SeriesItem {
|
|
7
|
+
data?: unknown[] | Record<string, unknown>;
|
|
8
|
+
}
|
|
9
|
+
|
|
6
10
|
/**
|
|
7
11
|
* Normalize size value to CSS string
|
|
8
12
|
*/
|
|
@@ -19,7 +23,7 @@ export function calculateDataLength(option: { series?: unknown } | undefined): n
|
|
|
19
23
|
let count = 0;
|
|
20
24
|
if (option.series) {
|
|
21
25
|
const series = Array.isArray(option.series) ? option.series : [option.series];
|
|
22
|
-
for (const seriesItem of series as
|
|
26
|
+
for (const seriesItem of series as SeriesItem[]) {
|
|
23
27
|
if (seriesItem.data) {
|
|
24
28
|
if (Array.isArray(seriesItem.data)) {
|
|
25
29
|
count += seriesItem.data.length;
|
|
@@ -35,11 +39,12 @@ export function calculateDataLength(option: { series?: unknown } | undefined): n
|
|
|
35
39
|
/**
|
|
36
40
|
* Filter data by filter conditions
|
|
37
41
|
*/
|
|
38
|
-
export function filterDataByKeys(data:
|
|
42
|
+
export function filterDataByKeys<T>(data: T[], filters: Record<string, unknown>): T[] {
|
|
39
43
|
if (!filters || Object.keys(filters).length === 0) return data;
|
|
40
44
|
return data.filter((item) => {
|
|
41
45
|
for (const [key, value] of Object.entries(filters)) {
|
|
42
|
-
|
|
46
|
+
const itemVal = (item as Record<string, unknown>)[key];
|
|
47
|
+
if (itemVal !== value && !(Array.isArray(itemVal) && itemVal.includes(value))) return false;
|
|
43
48
|
}
|
|
44
49
|
return true;
|
|
45
50
|
});
|
package/src/hooks/index.ts
CHANGED
|
@@ -9,6 +9,8 @@ import type { EChartsOption } from 'echarts';
|
|
|
9
9
|
import { useDataZoom } from './useDataZoom';
|
|
10
10
|
import { useChartConnect } from './useChartConnect';
|
|
11
11
|
import { useChartDownload } from './useChartDownload';
|
|
12
|
+
import { useChartHistory } from './useChartHistory';
|
|
13
|
+
import { useChartSelection } from './useChartSelection';
|
|
12
14
|
|
|
13
15
|
// ============================================================================
|
|
14
16
|
// 类型定义
|
|
@@ -651,6 +653,23 @@ export {
|
|
|
651
653
|
type DownloadDataOptions,
|
|
652
654
|
} from './useChartDownload';
|
|
653
655
|
|
|
656
|
+
// 图表历史记录 Hook (Undo/Redo)
|
|
657
|
+
export {
|
|
658
|
+
useChartHistory,
|
|
659
|
+
type UseChartHistoryOptions,
|
|
660
|
+
type UseChartHistoryReturn,
|
|
661
|
+
} from './useChartHistory';
|
|
662
|
+
|
|
663
|
+
// 图表选择 Hook
|
|
664
|
+
export {
|
|
665
|
+
useChartSelection,
|
|
666
|
+
type UseChartSelectionOptions,
|
|
667
|
+
type UseChartSelectionReturn,
|
|
668
|
+
type DataPointKey,
|
|
669
|
+
type SelectionMode,
|
|
670
|
+
type SelectionEvent,
|
|
671
|
+
} from './useChartSelection';
|
|
672
|
+
|
|
654
673
|
// ============================================================================
|
|
655
674
|
// 导出
|
|
656
675
|
// ============================================================================
|
|
@@ -683,4 +702,6 @@ export default {
|
|
|
683
702
|
useDataZoom,
|
|
684
703
|
useChartConnect,
|
|
685
704
|
useChartDownload,
|
|
705
|
+
useChartHistory,
|
|
706
|
+
useChartSelection,
|
|
686
707
|
};
|