@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.
Files changed (81) hide show
  1. package/README.md +324 -53
  2. package/dist/cjs/index.js +1 -0
  3. package/dist/esm/index.js +82979 -0
  4. package/package.json +160 -30
  5. package/src/__tests__/integration.test.tsx +168 -0
  6. package/src/adapters/__tests__/index.test.ts +91 -0
  7. package/src/adapters/h5/__tests__/index.test.ts +156 -0
  8. package/src/adapters/h5/index.ts +301 -0
  9. package/src/adapters/harmony/index.ts +274 -0
  10. package/src/adapters/index.ts +166 -0
  11. package/src/adapters/swan/index.ts +274 -0
  12. package/src/adapters/tt/index.ts +274 -0
  13. package/src/adapters/types.ts +162 -0
  14. package/src/adapters/weapp/index.ts +237 -0
  15. package/src/charts/bar/__tests__/index.test.tsx +113 -0
  16. package/src/charts/bar/index.tsx +18 -0
  17. package/src/charts/common/BaseChartWrapper.tsx +136 -0
  18. package/src/charts/funnel/index.tsx +18 -0
  19. package/src/charts/gauge/index.tsx +18 -0
  20. package/src/charts/heatmap/index.tsx +18 -0
  21. package/src/charts/index.ts +21 -0
  22. package/src/charts/line/__tests__/index.test.tsx +107 -0
  23. package/src/charts/line/index.tsx +18 -0
  24. package/src/charts/pie/__tests__/index.test.tsx +112 -0
  25. package/src/charts/pie/index.tsx +19 -0
  26. package/src/charts/radar/index.tsx +18 -0
  27. package/src/charts/scatter/index.tsx +18 -0
  28. package/src/charts/types.ts +619 -0
  29. package/src/charts/utils.ts +56 -0
  30. package/src/core/__tests__/platform.test.ts +48 -0
  31. package/src/core/animation/AnimationManager.ts +391 -0
  32. package/src/core/animation/index.ts +20 -0
  33. package/src/core/animation/types.ts +248 -0
  34. package/src/core/components/BaseChart.tsx +1313 -0
  35. package/src/core/components/ErrorBoundary.tsx +458 -0
  36. package/src/core/echarts.ts +58 -0
  37. package/src/core/index.ts +22 -0
  38. package/src/core/types/chart.ts +66 -0
  39. package/src/core/types/common.ts +224 -0
  40. package/src/core/types/index.ts +281 -0
  41. package/src/core/types/platform.ts +325 -0
  42. package/src/core/utils/__tests__/common.test.ts +52 -0
  43. package/src/core/utils/__tests__/environment.test.ts +94 -0
  44. package/src/core/utils/__tests__/i18n.test.ts +247 -0
  45. package/src/core/utils/__tests__/index.test.ts +219 -0
  46. package/src/core/utils/__tests__/uuid.test.ts +78 -0
  47. package/src/core/utils/chartInstances.ts +69 -0
  48. package/src/core/utils/codeGenerator/CodeGenerator.ts +655 -0
  49. package/src/core/utils/codeGenerator/index.ts +13 -0
  50. package/src/core/utils/codeGenerator/types.ts +198 -0
  51. package/src/core/utils/common.ts +58 -0
  52. package/src/core/utils/configGenerator/ConfigGenerator.ts +583 -0
  53. package/src/core/utils/configGenerator/index.ts +13 -0
  54. package/src/core/utils/configGenerator/types.ts +445 -0
  55. package/src/core/utils/debug/DebugPanel.tsx +637 -0
  56. package/src/core/utils/debug/debugger.ts +322 -0
  57. package/src/core/utils/debug/index.ts +21 -0
  58. package/src/core/utils/debug/types.ts +142 -0
  59. package/src/core/utils/i18n.ts +452 -0
  60. package/src/core/utils/index.ts +162 -0
  61. package/src/core/utils/performance/PerformanceAnalyzer.ts +586 -0
  62. package/src/core/utils/performance/index.ts +13 -0
  63. package/src/core/utils/performance/types.ts +180 -0
  64. package/src/core/utils/uuid.ts +30 -0
  65. package/src/editor/ThemeEditor.tsx +449 -0
  66. package/src/editor/index.ts +10 -0
  67. package/src/hooks/__tests__/index.test.tsx +333 -0
  68. package/src/hooks/index.ts +594 -0
  69. package/src/index.ts +75 -0
  70. package/src/main.tsx +247 -0
  71. package/src/react-dom.d.ts +7 -0
  72. package/src/themes/__tests__/index.test.ts +91 -0
  73. package/src/themes/index.ts +860 -0
  74. package/dist/389.index.esm.js +0 -1
  75. package/dist/389.index.js +0 -1
  76. package/dist/633.index.esm.js +0 -1
  77. package/dist/633.index.js +0 -1
  78. package/dist/967.index.esm.js +0 -1
  79. package/dist/967.index.js +0 -1
  80. package/dist/index.esm.js +0 -1
  81. package/dist/index.js +0 -1
