@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/core/utils/index.ts
CHANGED
|
@@ -1,162 +1,29 @@
|
|
|
1
|
-
//
|
|
2
|
-
|
|
3
|
-
click: 'click',
|
|
4
|
-
mousemove: 'mousemove',
|
|
5
|
-
mouseup: 'mouseup',
|
|
6
|
-
mousedown: 'mousedown',
|
|
7
|
-
mouseover: 'mouseover',
|
|
8
|
-
mouseout: 'mouseout',
|
|
9
|
-
globalout: 'globalout',
|
|
10
|
-
};
|
|
1
|
+
// Re-export barrel file — all public APIs preserved
|
|
2
|
+
// External import paths remain unchanged
|
|
11
3
|
|
|
12
|
-
//
|
|
13
|
-
|
|
14
|
-
import { uuid, shortId, prefixedId } from './uuid';
|
|
15
|
-
|
|
16
|
-
// 导入国际化工具
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* 深度合并对象
|
|
20
|
-
* @param target 目标对象
|
|
21
|
-
* @param source 源对象
|
|
22
|
-
* @returns 合并后的对象
|
|
23
|
-
*/
|
|
24
|
-
export function deepMerge<T extends Record<string, any>>(
|
|
25
|
-
target: T,
|
|
26
|
-
source: Record<string, any>
|
|
27
|
-
): T {
|
|
28
|
-
const result: any = { ...target };
|
|
29
|
-
|
|
30
|
-
Object.keys(source).forEach((key) => {
|
|
31
|
-
if (source[key] instanceof Object && key in target && target[key] instanceof Object) {
|
|
32
|
-
result[key] = deepMerge(target[key], source[key]);
|
|
33
|
-
} else {
|
|
34
|
-
result[key] = source[key];
|
|
35
|
-
}
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
return result;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* 防抖函数
|
|
43
|
-
* @param fn 需要防抖的函数
|
|
44
|
-
* @param delay 延迟时间(毫秒)
|
|
45
|
-
* @returns 防抖后的函数
|
|
46
|
-
*/
|
|
47
|
-
export function debounce<T extends (...args: any[]) => any>(
|
|
48
|
-
fn: T,
|
|
49
|
-
delay: number
|
|
50
|
-
): (...args: Parameters<T>) => void {
|
|
51
|
-
let timer: ReturnType<typeof setTimeout> | null = null;
|
|
52
|
-
|
|
53
|
-
return function (this: any, ...args: Parameters<T>): void {
|
|
54
|
-
if (timer) {
|
|
55
|
-
clearTimeout(timer);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
timer = setTimeout(() => {
|
|
59
|
-
fn.apply(this, args);
|
|
60
|
-
timer = null;
|
|
61
|
-
}, delay);
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* 节流函数
|
|
67
|
-
* @param fn 需要节流的函数
|
|
68
|
-
* @param interval 间隔时间(毫秒)
|
|
69
|
-
* @returns 节流后的函数
|
|
70
|
-
*/
|
|
71
|
-
export function throttle<T extends (...args: any[]) => any>(
|
|
72
|
-
fn: T,
|
|
73
|
-
interval: number
|
|
74
|
-
): (...args: Parameters<T>) => void {
|
|
75
|
-
let lastTime = 0;
|
|
4
|
+
// 事件常量
|
|
5
|
+
export { events } from './events';
|
|
76
6
|
|
|
77
|
-
|
|
78
|
-
|
|
7
|
+
// 对象合并
|
|
8
|
+
export { deepMerge } from './merge';
|
|
79
9
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
lastTime = now;
|
|
83
|
-
}
|
|
84
|
-
};
|
|
85
|
-
}
|
|
10
|
+
// 格式化与颜色工具
|
|
11
|
+
export { formatNumber, getContrastColor } from './format';
|
|
86
12
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
* @returns 环境信息
|
|
90
|
-
*/
|
|
91
|
-
export function getEnvironment() {
|
|
92
|
-
const isServer = typeof window === 'undefined';
|
|
93
|
-
const isClient = !isServer;
|
|
13
|
+
// 检测当前环境(简易版,向后兼容)
|
|
14
|
+
export { getEnvironment } from './runtime';
|
|
94
15
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
typeof (window as any)['wx'].getSystemInfoSync === 'function';
|
|
99
|
-
const isAlipay =
|
|
100
|
-
typeof (window as any)['my'] !== 'undefined' &&
|
|
101
|
-
typeof (window as any)['my'].getSystemInfoSync === 'function';
|
|
102
|
-
const isWeb = isClient && !isWeapp && !isAlipay;
|
|
16
|
+
// 统一运行时检测
|
|
17
|
+
export { detectRuntime, resetRuntimeCache } from './runtime';
|
|
18
|
+
export type { RuntimeInfo, MiniAppType } from './runtime';
|
|
103
19
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
isClient,
|
|
107
|
-
isWeapp,
|
|
108
|
-
isAlipay,
|
|
109
|
-
isWeb,
|
|
110
|
-
};
|
|
111
|
-
}
|
|
20
|
+
// UUID工具函数
|
|
21
|
+
export { uuid, shortId, prefixedId } from './uuid';
|
|
112
22
|
|
|
113
|
-
|
|
114
|
-
*
|
|
115
|
-
* @param value 要格式化的数值
|
|
116
|
-
* @param digits 小数位数
|
|
117
|
-
* @param options 配置选项
|
|
118
|
-
* @returns 格式化后的字符串
|
|
119
|
-
*/
|
|
120
|
-
export function formatNumber(
|
|
121
|
-
value: number,
|
|
122
|
-
digits: number = 2,
|
|
123
|
-
options: {
|
|
124
|
-
useGrouping?: boolean;
|
|
125
|
-
locale?: string;
|
|
126
|
-
} = {}
|
|
127
|
-
): string {
|
|
128
|
-
const { useGrouping = true, locale = 'zh-CN' } = options;
|
|
129
|
-
|
|
130
|
-
return new Intl.NumberFormat(locale, {
|
|
131
|
-
minimumFractionDigits: digits,
|
|
132
|
-
maximumFractionDigits: digits,
|
|
133
|
-
useGrouping,
|
|
134
|
-
}).format(value);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* 获取颜色的对比色
|
|
139
|
-
* @param color 十六进制颜色值
|
|
140
|
-
* @returns 对比色
|
|
141
|
-
*/
|
|
142
|
-
export function getContrastColor(color: string): string {
|
|
143
|
-
// 移除#前缀
|
|
144
|
-
const hex = color.replace('#', '');
|
|
145
|
-
|
|
146
|
-
// 转换为RGB
|
|
147
|
-
const r = parseInt(hex.substring(0, 2), 16);
|
|
148
|
-
const g = parseInt(hex.substring(2, 4), 16);
|
|
149
|
-
const b = parseInt(hex.substring(4, 6), 16);
|
|
150
|
-
|
|
151
|
-
// 计算亮度
|
|
152
|
-
const brightness = (r * 299 + g * 587 + b * 114) / 1000;
|
|
153
|
-
|
|
154
|
-
// 根据亮度返回黑色或白色
|
|
155
|
-
return brightness > 128 ? '#000000' : '#FFFFFF';
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// 导出UUID工具函数
|
|
159
|
-
export { uuid, shortId, prefixedId };
|
|
160
|
-
|
|
161
|
-
// 导出国际化工具
|
|
23
|
+
// 国际化工具
|
|
24
|
+
import * as i18n from './i18n';
|
|
162
25
|
export { i18n };
|
|
26
|
+
|
|
27
|
+
// 性能优化工具(含 debounce, throttle, DebounceManager 等)
|
|
28
|
+
export * from './performanceUtils';
|
|
29
|
+
export { DebounceManager } from './performanceUtils';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 深度合并对象
|
|
3
|
+
* @param target 目标对象
|
|
4
|
+
* @param source 源对象
|
|
5
|
+
* @returns 合并后的对象
|
|
6
|
+
*/
|
|
7
|
+
export function deepMerge<T extends Record<string, unknown>>(
|
|
8
|
+
target: T,
|
|
9
|
+
source: Partial<Record<string, unknown>>
|
|
10
|
+
): T {
|
|
11
|
+
const result: Record<string, unknown> = { ...target };
|
|
12
|
+
|
|
13
|
+
Object.keys(source).forEach((key) => {
|
|
14
|
+
if (source[key] instanceof Object && key in target && target[key] instanceof Object) {
|
|
15
|
+
result[key] = deepMerge(
|
|
16
|
+
target[key] as Record<string, unknown>,
|
|
17
|
+
source[key] as Record<string, unknown>
|
|
18
|
+
);
|
|
19
|
+
} else {
|
|
20
|
+
result[key] = source[key];
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
return result as T;
|
|
25
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
1
2
|
/**
|
|
2
3
|
* TaroViz 性能分析工具核心实现
|
|
3
4
|
*/
|
|
@@ -12,6 +13,15 @@ import {
|
|
|
12
13
|
PerformanceEventData,
|
|
13
14
|
PerformanceReportConfig,
|
|
14
15
|
} from './types';
|
|
16
|
+
const DEFAULT_10 = 10;
|
|
17
|
+
const DEFAULT_15 = 15;
|
|
18
|
+
const DEFAULT_20 = 20;
|
|
19
|
+
const DEFAULT_25 = 25;
|
|
20
|
+
const DEFAULT_30 = 30;
|
|
21
|
+
const DEFAULT_50 = 50;
|
|
22
|
+
const DEFAULT_100 = 100;
|
|
23
|
+
const DEFAULT_1000 = 1000;
|
|
24
|
+
const DEFAULT_1024 = 1024;
|
|
15
25
|
|
|
16
26
|
/**
|
|
17
27
|
* 性能分析器类
|
|
@@ -122,14 +132,25 @@ export class PerformanceAnalyzer {
|
|
|
122
132
|
private emit(eventType: PerformanceEventType.MONITORING_START): void;
|
|
123
133
|
private emit(eventType: PerformanceEventType.MONITORING_END): void;
|
|
124
134
|
private emit(eventType: PerformanceEventType.METRIC_UPDATE, data: PerformanceMetric): void;
|
|
125
|
-
private emit(
|
|
126
|
-
|
|
135
|
+
private emit(
|
|
136
|
+
eventType: PerformanceEventType.ANALYSIS_COMPLETE,
|
|
137
|
+
data: PerformanceAnalysisResult
|
|
138
|
+
): void;
|
|
139
|
+
private emit(
|
|
140
|
+
eventType: PerformanceEventType,
|
|
141
|
+
data?: PerformanceMetric | PerformanceAnalysisResult
|
|
142
|
+
): void {
|
|
127
143
|
const handlers = this.eventHandlers.get(eventType);
|
|
128
|
-
const eventData: PerformanceEventData =
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
144
|
+
const eventData: PerformanceEventData =
|
|
145
|
+
data === undefined
|
|
146
|
+
? {
|
|
147
|
+
type: eventType as
|
|
148
|
+
| PerformanceEventType.MONITORING_START
|
|
149
|
+
| PerformanceEventType.MONITORING_END,
|
|
150
|
+
}
|
|
151
|
+
: eventType === PerformanceEventType.METRIC_UPDATE
|
|
152
|
+
? { type: eventType, data: data as PerformanceMetric }
|
|
153
|
+
: { type: eventType, data: data as PerformanceAnalysisResult };
|
|
133
154
|
handlers?.forEach((handler) => {
|
|
134
155
|
try {
|
|
135
156
|
handler(eventData);
|
|
@@ -149,7 +170,7 @@ export class PerformanceAnalyzer {
|
|
|
149
170
|
|
|
150
171
|
this.isMonitoring = true;
|
|
151
172
|
this.startTime = Date.now();
|
|
152
|
-
this.lastFrameTime = performance.now();
|
|
173
|
+
this.lastFrameTime = typeof performance !== 'undefined' ? performance.now() : Date.now();
|
|
153
174
|
|
|
154
175
|
// 启动采样定时器
|
|
155
176
|
if (this.config.sampleInterval && this.config.realTime) {
|
|
@@ -211,6 +232,7 @@ export class PerformanceAnalyzer {
|
|
|
211
232
|
* 开始帧率监控
|
|
212
233
|
*/
|
|
213
234
|
private startFrameRateMonitoring(): void {
|
|
235
|
+
if (typeof requestAnimationFrame === 'undefined' || typeof performance === 'undefined') return;
|
|
214
236
|
const updateFrameRate = () => {
|
|
215
237
|
if (!this.isMonitoring) {
|
|
216
238
|
return;
|
|
@@ -264,9 +286,11 @@ export class PerformanceAnalyzer {
|
|
|
264
286
|
// 采样内存使用(如果支持)
|
|
265
287
|
if (
|
|
266
288
|
this.config.metrics?.includes('memoryUsage') &&
|
|
267
|
-
typeof (performance as
|
|
289
|
+
typeof (performance as Performance & { memory?: { usedJSHeapSize: number } }).memory !==
|
|
290
|
+
'undefined'
|
|
268
291
|
) {
|
|
269
|
-
const
|
|
292
|
+
const memory = (performance as Performance & { memory?: { usedJSHeapSize: number } }).memory;
|
|
293
|
+
const memoryUsage = ((memory?.usedJSHeapSize ?? 0) / (1024 * 1024)).toFixed(2);
|
|
270
294
|
this.recordMetric('memoryUsage', parseFloat(memoryUsage), 'MB');
|
|
271
295
|
}
|
|
272
296
|
}
|
|
@@ -389,22 +413,22 @@ export class PerformanceAnalyzer {
|
|
|
389
413
|
});
|
|
390
414
|
|
|
391
415
|
// 计算性能评分和建议
|
|
392
|
-
if (averages.renderTime > 100) {
|
|
416
|
+
if (averages.renderTime !== undefined && averages.renderTime > 100) {
|
|
393
417
|
score -= 20;
|
|
394
418
|
suggestions.push('渲染时间过长,建议优化数据处理或减少图表复杂度');
|
|
395
419
|
}
|
|
396
420
|
|
|
397
|
-
if (averages.updateTime > 50) {
|
|
421
|
+
if (averages.updateTime !== undefined && averages.updateTime > 50) {
|
|
398
422
|
score -= 15;
|
|
399
423
|
suggestions.push('更新时间过长,建议优化数据更新逻辑');
|
|
400
424
|
}
|
|
401
425
|
|
|
402
|
-
if (averages.frameRate < 30) {
|
|
426
|
+
if (averages.frameRate !== undefined && averages.frameRate < 30) {
|
|
403
427
|
score -= 25;
|
|
404
428
|
suggestions.push('帧率过低,建议减少动画效果或优化渲染逻辑');
|
|
405
429
|
}
|
|
406
430
|
|
|
407
|
-
if (averages.dataSize > 100) {
|
|
431
|
+
if (averages.dataSize !== undefined && averages.dataSize > 100) {
|
|
408
432
|
score -= 10;
|
|
409
433
|
suggestions.push('数据量过大,建议进行数据压缩或分页处理');
|
|
410
434
|
}
|
|
@@ -611,13 +635,6 @@ export class PerformanceAnalyzer {
|
|
|
611
635
|
this.config = { ...this.config, ...config };
|
|
612
636
|
}
|
|
613
637
|
|
|
614
|
-
/**
|
|
615
|
-
* 获取所有指标数据
|
|
616
|
-
*/
|
|
617
|
-
public getAllMetrics(): Map<PerformanceMetricType, PerformanceMetric[]> {
|
|
618
|
-
return new Map(this.metrics);
|
|
619
|
-
}
|
|
620
|
-
|
|
621
638
|
/**
|
|
622
639
|
* 获取特定类型的指标数据
|
|
623
640
|
*/
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
1
2
|
/**
|
|
2
3
|
* useAnimation - 图表动画控制 Hook
|
|
3
4
|
* 提供图表动画的播放、暂停、控制等功能
|
|
4
5
|
*/
|
|
5
|
-
import { useState, useCallback, useRef, useEffect } from 'react';
|
|
6
|
-
import type { ChartInstance } from '
|
|
6
|
+
import { useState, useCallback, useRef, useEffect, useMemo } from 'react';
|
|
7
|
+
import type { ChartInstance } from '../../../hooks/types';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* 动画状态
|
|
@@ -47,11 +48,11 @@ export interface UseAnimationReturn {
|
|
|
47
48
|
/** 停止动画并重置 */
|
|
48
49
|
stop: () => void;
|
|
49
50
|
/** 跳转到指定帧 */
|
|
50
|
-
seekTo: (
|
|
51
|
+
seekTo: (_frame: number) => void;
|
|
51
52
|
/** 跳转到指定进度 */
|
|
52
|
-
seekToProgress: (
|
|
53
|
+
seekToProgress: (_progress: number) => void;
|
|
53
54
|
/** 设置播放速度 */
|
|
54
|
-
setPlaybackSpeed: (
|
|
55
|
+
setPlaybackSpeed: (_speed: number) => void;
|
|
55
56
|
/** 播放速度 */
|
|
56
57
|
playbackSpeed: number;
|
|
57
58
|
}
|
|
@@ -81,35 +82,45 @@ export function useAnimation(
|
|
|
81
82
|
const [playbackSpeed, setPlaybackSpeedState] = useState(1);
|
|
82
83
|
|
|
83
84
|
// Refs
|
|
85
|
+
const chartRef = useRef<ChartInstance | null>(null);
|
|
86
|
+
chartRef.current = chartInstance;
|
|
87
|
+
|
|
88
|
+
// Animation state ref — tracks RAF id, start time, current frame, loop count, paused flag
|
|
84
89
|
const animationRef = useRef<{
|
|
90
|
+
animationId: number | null;
|
|
85
91
|
startTime: number;
|
|
86
92
|
currentFrame: number;
|
|
87
93
|
loopCounter: number;
|
|
88
|
-
animationId: number | null;
|
|
89
94
|
isPaused: boolean;
|
|
90
95
|
}>({
|
|
96
|
+
animationId: null,
|
|
91
97
|
startTime: 0,
|
|
92
98
|
currentFrame: 0,
|
|
93
99
|
loopCounter: 0,
|
|
94
|
-
animationId: null,
|
|
95
100
|
isPaused: false,
|
|
96
101
|
});
|
|
97
102
|
|
|
98
|
-
|
|
99
|
-
|
|
103
|
+
// 缓动函数 - 使用 useMemo 缓存,避免每次重新创建
|
|
104
|
+
const easingFunctions = useMemo<Record<string, (t: number) => number>>(
|
|
105
|
+
() => ({
|
|
106
|
+
cubicOut: (t) => 1 - Math.pow(1 - t, 3),
|
|
107
|
+
cubicIn: (t) => t * t * t,
|
|
108
|
+
cubicInOut: (t) => (t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2),
|
|
109
|
+
linear: (t) => t,
|
|
110
|
+
sinusoidalIn: (t) => 1 - Math.cos((t * Math.PI) / 2),
|
|
111
|
+
sinusoidalOut: (t) => Math.sin((t * Math.PI) / 2),
|
|
112
|
+
}),
|
|
113
|
+
[]
|
|
114
|
+
);
|
|
100
115
|
|
|
101
116
|
// 计算总帧数(假设 60fps)
|
|
102
|
-
const totalFrames = Math.ceil((duration / 1000) * 60);
|
|
103
|
-
|
|
104
|
-
//
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
linear: (t) => t,
|
|
110
|
-
sinusoidalIn: (t) => 1 - Math.cos((t * Math.PI) / 2),
|
|
111
|
-
sinusoidalOut: (t) => Math.sin((t * Math.PI) / 2),
|
|
112
|
-
};
|
|
117
|
+
const totalFrames = useMemo(() => Math.ceil((duration / 1000) * 60), [duration]);
|
|
118
|
+
|
|
119
|
+
// 获取当前缓动函数
|
|
120
|
+
const getEasing = useCallback(
|
|
121
|
+
(easingName: string) => easingFunctions[easingName] ?? easingFunctions.linear,
|
|
122
|
+
[easingFunctions]
|
|
123
|
+
);
|
|
113
124
|
|
|
114
125
|
// 计算当前进度对应的帧
|
|
115
126
|
const calculateFrame = useCallback(
|
|
@@ -128,10 +139,7 @@ export function useAnimation(
|
|
|
128
139
|
const animate = useCallback(() => {
|
|
129
140
|
const anim = animationRef.current;
|
|
130
141
|
const chart = chartRef.current;
|
|
131
|
-
|
|
132
|
-
if (!chart || anim.isPaused || disabled) {
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
142
|
+
if (!chart || anim.isPaused || disabled) return;
|
|
135
143
|
|
|
136
144
|
const elapsed = performance.now() - anim.startTime;
|
|
137
145
|
const adjustedDuration = duration / playbackSpeed;
|
|
@@ -154,9 +162,7 @@ export function useAnimation(
|
|
|
154
162
|
|
|
155
163
|
// 更新图表配置以反映动画进度
|
|
156
164
|
try {
|
|
157
|
-
// ECharts 通过 setOption 配合 notMerge: false 更新动画
|
|
158
165
|
if (chart.setOption && !anim.isPaused) {
|
|
159
|
-
// 触发图表重新渲染
|
|
160
166
|
chart.setOption({}, false, true);
|
|
161
167
|
}
|
|
162
168
|
} catch (e) {
|
|
@@ -166,13 +172,11 @@ export function useAnimation(
|
|
|
166
172
|
// 检查是否完成
|
|
167
173
|
if (effectiveElapsed >= adjustedDuration) {
|
|
168
174
|
if (loop && (loopCount === -1 || anim.loopCounter < loopCount)) {
|
|
169
|
-
// 继续循环
|
|
170
175
|
anim.loopCounter++;
|
|
171
176
|
anim.startTime = performance.now();
|
|
172
177
|
anim.isPaused = false;
|
|
173
178
|
setStatus('playing');
|
|
174
179
|
} else {
|
|
175
|
-
// 动画结束
|
|
176
180
|
setStatus('stopped');
|
|
177
181
|
anim.animationId = null;
|
|
178
182
|
return;
|
|
@@ -180,22 +184,20 @@ export function useAnimation(
|
|
|
180
184
|
}
|
|
181
185
|
|
|
182
186
|
anim.animationId = requestAnimationFrame(animate);
|
|
183
|
-
}, [duration,
|
|
187
|
+
}, [duration, delay, loop, loopCount, playbackSpeed, disabled, easing, calculateFrame]);
|
|
184
188
|
|
|
185
189
|
// 播放动画
|
|
186
|
-
const
|
|
190
|
+
const playRef = useRef<() => void>(() => {});
|
|
191
|
+
playRef.current = () => {
|
|
187
192
|
const chart = chartRef.current;
|
|
188
193
|
if (!chart || disabled) return;
|
|
189
194
|
|
|
190
195
|
const anim = animationRef.current;
|
|
191
|
-
|
|
192
196
|
if (status === 'paused') {
|
|
193
|
-
// 从暂停恢复
|
|
194
197
|
anim.isPaused = false;
|
|
195
198
|
anim.startTime = performance.now() - (anim.currentFrame / totalFrames) * duration;
|
|
196
199
|
setStatus('playing');
|
|
197
200
|
} else {
|
|
198
|
-
// 开始新动画
|
|
199
201
|
anim.startTime = performance.now();
|
|
200
202
|
anim.currentFrame = 0;
|
|
201
203
|
anim.loopCounter = 0;
|
|
@@ -206,7 +208,11 @@ export function useAnimation(
|
|
|
206
208
|
if (anim.animationId === null) {
|
|
207
209
|
anim.animationId = requestAnimationFrame(animate);
|
|
208
210
|
}
|
|
209
|
-
}
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
const play = useCallback(() => {
|
|
214
|
+
playRef.current();
|
|
215
|
+
}, []);
|
|
210
216
|
|
|
211
217
|
// 暂停动画
|
|
212
218
|
const pause = useCallback(() => {
|
|
@@ -238,12 +244,12 @@ export function useAnimation(
|
|
|
238
244
|
const chart = chartRef.current;
|
|
239
245
|
if (!chart) return;
|
|
240
246
|
|
|
241
|
-
const
|
|
247
|
+
const currentTotalFrames = Math.ceil((duration / 1000) * 60);
|
|
248
|
+
const clampedFrame = Math.max(0, Math.min(currentTotalFrames, targetFrame));
|
|
242
249
|
anim.currentFrame = clampedFrame;
|
|
243
250
|
setFrame(clampedFrame);
|
|
244
251
|
|
|
245
|
-
|
|
246
|
-
const progress = clampedFrame / totalFrames;
|
|
252
|
+
const _progress = clampedFrame / currentTotalFrames;
|
|
247
253
|
try {
|
|
248
254
|
if (chart.setOption) {
|
|
249
255
|
chart.setOption({}, false, true);
|
|
@@ -252,7 +258,7 @@ export function useAnimation(
|
|
|
252
258
|
console.warn('[useAnimation] Failed to seek:', e);
|
|
253
259
|
}
|
|
254
260
|
},
|
|
255
|
-
[
|
|
261
|
+
[duration]
|
|
256
262
|
);
|
|
257
263
|
|
|
258
264
|
// 跳转到指定进度
|
|
@@ -362,7 +368,7 @@ export function useProgressiveLoading(
|
|
|
362
368
|
setCurrentBatch(0);
|
|
363
369
|
|
|
364
370
|
intervalRef.current = window.setInterval(() => {
|
|
365
|
-
setCurrentBatch(prev => {
|
|
371
|
+
setCurrentBatch((prev) => {
|
|
366
372
|
const next = prev + 1;
|
|
367
373
|
onBatchLoaded?.(next, totalBatches);
|
|
368
374
|
|
|
@@ -423,5 +429,3 @@ export function useProgressiveLoading(
|
|
|
423
429
|
reset,
|
|
424
430
|
};
|
|
425
431
|
}
|
|
426
|
-
|
|
427
|
-
export default useAnimation;
|