@agions/taroviz 1.1.1 → 1.2.1
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/README.md +324 -53
- package/dist/cjs/index.js +1 -0
- package/dist/esm/index.js +82979 -0
- package/package.json +160 -30
- package/src/__tests__/integration.test.tsx +168 -0
- package/src/adapters/__tests__/index.test.ts +91 -0
- package/src/adapters/h5/__tests__/index.test.ts +156 -0
- package/src/adapters/h5/index.ts +301 -0
- package/src/adapters/harmony/index.ts +274 -0
- package/src/adapters/index.ts +166 -0
- package/src/adapters/swan/index.ts +274 -0
- package/src/adapters/tt/index.ts +274 -0
- package/src/adapters/types.ts +162 -0
- package/src/adapters/weapp/index.ts +237 -0
- package/src/charts/bar/__tests__/index.test.tsx +113 -0
- package/src/charts/bar/index.tsx +18 -0
- package/src/charts/common/BaseChartWrapper.tsx +136 -0
- package/src/charts/funnel/index.tsx +18 -0
- package/src/charts/gauge/index.tsx +18 -0
- package/src/charts/heatmap/index.tsx +18 -0
- package/src/charts/index.ts +21 -0
- package/src/charts/line/__tests__/index.test.tsx +107 -0
- package/src/charts/line/index.tsx +18 -0
- package/src/charts/pie/__tests__/index.test.tsx +112 -0
- package/src/charts/pie/index.tsx +19 -0
- package/src/charts/radar/index.tsx +18 -0
- package/src/charts/scatter/index.tsx +18 -0
- package/src/charts/types.ts +619 -0
- package/src/charts/utils.ts +56 -0
- package/src/core/__tests__/platform.test.ts +48 -0
- package/src/core/animation/AnimationManager.ts +391 -0
- package/src/core/animation/index.ts +20 -0
- package/src/core/animation/types.ts +248 -0
- package/src/core/components/BaseChart.tsx +1313 -0
- package/src/core/components/ErrorBoundary.tsx +458 -0
- package/src/core/echarts.ts +58 -0
- package/src/core/index.ts +22 -0
- package/src/core/types/chart.ts +66 -0
- package/src/core/types/common.ts +224 -0
- package/src/core/types/index.ts +281 -0
- package/src/core/types/platform.ts +325 -0
- package/src/core/utils/__tests__/common.test.ts +52 -0
- package/src/core/utils/__tests__/environment.test.ts +94 -0
- package/src/core/utils/__tests__/i18n.test.ts +247 -0
- package/src/core/utils/__tests__/index.test.ts +219 -0
- package/src/core/utils/__tests__/uuid.test.ts +78 -0
- package/src/core/utils/chartInstances.ts +69 -0
- package/src/core/utils/codeGenerator/CodeGenerator.ts +655 -0
- package/src/core/utils/codeGenerator/index.ts +13 -0
- package/src/core/utils/codeGenerator/types.ts +198 -0
- package/src/core/utils/common.ts +58 -0
- package/src/core/utils/configGenerator/ConfigGenerator.ts +583 -0
- package/src/core/utils/configGenerator/index.ts +13 -0
- package/src/core/utils/configGenerator/types.ts +445 -0
- package/src/core/utils/debug/DebugPanel.tsx +637 -0
- package/src/core/utils/debug/debugger.ts +322 -0
- package/src/core/utils/debug/index.ts +21 -0
- package/src/core/utils/debug/types.ts +142 -0
- package/src/core/utils/i18n.ts +452 -0
- package/src/core/utils/index.ts +162 -0
- package/src/core/utils/performance/PerformanceAnalyzer.ts +586 -0
- package/src/core/utils/performance/index.ts +13 -0
- package/src/core/utils/performance/types.ts +180 -0
- package/src/core/utils/uuid.ts +30 -0
- package/src/editor/ThemeEditor.tsx +449 -0
- package/src/editor/index.ts +10 -0
- package/src/hooks/__tests__/index.test.tsx +333 -0
- package/src/hooks/index.ts +594 -0
- package/src/index.ts +75 -0
- package/src/main.tsx +247 -0
- package/src/react-dom.d.ts +7 -0
- package/src/themes/__tests__/index.test.ts +91 -0
- package/src/themes/index.ts +860 -0
- package/dist/389.index.esm.js +0 -1
- package/dist/389.index.js +0 -1
- package/dist/633.index.esm.js +0 -1
- package/dist/633.index.js +0 -1
- package/dist/967.index.esm.js +0 -1
- package/dist/967.index.js +0 -1
- package/dist/index.esm.js +0 -1
- package/dist/index.js +0 -1
|
@@ -0,0 +1,586 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TaroViz 性能分析工具核心实现
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
PerformanceMetricType,
|
|
7
|
+
PerformanceMetric,
|
|
8
|
+
PerformanceAnalysisConfig,
|
|
9
|
+
PerformanceAnalysisResult,
|
|
10
|
+
PerformanceEventType,
|
|
11
|
+
PerformanceEventHandler,
|
|
12
|
+
PerformanceReportConfig,
|
|
13
|
+
} from './types';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 性能分析器类
|
|
17
|
+
* 负责监控、采集和分析图表性能数据
|
|
18
|
+
*/
|
|
19
|
+
export class PerformanceAnalyzer {
|
|
20
|
+
private static instance: PerformanceAnalyzer | null = null;
|
|
21
|
+
private config: PerformanceAnalysisConfig;
|
|
22
|
+
private metrics: Map<PerformanceMetricType, PerformanceMetric[]> = new Map();
|
|
23
|
+
private eventHandlers: Map<PerformanceEventType, PerformanceEventHandler[]> = new Map();
|
|
24
|
+
private isMonitoring: boolean = false;
|
|
25
|
+
private startTime: number = 0;
|
|
26
|
+
private sampleIntervalId: NodeJS.Timeout | null = null;
|
|
27
|
+
private frameRateHistory: number[] = [];
|
|
28
|
+
private lastFrameTime: number = 0;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* 私有构造函数,使用单例模式
|
|
32
|
+
*/
|
|
33
|
+
private constructor(config: PerformanceAnalysisConfig = {}) {
|
|
34
|
+
this.config = {
|
|
35
|
+
enabled: true,
|
|
36
|
+
metrics: ['initTime', 'renderTime', 'updateTime', 'dataSize', 'frameRate'],
|
|
37
|
+
sampleInterval: 1000,
|
|
38
|
+
maxSamples: 100,
|
|
39
|
+
realTime: true,
|
|
40
|
+
autoStart: false,
|
|
41
|
+
...config,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// 初始化指标存储
|
|
45
|
+
this.config.metrics?.forEach((metricType) => {
|
|
46
|
+
this.metrics.set(metricType, []);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// 自动开始监控
|
|
50
|
+
if (this.config.autoStart) {
|
|
51
|
+
this.start();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* 获取单例实例
|
|
57
|
+
*/
|
|
58
|
+
public static getInstance(config?: PerformanceAnalysisConfig): PerformanceAnalyzer {
|
|
59
|
+
if (!PerformanceAnalyzer.instance) {
|
|
60
|
+
PerformanceAnalyzer.instance = new PerformanceAnalyzer(config);
|
|
61
|
+
}
|
|
62
|
+
return PerformanceAnalyzer.instance;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* 重置单例实例
|
|
67
|
+
*/
|
|
68
|
+
public static resetInstance(): void {
|
|
69
|
+
if (PerformanceAnalyzer.instance) {
|
|
70
|
+
PerformanceAnalyzer.instance.stop();
|
|
71
|
+
PerformanceAnalyzer.instance = null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* 注册事件处理器
|
|
77
|
+
*/
|
|
78
|
+
public on(eventType: PerformanceEventType, handler: PerformanceEventHandler): void {
|
|
79
|
+
if (!this.eventHandlers.has(eventType)) {
|
|
80
|
+
this.eventHandlers.set(eventType, []);
|
|
81
|
+
}
|
|
82
|
+
this.eventHandlers.get(eventType)?.push(handler);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* 移除事件处理器
|
|
87
|
+
*/
|
|
88
|
+
public off(eventType: PerformanceEventType, handler: PerformanceEventHandler): void {
|
|
89
|
+
const handlers = this.eventHandlers.get(eventType);
|
|
90
|
+
if (handlers) {
|
|
91
|
+
const index = handlers.indexOf(handler);
|
|
92
|
+
if (index > -1) {
|
|
93
|
+
handlers.splice(index, 1);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* 触发事件
|
|
100
|
+
*/
|
|
101
|
+
private emit(eventType: PerformanceEventType, data?: any): void {
|
|
102
|
+
const handlers = this.eventHandlers.get(eventType);
|
|
103
|
+
handlers?.forEach((handler) => {
|
|
104
|
+
try {
|
|
105
|
+
handler({ type: eventType, data });
|
|
106
|
+
} catch (error) {
|
|
107
|
+
console.error('Error in performance event handler:', error);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* 开始性能监控
|
|
114
|
+
*/
|
|
115
|
+
public start(): void {
|
|
116
|
+
if (this.isMonitoring || !this.config.enabled) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
this.isMonitoring = true;
|
|
121
|
+
this.startTime = Date.now();
|
|
122
|
+
this.lastFrameTime = performance.now();
|
|
123
|
+
|
|
124
|
+
// 启动采样定时器
|
|
125
|
+
if (this.config.sampleInterval && this.config.realTime) {
|
|
126
|
+
this.sampleIntervalId = setInterval(() => {
|
|
127
|
+
this.sampleMetrics();
|
|
128
|
+
}, this.config.sampleInterval);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// 监听帧率
|
|
132
|
+
this.startFrameRateMonitoring();
|
|
133
|
+
|
|
134
|
+
this.emit(PerformanceEventType.MONITORING_START);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* 停止性能监控
|
|
139
|
+
*/
|
|
140
|
+
public stop(): void {
|
|
141
|
+
if (!this.isMonitoring) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
this.isMonitoring = false;
|
|
146
|
+
|
|
147
|
+
// 清除采样定时器
|
|
148
|
+
if (this.sampleIntervalId) {
|
|
149
|
+
clearInterval(this.sampleIntervalId);
|
|
150
|
+
this.sampleIntervalId = null;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// 停止帧率监控
|
|
154
|
+
this.stopFrameRateMonitoring();
|
|
155
|
+
|
|
156
|
+
this.emit(PerformanceEventType.MONITORING_END);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* 开始帧率监控
|
|
161
|
+
*/
|
|
162
|
+
private startFrameRateMonitoring(): void {
|
|
163
|
+
const updateFrameRate = () => {
|
|
164
|
+
if (!this.isMonitoring) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const currentTime = performance.now();
|
|
169
|
+
const deltaTime = currentTime - this.lastFrameTime;
|
|
170
|
+
const frameRate = deltaTime > 0 ? Math.round(1000 / deltaTime) : 0;
|
|
171
|
+
|
|
172
|
+
this.frameRateHistory.push(frameRate);
|
|
173
|
+
if (this.frameRateHistory.length > 60) {
|
|
174
|
+
this.frameRateHistory.shift();
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
this.lastFrameTime = currentTime;
|
|
178
|
+
requestAnimationFrame(updateFrameRate);
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
requestAnimationFrame(updateFrameRate);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* 停止帧率监控
|
|
186
|
+
*/
|
|
187
|
+
private stopFrameRateMonitoring(): void {
|
|
188
|
+
// requestAnimationFrame 会自动停止,不需要额外清理
|
|
189
|
+
this.frameRateHistory = [];
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* 采样性能指标
|
|
194
|
+
*/
|
|
195
|
+
private sampleMetrics(): void {
|
|
196
|
+
if (!this.isMonitoring) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// 采样帧率
|
|
201
|
+
if (this.config.metrics?.includes('frameRate') && this.frameRateHistory.length > 0) {
|
|
202
|
+
const avgFrameRate =
|
|
203
|
+
this.frameRateHistory.reduce((sum, fr) => sum + fr, 0) / this.frameRateHistory.length;
|
|
204
|
+
this.recordMetric('frameRate', avgFrameRate, 'FPS');
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// 采样内存使用(如果支持)
|
|
208
|
+
if (
|
|
209
|
+
this.config.metrics?.includes('memoryUsage') &&
|
|
210
|
+
typeof (performance as any).memory !== 'undefined'
|
|
211
|
+
) {
|
|
212
|
+
const memoryUsage = ((performance as any).memory.usedJSHeapSize / (1024 * 1024)).toFixed(2);
|
|
213
|
+
this.recordMetric('memoryUsage', parseFloat(memoryUsage), 'MB');
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* 记录性能指标
|
|
219
|
+
*/
|
|
220
|
+
public recordMetric(
|
|
221
|
+
type: PerformanceMetricType,
|
|
222
|
+
value: number,
|
|
223
|
+
unit: string,
|
|
224
|
+
description?: string
|
|
225
|
+
): void {
|
|
226
|
+
if (!this.config.enabled || !this.config.metrics?.includes(type)) {
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const metric: PerformanceMetric = {
|
|
231
|
+
type,
|
|
232
|
+
value,
|
|
233
|
+
unit,
|
|
234
|
+
timestamp: Date.now(),
|
|
235
|
+
description,
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
// 获取当前指标列表
|
|
239
|
+
const metrics = this.metrics.get(type) || [];
|
|
240
|
+
|
|
241
|
+
// 添加新指标
|
|
242
|
+
metrics.push(metric);
|
|
243
|
+
|
|
244
|
+
// 限制指标数量
|
|
245
|
+
if (this.config.maxSamples && metrics.length > this.config.maxSamples) {
|
|
246
|
+
metrics.shift();
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// 更新指标存储
|
|
250
|
+
this.metrics.set(type, metrics);
|
|
251
|
+
|
|
252
|
+
// 触发指标更新事件
|
|
253
|
+
this.emit(PerformanceEventType.METRIC_UPDATE, metric);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* 记录初始化时间
|
|
258
|
+
*/
|
|
259
|
+
public recordInitTime(duration: number): void {
|
|
260
|
+
this.recordMetric('initTime', duration, 'ms', '图表初始化耗时');
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* 记录渲染时间
|
|
265
|
+
*/
|
|
266
|
+
public recordRenderTime(duration: number): void {
|
|
267
|
+
this.recordMetric('renderTime', duration, 'ms', '图表渲染耗时');
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* 记录更新时间
|
|
272
|
+
*/
|
|
273
|
+
public recordUpdateTime(duration: number): void {
|
|
274
|
+
this.recordMetric('updateTime', duration, 'ms', '图表更新耗时');
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* 记录数据大小
|
|
279
|
+
*/
|
|
280
|
+
public recordDataSize(data: any): void {
|
|
281
|
+
try {
|
|
282
|
+
const dataSize = new Blob([JSON.stringify(data)]).size / 1024;
|
|
283
|
+
this.recordMetric('dataSize', dataSize, 'KB', '图表数据大小');
|
|
284
|
+
} catch (error) {
|
|
285
|
+
console.error('Failed to calculate data size:', error);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* 分析性能数据
|
|
291
|
+
*/
|
|
292
|
+
public analyze(): PerformanceAnalysisResult {
|
|
293
|
+
const averages: Record<PerformanceMetricType, number> = {} as Record<
|
|
294
|
+
PerformanceMetricType,
|
|
295
|
+
number
|
|
296
|
+
>;
|
|
297
|
+
const maxValues: Record<PerformanceMetricType, number> = {} as Record<
|
|
298
|
+
PerformanceMetricType,
|
|
299
|
+
number
|
|
300
|
+
>;
|
|
301
|
+
const minValues: Record<PerformanceMetricType, number> = {} as Record<
|
|
302
|
+
PerformanceMetricType,
|
|
303
|
+
number
|
|
304
|
+
>;
|
|
305
|
+
const trends: Record<PerformanceMetricType, PerformanceMetric[]> = {} as Record<
|
|
306
|
+
PerformanceMetricType,
|
|
307
|
+
PerformanceMetric[]
|
|
308
|
+
>;
|
|
309
|
+
|
|
310
|
+
let totalSamples = 0;
|
|
311
|
+
let score = 100;
|
|
312
|
+
const suggestions: string[] = [];
|
|
313
|
+
|
|
314
|
+
// 计算各项指标的统计数据
|
|
315
|
+
this.metrics.forEach((metricList, metricType) => {
|
|
316
|
+
if (metricList.length === 0) {
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
totalSamples += metricList.length;
|
|
321
|
+
trends[metricType] = [...metricList];
|
|
322
|
+
|
|
323
|
+
// 计算平均值
|
|
324
|
+
const sum = metricList.reduce((acc, metric) => acc + metric.value, 0);
|
|
325
|
+
averages[metricType] = parseFloat((sum / metricList.length).toFixed(2));
|
|
326
|
+
|
|
327
|
+
// 计算最大值
|
|
328
|
+
maxValues[metricType] = Math.max(...metricList.map((metric) => metric.value));
|
|
329
|
+
|
|
330
|
+
// 计算最小值
|
|
331
|
+
minValues[metricType] = Math.min(...metricList.map((metric) => metric.value));
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
// 计算性能评分和建议
|
|
335
|
+
if (averages.renderTime > 100) {
|
|
336
|
+
score -= 20;
|
|
337
|
+
suggestions.push('渲染时间过长,建议优化数据处理或减少图表复杂度');
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (averages.updateTime > 50) {
|
|
341
|
+
score -= 15;
|
|
342
|
+
suggestions.push('更新时间过长,建议优化数据更新逻辑');
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
if (averages.frameRate < 30) {
|
|
346
|
+
score -= 25;
|
|
347
|
+
suggestions.push('帧率过低,建议减少动画效果或优化渲染逻辑');
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
if (averages.dataSize > 100) {
|
|
351
|
+
score -= 10;
|
|
352
|
+
suggestions.push('数据量过大,建议进行数据压缩或分页处理');
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// 确保评分在0-100之间
|
|
356
|
+
score = Math.max(0, Math.min(100, score));
|
|
357
|
+
|
|
358
|
+
const result: PerformanceAnalysisResult = {
|
|
359
|
+
averages,
|
|
360
|
+
maxValues,
|
|
361
|
+
minValues,
|
|
362
|
+
trends,
|
|
363
|
+
score,
|
|
364
|
+
suggestions,
|
|
365
|
+
totalSamples,
|
|
366
|
+
duration: Date.now() - this.startTime,
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
// 触发分析完成事件
|
|
370
|
+
this.emit(PerformanceEventType.ANALYSIS_COMPLETE, result);
|
|
371
|
+
|
|
372
|
+
return result;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* 生成性能报告
|
|
377
|
+
*/
|
|
378
|
+
public generateReport(config: PerformanceReportConfig = {}): string | object {
|
|
379
|
+
const analysisResult = this.analyze();
|
|
380
|
+
const reportConfig = {
|
|
381
|
+
format: 'json' as const,
|
|
382
|
+
includeCharts: false,
|
|
383
|
+
includeSuggestions: true,
|
|
384
|
+
includeDetailedData: false,
|
|
385
|
+
...config,
|
|
386
|
+
};
|
|
387
|
+
|
|
388
|
+
switch (reportConfig.format) {
|
|
389
|
+
case 'json':
|
|
390
|
+
return this.generateJsonReport(analysisResult, reportConfig);
|
|
391
|
+
case 'csv':
|
|
392
|
+
return this.generateCsvReport(analysisResult, reportConfig);
|
|
393
|
+
case 'html':
|
|
394
|
+
return this.generateHtmlReport(analysisResult, reportConfig);
|
|
395
|
+
default:
|
|
396
|
+
return this.generateJsonReport(analysisResult, reportConfig);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* 生成 JSON 格式报告
|
|
402
|
+
*/
|
|
403
|
+
private generateJsonReport(
|
|
404
|
+
result: PerformanceAnalysisResult,
|
|
405
|
+
_config: PerformanceReportConfig
|
|
406
|
+
): object {
|
|
407
|
+
const report: any = {
|
|
408
|
+
timestamp: new Date().toISOString(),
|
|
409
|
+
duration: result.duration,
|
|
410
|
+
score: result.score,
|
|
411
|
+
totalSamples: result.totalSamples,
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
if (_config.includeSuggestions) {
|
|
415
|
+
report.suggestions = result.suggestions;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
if (_config.includeDetailedData) {
|
|
419
|
+
report.averages = result.averages;
|
|
420
|
+
report.maxValues = result.maxValues;
|
|
421
|
+
report.minValues = result.minValues;
|
|
422
|
+
report.trends = result.trends;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
return report;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* 生成 CSV 格式报告
|
|
430
|
+
*/
|
|
431
|
+
private generateCsvReport(
|
|
432
|
+
result: PerformanceAnalysisResult,
|
|
433
|
+
_config: PerformanceReportConfig
|
|
434
|
+
): string {
|
|
435
|
+
let csv = 'Metric,Type,Value,Unit\n';
|
|
436
|
+
|
|
437
|
+
// 添加平均值
|
|
438
|
+
Object.entries(result.averages).forEach(([metric, value]) => {
|
|
439
|
+
csv += `${metric},Average,${value},ms\n`;
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
// 添加最大值
|
|
443
|
+
Object.entries(result.maxValues).forEach(([metric, value]) => {
|
|
444
|
+
csv += `${metric},Max,${value},ms\n`;
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
// 添加最小值
|
|
448
|
+
Object.entries(result.minValues).forEach(([metric, value]) => {
|
|
449
|
+
csv += `${metric},Min,${value},ms\n`;
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
return csv;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/**
|
|
456
|
+
* 生成 HTML 格式报告
|
|
457
|
+
*/
|
|
458
|
+
private generateHtmlReport(
|
|
459
|
+
result: PerformanceAnalysisResult,
|
|
460
|
+
config: PerformanceReportConfig
|
|
461
|
+
): string {
|
|
462
|
+
let html = `
|
|
463
|
+
<!DOCTYPE html>
|
|
464
|
+
<html>
|
|
465
|
+
<head>
|
|
466
|
+
<title>TaroViz 性能报告</title>
|
|
467
|
+
<style>
|
|
468
|
+
body { font-family: Arial, sans-serif; margin: 20px; }
|
|
469
|
+
.report-header { background: #f0f0f0; padding: 20px; border-radius: 8px; }
|
|
470
|
+
.score { font-size: 48px; font-weight: bold; color: #4CAF50; }
|
|
471
|
+
.metric-section { margin: 20px 0; }
|
|
472
|
+
.metric-table { border-collapse: collapse; width: 100%; }
|
|
473
|
+
.metric-table th, .metric-table td { border: 1px solid #ddd; padding: 8px; text-align: left; }
|
|
474
|
+
.metric-table th { background-color: #f2f2f2; }
|
|
475
|
+
.suggestions { background: #fff3cd; padding: 15px; border-radius: 8px; margin: 20px 0; }
|
|
476
|
+
</style>
|
|
477
|
+
</head>
|
|
478
|
+
<body>
|
|
479
|
+
<div class="report-header">
|
|
480
|
+
<h1>TaroViz 性能报告</h1>
|
|
481
|
+
<p>生成时间: ${new Date().toISOString()}</p>
|
|
482
|
+
<p>监控时长: ${Math.round(result.duration / 1000)} 秒</p>
|
|
483
|
+
<div class="score">${result.score} / 100</div>
|
|
484
|
+
</div>
|
|
485
|
+
`;
|
|
486
|
+
|
|
487
|
+
// 添加指标数据
|
|
488
|
+
html += `
|
|
489
|
+
<div class="metric-section">
|
|
490
|
+
<h2>性能指标</h2>
|
|
491
|
+
<table class="metric-table">
|
|
492
|
+
<tr>
|
|
493
|
+
<th>指标</th>
|
|
494
|
+
<th>平均值</th>
|
|
495
|
+
<th>最大值</th>
|
|
496
|
+
<th>最小值</th>
|
|
497
|
+
</tr>`;
|
|
498
|
+
|
|
499
|
+
Object.entries(result.averages).forEach(([metric, average]) => {
|
|
500
|
+
const max = result.maxValues[metric as PerformanceMetricType];
|
|
501
|
+
const min = result.minValues[metric as PerformanceMetricType];
|
|
502
|
+
html += `
|
|
503
|
+
<tr>
|
|
504
|
+
<td>${metric}</td>
|
|
505
|
+
<td>${average} ms</td>
|
|
506
|
+
<td>${max} ms</td>
|
|
507
|
+
<td>${min} ms</td>
|
|
508
|
+
</tr>`;
|
|
509
|
+
});
|
|
510
|
+
|
|
511
|
+
html += `
|
|
512
|
+
</table>
|
|
513
|
+
</div>`;
|
|
514
|
+
|
|
515
|
+
// 添加建议
|
|
516
|
+
if (config.includeSuggestions && result.suggestions.length > 0) {
|
|
517
|
+
html += `
|
|
518
|
+
<div class="suggestions">
|
|
519
|
+
<h2>性能建议</h2>
|
|
520
|
+
<ul>`;
|
|
521
|
+
result.suggestions.forEach((suggestion) => {
|
|
522
|
+
html += `
|
|
523
|
+
<li>${suggestion}</li>`;
|
|
524
|
+
});
|
|
525
|
+
html += `
|
|
526
|
+
</ul>
|
|
527
|
+
</div>`;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
html += `
|
|
531
|
+
</body>
|
|
532
|
+
</html>`;
|
|
533
|
+
return html;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
/**
|
|
537
|
+
* 获取当前监控状态
|
|
538
|
+
*/
|
|
539
|
+
public getIsMonitoring(): boolean {
|
|
540
|
+
return this.isMonitoring;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
/**
|
|
544
|
+
* 获取当前配置
|
|
545
|
+
*/
|
|
546
|
+
public getConfig(): PerformanceAnalysisConfig {
|
|
547
|
+
return { ...this.config };
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
/**
|
|
551
|
+
* 更新配置
|
|
552
|
+
*/
|
|
553
|
+
public updateConfig(config: Partial<PerformanceAnalysisConfig>): void {
|
|
554
|
+
this.config = { ...this.config, ...config };
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
/**
|
|
558
|
+
* 获取所有指标数据
|
|
559
|
+
*/
|
|
560
|
+
public getAllMetrics(): Map<PerformanceMetricType, PerformanceMetric[]> {
|
|
561
|
+
return new Map(this.metrics);
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
/**
|
|
565
|
+
* 获取特定类型的指标数据
|
|
566
|
+
*/
|
|
567
|
+
public getMetricsByType(type: PerformanceMetricType): PerformanceMetric[] {
|
|
568
|
+
return this.metrics.get(type) || [];
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
/**
|
|
572
|
+
* 清空所有指标数据
|
|
573
|
+
*/
|
|
574
|
+
public clearMetrics(): void {
|
|
575
|
+
this.metrics.clear();
|
|
576
|
+
this.frameRateHistory = [];
|
|
577
|
+
this.startTime = Date.now();
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
/**
|
|
581
|
+
* 获取性能评分
|
|
582
|
+
*/
|
|
583
|
+
public getScore(): number {
|
|
584
|
+
return this.analyze().score;
|
|
585
|
+
}
|
|
586
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TaroViz 性能分析工具入口
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// 导出类型定义
|
|
6
|
+
export * from './types';
|
|
7
|
+
|
|
8
|
+
// 导出性能分析器类
|
|
9
|
+
export { PerformanceAnalyzer } from './PerformanceAnalyzer';
|
|
10
|
+
|
|
11
|
+
// 导出默认实例
|
|
12
|
+
import { PerformanceAnalyzer } from './PerformanceAnalyzer';
|
|
13
|
+
export const performanceAnalyzer = PerformanceAnalyzer.getInstance();
|