@@ -0,0 +1,583 @@
1
+ /**
2
+ * TaroViz 图表配置生成器
3
+ * 用于根据简单配置生成完整的 ECharts 配置
4
+ */
5
+
6
+ import { EChartsOption } from '../../types';
7
+
8
+ import {
9
+ ConfigGeneratorOptions,
10
+ ConfigGeneratorResult,
11
+ ChartConfigTemplate,
12
+ ConfigGeneratorEventType,
13
+ ConfigGeneratorEventHandler,
14
+ ChartType,
15
+ } from './types';
16
+
17
+ /**
18
+ * 图表配置生成器类
19
+ */
20
+ export class ConfigGenerator {
21
+ private static instance: ConfigGenerator | null = null;
22
+ private eventHandlers: Map<ConfigGeneratorEventType, ConfigGeneratorEventHandler[]> = new Map();
23
+ private templates: Map<string, ChartConfigTemplate> = new Map();
24
+
25
+ /**
26
+ * 私有构造函数,使用单例模式
27
+ */
28
+ private constructor() {
29
+ // 初始化内置模板
30
+ this.initBuiltinTemplates();
31
+ }
32
+
33
+ /**
34
+ * 获取单例实例
35
+ */
36
+ public static getInstance(): ConfigGenerator {
37
+ if (!ConfigGenerator.instance) {
38
+ ConfigGenerator.instance = new ConfigGenerator();
39
+ }
40
+ return ConfigGenerator.instance;
41
+ }
42
+
43
+ /**
44
+ * 注册事件处理器
45
+ */
46
+ public on(eventType: ConfigGeneratorEventType, handler: ConfigGeneratorEventHandler): void {
47
+ if (!this.eventHandlers.has(eventType)) {
48
+ this.eventHandlers.set(eventType, []);
49
+ }
50
+ this.eventHandlers.get(eventType)?.push(handler);
51
+ }
52
+
53
+ /**
54
+ * 移除事件处理器
55
+ */
56
+ public off(eventType: ConfigGeneratorEventType, handler: ConfigGeneratorEventHandler): void {
57
+ const handlers = this.eventHandlers.get(eventType);
58
+ if (handlers) {
59
+ const index = handlers.indexOf(handler);
60
+ if (index > -1) {
61
+ handlers.splice(index, 1);
62
+ }
63
+ }
64
+ }
65
+
66
+ /**
67
+ * 初始化内置模板
68
+ */
69
+ private initBuiltinTemplates(): void {
70
+ // 折线图模板
71
+ this.registerTemplate({
72
+ name: 'basicLine',
73
+ description: '基础折线图模板',
74
+ chartTypes: ['line'],
75
+ config: {
76
+ title: {
77
+ text: '折线图示例',
78
+ },
79
+ tooltip: {
80
+ trigger: 'axis',
81
+ },
82
+ legend: {
83
+ show: true,
84
+ position: 'top',
85
+ },
86
+ xAxis: {
87
+ type: 'category',
88
+ data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
89
+ },
90
+ yAxis: {
91
+ type: 'value',
92
+ },
93
+ series: [
94
+ {
95
+ name: '系列1',
96
+ type: 'line',
97
+ data: [
98
+ { value: 120 },
99
+ { value: 200 },
100
+ { value: 150 },
101
+ { value: 80 },
102
+ { value: 70 },
103
+ { value: 110 },
104
+ { value: 130 },
105
+ ],
106
+ showInLegend: true,
107
+ },
108
+ ],
109
+ },
110
+ });
111
+
112
+ // 柱状图模板
113
+ this.registerTemplate({
114
+ name: 'basicBar',
115
+ description: '基础柱状图模板',
116
+ chartTypes: ['bar'],
117
+ config: {
118
+ title: {
119
+ text: '柱状图示例',
120
+ },
121
+ tooltip: {
122
+ trigger: 'axis',
123
+ },
124
+ legend: {
125
+ show: true,
126
+ position: 'top',
127
+ },
128
+ xAxis: {
129
+ type: 'category',
130
+ data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
131
+ },
132
+ yAxis: {
133
+ type: 'value',
134
+ },
135
+ series: [
136
+ {
137
+ name: '系列1',
138
+ type: 'bar',
139
+ data: [
140
+ { value: 120 },
141
+ { value: 200 },
142
+ { value: 150 },
143
+ { value: 80 },
144
+ { value: 70 },
145
+ { value: 110 },
146
+ { value: 130 },
147
+ ],
148
+ showInLegend: true,
149
+ },
150
+ ],
151
+ },
152
+ });
153
+
154
+ // 饼图模板
155
+ this.registerTemplate({
156
+ name: 'basicPie',
157
+ description: '基础饼图模板',
158
+ chartTypes: ['pie'],
159
+ config: {
160
+ title: {
161
+ text: '饼图示例',
162
+ },
163
+ tooltip: {
164
+ trigger: 'item',
165
+ },
166
+ legend: {
167
+ show: true,
168
+ position: 'right',
169
+ },
170
+ series: [
171
+ {
172
+ name: '访问来源',
173
+ type: 'pie',
174
+ radius: '50%',
175
+ data: [
176
+ { value: 400, name: '搜索引擎' },
177
+ { value: 335, name: '直接访问' },
178
+ { value: 310, name: '邮件营销' },
179
+ { value: 274, name: '联盟广告' },
180
+ { value: 235, name: '视频广告' },
181
+ ],
182
+ emphasis: {
183
+ itemStyle: {
184
+ shadowBlur: 10,
185
+ shadowOffsetX: 0,
186
+ shadowColor: 'rgba(0, 0, 0, 0.5)',
187
+ },
188
+ },
189
+ },
190
+ ],
191
+ },
192
+ });
193
+
194
+ // 散点图模板
195
+ this.registerTemplate({
196
+ name: 'basicScatter',
197
+ description: '基础散点图模板',
198
+ chartTypes: ['scatter'],
199
+ config: {
200
+ title: {
201
+ text: '散点图示例',
202
+ },
203
+ tooltip: {
204
+ trigger: 'item',
205
+ },
206
+ legend: {
207
+ show: true,
208
+ position: 'top',
209
+ },
210
+ xAxis: {
211
+ type: 'value',
212
+ name: 'X轴',
213
+ },
214
+ yAxis: {
215
+ type: 'value',
216
+ name: 'Y轴',
217
+ },
218
+ series: [
219
+ {
220
+ name: '系列1',
221
+ type: 'scatter',
222
+ data: [
223
+ { value: [10.0, 8.04] },
224
+ { value: [8.0, 6.95] },
225
+ { value: [13.0, 7.58] },
226
+ { value: [9.0, 8.81] },
227
+ { value: [11.0, 8.33] },
228
+ { value: [14.0, 9.96] },
229
+ { value: [6.0, 7.24] },
230
+ { value: [4.0, 4.26] },
231
+ { value: [12.0, 10.84] },
232
+ { value: [7.0, 4.82] },
233
+ { value: [5.0, 5.68] },
234
+ ],
235
+ showInLegend: true,
236
+ },
237
+ ],
238
+ },
239
+ });
240
+ }
241
+
242
+ /**
243
+ * 注册模板
244
+ */
245
+ public registerTemplate(template: ChartConfigTemplate): void {
246
+ this.templates.set(template.name, template);
247
+ }
248
+
249
+ /**
250
+ * 获取模板
251
+ */
252
+ public getTemplate(name: string): ChartConfigTemplate | undefined {
253
+ return this.templates.get(name);
254
+ }
255
+
256
+ /**
257
+ * 获取所有模板
258
+ */
259
+ public getAllTemplates(): ChartConfigTemplate[] {
260
+ return Array.from(this.templates.values());
261
+ }
262
+
263
+ /**
264
+ * 根据图表类型获取模板
265
+ */
266
+ public getTemplatesByChartType(chartType: ChartType): ChartConfigTemplate[] {
267
+ return Array.from(this.templates.values()).filter((template) =>
268
+ template.chartTypes.includes(chartType)
269
+ );
270
+ }
271
+
272
+ /**
273
+ * 删除模板
274
+ */
275
+ public removeTemplate(name: string): void {
276
+ this.templates.delete(name);
277
+ }
278
+
279
+ /**
280
+ * 生成图表配置
281
+ */
282
+ public generate(options: ConfigGeneratorOptions): ConfigGeneratorResult {
283
+ try {
284
+ // 触发生成开始事件
285
+ this.emit(ConfigGeneratorEventType.GENERATE_START, options);
286
+
287
+ // 应用模板
288
+ const mergedOptions = this.applyTemplate(options);
289
+
290
+ // 生成基础配置
291
+ const baseConfig = this.generateBaseConfig(mergedOptions);
292
+
293
+ // 生成系列配置
294
+ const seriesConfig = this.generateSeriesConfig(mergedOptions);
295
+
296
+ // 生成坐标轴配置
297
+ const axisConfig = this.generateAxisConfig(mergedOptions);
298
+
299
+ // 生成交互配置
300
+ const interactionConfig = this.generateInteractionConfig(mergedOptions);
301
+
302
+ // 合并所有配置,排除非ECharts配置
303
+ const {
304
+ chartType: _chartType,
305
+ subtitle: _subtitle,
306
+ template: _template,
307
+ responsive: _responsive,
308
+ width: _width,
309
+ height: _height,
310
+ title: _optionsTitle,
311
+ ...echartsOptions
312
+ } = mergedOptions;
313
+ // 使用类型断言确保TypeScript接受生成的配置
314
+ const finalOption = {
315
+ ...baseConfig,
316
+ ...seriesConfig,
317
+ ...axisConfig,
318
+ ...interactionConfig,
319
+ ...echartsOptions,
320
+ } as EChartsOption;
321
+
322
+ // 计算数据项数量
323
+ const dataItemCount = mergedOptions.series.reduce((count, series) => {
324
+ return count + series.data.length;
325
+ }, 0);
326
+
327
+ const result: ConfigGeneratorResult = {
328
+ option: finalOption,
329
+ metadata: {
330
+ chartType: mergedOptions.chartType,
331
+ seriesCount: mergedOptions.series.length,
332
+ dataItemCount,
333
+ generatedAt: Date.now(),
334
+ },
335
+ };
336
+
337
+ // 触发生成完成事件
338
+ this.emit(ConfigGeneratorEventType.GENERATE_COMPLETE, result);
339
+
340
+ return result;
341
+ } catch (error) {
342
+ // 触发生成失败事件
343
+ this.emit(ConfigGeneratorEventType.GENERATE_ERROR, { error });
344
+ throw error;
345
+ }
346
+ }
347
+
348
+ /**
349
+ * 应用模板
350
+ */
351
+ private applyTemplate(options: ConfigGeneratorOptions): ConfigGeneratorOptions {
352
+ if (!options.template) {
353
+ return options;
354
+ }
355
+
356
+ const template = this.getTemplate(options.template);
357
+ if (!template) {
358
+ return options;
359
+ }
360
+
361
+ // 触发模板应用事件
362
+ this.emit(ConfigGeneratorEventType.TEMPLATE_APPLY, { template, options });
363
+
364
+ // 合并模板配置和用户配置
365
+ return {
366
+ ...template.config,
367
+ ...options,
368
+ series: options.series || template.config.series || [],
369
+ xAxis: options.xAxis || template.config.xAxis,
370
+ yAxis: options.yAxis || template.config.yAxis,
371
+ } as ConfigGeneratorOptions;
372
+ }
373
+
374
+ /**
375
+ * 生成基础配置
376
+ */
377
+ private generateBaseConfig(options: ConfigGeneratorOptions): EChartsOption {
378
+ const baseConfig: EChartsOption = {};
379
+
380
+ // 添加标题
381
+ if (options.title || options.subtitle) {
382
+ if (typeof options.title === 'string') {
383
+ baseConfig.title = {
384
+ text: options.title,
385
+ subtext: options.subtitle,
386
+ };
387
+ } else if (options.title) {
388
+ baseConfig.title = {
389
+ ...options.title,
390
+ subtext: options.title.subtext || options.subtitle,
391
+ };
392
+ } else if (options.subtitle) {
393
+ baseConfig.title = {
394
+ subtext: options.subtitle,
395
+ };
396
+ }
397
+ }
398
+
399
+ // 添加主题
400
+ if (options.theme) {
401
+ baseConfig.theme = options.theme;
402
+ }
403
+
404
+ return baseConfig;
405
+ }
406
+
407
+ /**
408
+ * 生成系列配置
409
+ */
410
+ private generateSeriesConfig(options: ConfigGeneratorOptions): EChartsOption {
411
+ const series = options.series.map((seriesConfig, index) => {
412
+ // 处理数据,转换为ECharts支持的格式
413
+ const processedData = seriesConfig.data.map((item) => {
414
+ if (typeof item.value === 'number') {
415
+ return { name: item.name, value: item.value };
416
+ }
417
+ return item.value;
418
+ });
419
+
420
+ // 创建系列配置,避免重复属性
421
+ const baseSeries: any = {
422
+ name: seriesConfig.name || `系列${index + 1}`,
423
+ xAxisIndex: seriesConfig.xAxisIndex,
424
+ yAxisIndex: seriesConfig.yAxisIndex,
425
+ ...seriesConfig,
426
+ data: processedData,
427
+ };
428
+
429
+ // 移除不需要的属性
430
+ delete baseSeries.showInLegend;
431
+ delete baseSeries.style;
432
+
433
+ return baseSeries;
434
+ });
435
+
436
+ return { series };
437
+ }
438
+
439
+ /**
440
+ * 生成坐标轴配置
441
+ */
442
+ private generateAxisConfig(options: ConfigGeneratorOptions): EChartsOption {
443
+ const axisConfig: EChartsOption = {};
444
+
445
+ // 处理X轴配置
446
+ if (options.xAxis) {
447
+ axisConfig.xAxis = Array.isArray(options.xAxis)
448
+ ? options.xAxis.map((axis) => this.normalizeAxisConfig(axis))
449
+ : this.normalizeAxisConfig(options.xAxis);
450
+ } else if (this.needsAxis(options.chartType)) {
451
+ // 为需要坐标轴的图表类型生成默认X轴
452
+ axisConfig.xAxis = this.normalizeAxisConfig({ type: 'category' });
453
+ }
454
+
455
+ // 处理Y轴配置
456
+ if (options.yAxis) {
457
+ axisConfig.yAxis = Array.isArray(options.yAxis)
458
+ ? options.yAxis.map((axis) => this.normalizeAxisConfig(axis))
459
+ : this.normalizeAxisConfig(options.yAxis);
460
+ } else if (this.needsAxis(options.chartType)) {
461
+ // 为需要坐标轴的图表类型生成默认Y轴
462
+ axisConfig.yAxis = this.normalizeAxisConfig({ type: 'value' });
463
+ }
464
+
465
+ return axisConfig;
466
+ }
467
+
468
+ /**
469
+ * 标准化坐标轴配置
470
+ */
471
+ private normalizeAxisConfig(axis: any): any {
472
+ return {
473
+ type: 'category',
474
+ show: true,
475
+ ...axis,
476
+ };
477
+ }
478
+
479
+ /**
480
+ * 生成交互配置
481
+ */
482
+ private generateInteractionConfig(options: ConfigGeneratorOptions): EChartsOption {
483
+ const interactionConfig: EChartsOption = {};
484
+
485
+ // 生成图例配置
486
+ if (options.legend) {
487
+ const showLegend = options.legend.show !== false;
488
+ if (showLegend) {
489
+ interactionConfig.legend = {
490
+ show: true,
491
+ position: 'top',
492
+ type: 'plain',
493
+ ...options.legend,
494
+ };
495
+ }
496
+ }
497
+
498
+ // 生成提示框配置
499
+ if (options.tooltip) {
500
+ const showTooltip = options.tooltip.show !== false;
501
+ if (showTooltip) {
502
+ interactionConfig.tooltip = {
503
+ show: true,
504
+ trigger: this.getTooltipTrigger(options.chartType),
505
+ ...options.tooltip,
506
+ };
507
+ }
508
+ }
509
+
510
+ // 生成工具箱配置
511
+ if (options.toolbox) {
512
+ interactionConfig.toolbox = {
513
+ show: true,
514
+ feature: {
515
+ saveAsImage: {},
516
+ restore: {},
517
+ ...options.toolbox.feature,
518
+ },
519
+ ...options.toolbox,
520
+ } as any;
521
+ }
522
+
523
+ // 生成数据缩放配置
524
+ if (options.dataZoom) {
525
+ interactionConfig.dataZoom = options.dataZoom;
526
+ }
527
+
528
+ return interactionConfig;
529
+ }
530
+
531
+ /**
532
+ * 获取提示框触发方式
533
+ */
534
+ private getTooltipTrigger(chartType: ChartType): 'item' | 'axis' | 'none' {
535
+ const axisCharts = ['line', 'bar', 'scatter', 'boxplot', 'candlestick', 'parallel'];
536
+ const itemCharts = ['pie', 'gauge', 'funnel', 'sunburst', 'treemap', 'wordCloud'];
537
+
538
+ if (axisCharts.includes(chartType)) {
539
+ return 'axis';
540
+ } else if (itemCharts.includes(chartType)) {
541
+ return 'item';
542
+ }
543
+
544
+ return 'none';
545
+ }
546
+
547
+ /**
548
+ * 判断图表类型是否需要坐标轴
549
+ */
550
+ private needsAxis(chartType: ChartType): boolean {
551
+ const noAxisCharts = ['pie', 'gauge', 'funnel', 'sunburst', 'treemap', 'wordCloud', 'liquid'];
552
+ return !noAxisCharts.includes(chartType);
553
+ }
554
+
555
+ /**
556
+ * 预览配置
557
+ */
558
+ public preview(options: ConfigGeneratorOptions): void {
559
+ const result = this.generate(options);
560
+ this.emit(ConfigGeneratorEventType.CONFIG_PREVIEW, result);
561
+ }
562
+
563
+ /**
564
+ * 触发事件
565
+ */
566
+ private emit(eventType: ConfigGeneratorEventType, data?: any): void {
567
+ const handlers = this.eventHandlers.get(eventType);
568
+ handlers?.forEach((handler) => {
569
+ try {
570
+ handler({ type: eventType, data });
571
+ } catch (error) {
572
+ console.error('Error in config generator event handler:', error);
573
+ }
574
+ });
575
+ }
576
+
577
+ /**
578
+ * 重置实例
579
+ */
580
+ public static resetInstance(): void {
581
+ ConfigGenerator.instance = null;
582
+ }
583
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * TaroViz 图表配置生成器入口
3
+ */
4
+
5
+ // 导出类型定义
6
+ export * from './types';
7
+
8
+ // 导出配置生成器类
9
+ export { ConfigGenerator } from './ConfigGenerator';
10
+
11
+ // 导出默认实例
12
+ import { ConfigGenerator } from './ConfigGenerator';
13
+ export const configGenerator = ConfigGenerator.getInstance();