@agions/taroviz 1.11.5 → 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.
Files changed (118) hide show
  1. package/CHANGELOG.md +245 -0
  2. package/README.md +31 -46
  3. package/dist/cjs/index.js +1 -1
  4. package/dist/cjs/vendors.js +1 -1
  5. package/dist/cjs/vendors~echarts.js +1 -1
  6. package/dist/esm/index.js +1 -14270
  7. package/dist/esm/vendors.js +1 -16770
  8. package/dist/esm/vendors~echarts.js +1 -59417
  9. package/package.json +10 -15
  10. package/src/adapters/h5/index.ts +38 -38
  11. package/src/adapters/index.ts +32 -34
  12. package/src/adapters/types.ts +23 -55
  13. package/src/charts/boxplot/types.ts +2 -2
  14. package/src/charts/common/BaseChartWrapper.tsx +9 -7
  15. package/src/charts/createChartComponent.tsx +9 -21
  16. package/src/charts/createOptionChartComponent.tsx +32 -0
  17. package/src/charts/funnel/__tests__/index.test.tsx +99 -0
  18. package/src/charts/funnel/index.tsx +64 -0
  19. package/src/charts/funnel/types.ts +6 -0
  20. package/src/charts/graph/__tests__/index.test.tsx +116 -0
  21. package/src/charts/graph/index.tsx +70 -0
  22. package/src/charts/graph/types.ts +6 -0
  23. package/src/charts/heatmap/__tests__/index.test.tsx +139 -0
  24. package/src/charts/heatmap/index.tsx +107 -0
  25. package/src/charts/heatmap/types.ts +6 -0
  26. package/src/charts/index.ts +47 -57
  27. package/src/charts/liquid/__tests__/index.test.tsx +52 -0
  28. package/src/charts/liquid/index.tsx +7 -133
  29. package/src/charts/liquid/types.ts +6 -6
  30. package/src/charts/parallel/types.ts +3 -3
  31. package/src/charts/radar/__tests__/index.test.tsx +210 -0
  32. package/src/charts/radar/index.tsx +147 -0
  33. package/src/charts/radar/types.ts +13 -0
  34. package/src/charts/sankey/__tests__/index.test.tsx +124 -0
  35. package/src/charts/sankey/index.tsx +70 -0
  36. package/src/charts/sankey/types.ts +6 -0
  37. package/src/charts/tree/__tests__/index.test.tsx +71 -0
  38. package/src/charts/tree/index.tsx +1 -1
  39. package/src/charts/tree/types.ts +8 -8
  40. package/src/charts/types.ts +208 -106
  41. package/src/charts/wordcloud/__tests__/index.test.tsx +106 -0
  42. package/src/charts/wordcloud/index.tsx +79 -0
  43. package/src/charts/wordcloud/types.ts +6 -0
  44. package/src/components/DataFilter/index.tsx +7 -6
  45. package/src/core/animation/types.ts +6 -6
  46. package/src/core/components/Annotation.tsx +6 -6
  47. package/src/core/components/BaseChart.tsx +97 -133
  48. package/src/core/components/LazyChart.tsx +3 -8
  49. package/src/core/components/hooks/index.ts +6 -2
  50. package/src/core/components/hooks/usePerformance.ts +8 -2
  51. package/src/core/components/hooks/useVirtualScroll.ts +2 -1
  52. package/src/core/types/common.ts +2 -1
  53. package/src/core/types/platform.ts +1 -0
  54. package/src/core/utils/__tests__/deepClone.test.ts +317 -0
  55. package/src/core/utils/__tests__/index.test.ts +2 -1
  56. package/src/core/utils/chartInstances.ts +13 -0
  57. package/src/core/utils/common.ts +20 -36
  58. package/src/core/utils/deepClone.ts +114 -0
  59. package/src/core/utils/download.ts +22 -28
  60. package/src/core/utils/drillDown.ts +1 -0
  61. package/src/core/utils/events.ts +12 -0
  62. package/src/core/utils/export/ExportUtils.ts +2 -1
  63. package/src/core/utils/format.ts +44 -0
  64. package/src/core/utils/index.ts +18 -159
  65. package/src/core/utils/merge.ts +25 -0
  66. package/src/core/utils/performance/PerformanceAnalyzer.ts +3 -1
  67. package/src/core/utils/performance/hooks.ts +7 -0
  68. package/src/core/utils/performance/index.ts +2 -0
  69. package/src/{hooks → core/utils/performance}/useAnimation.ts +6 -5
  70. package/src/{hooks → core/utils/performance}/useDataZoom.ts +7 -2
  71. package/src/{hooks → core/utils/performance}/usePerformance.ts +39 -39
  72. package/src/{hooks → core/utils/performance}/usePerformanceHooks.ts +39 -39
  73. package/src/core/utils/runtime.ts +190 -0
  74. package/src/editor/components/ThemeSelector.tsx +3 -3
  75. package/src/hooks/chartConnectHelpers.ts +6 -0
  76. package/src/hooks/index.ts +54 -626
  77. package/src/hooks/types.ts +27 -0
  78. package/src/hooks/useChartAutoResize.ts +73 -0
  79. package/src/hooks/useChartConnect.ts +5 -1
  80. package/src/hooks/useChartDownload.ts +1 -1
  81. package/src/hooks/useChartHistory.ts +1 -3
  82. package/src/hooks/useChartInit.ts +59 -0
  83. package/src/hooks/useChartOptions.ts +259 -0
  84. package/src/hooks/useChartPerformance.ts +109 -0
  85. package/src/hooks/useChartSelection.ts +23 -12
  86. package/src/hooks/useChartTheme.ts +51 -0
  87. package/src/hooks/useDataTransform.ts +19 -4
  88. package/src/index.ts +5 -10
  89. package/src/react-dom.d.ts +3 -3
  90. package/src/themes/index.ts +30 -855
  91. package/src/themes/palettes/blue-green.ts +13 -0
  92. package/src/themes/palettes/chalk.ts +13 -0
  93. package/src/themes/palettes/cyber.ts +44 -0
  94. package/src/themes/palettes/dark.ts +52 -0
  95. package/src/themes/palettes/default.ts +52 -0
  96. package/src/themes/palettes/elegant.ts +34 -0
  97. package/src/themes/palettes/forest.ts +13 -0
  98. package/src/themes/palettes/glass.ts +49 -0
  99. package/src/themes/palettes/golden.ts +13 -0
  100. package/src/themes/palettes/neon.ts +43 -0
  101. package/src/themes/palettes/ocean.ts +39 -0
  102. package/src/themes/palettes/pastel.ts +37 -0
  103. package/src/themes/palettes/purple-passion.ts +13 -0
  104. package/src/themes/palettes/retro.ts +33 -0
  105. package/src/themes/palettes/sunset.ts +40 -0
  106. package/src/themes/palettes/walden.ts +13 -0
  107. package/src/themes/registry.ts +184 -0
  108. package/src/themes/types.ts +213 -0
  109. package/src/core/utils/codeGenerator/CodeGenerator.ts +0 -669
  110. package/src/core/utils/codeGenerator/index.ts +0 -13
  111. package/src/core/utils/codeGenerator/types.ts +0 -198
  112. package/src/core/utils/configGenerator/ConfigGenerator.ts +0 -583
  113. package/src/core/utils/configGenerator/index.ts +0 -13
  114. package/src/core/utils/configGenerator/types.ts +0 -449
  115. package/src/core/utils/debug/DebugPanel.tsx +0 -640
  116. package/src/core/utils/debug/debugger.ts +0 -322
  117. package/src/core/utils/debug/index.ts +0 -21
  118. package/src/core/utils/debug/types.ts +0 -142
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@agions/taroviz",
3
- "version": "1.11.5",
4
- "description": "基于 Taro 和 ECharts 的多端图表组件库",
3
+ "version": "2.0.3",
4
+ "description": "基于 Taro 和 ECharts 的多端图表组件库 - v2.0.0 大版本更新,新增 6 种图表类型",
5
5
  "type": "module",
6
6
  "main": "dist/cjs/index.js",
7
7
  "module": "dist/esm/index.js",
@@ -42,10 +42,6 @@
42
42
  "test:watch": "jest --watch",
43
43
  "test:ci": "jest --ci --maxWorkers=50%",
44
44
  "test:coverage": "jest --coverage",
45
- "cypress:open": "cypress open",
46
- "cypress:run": "cypress run",
47
- "cypress:component": "cypress open --component",
48
- "test:e2e": "cypress run --e2e",
49
45
  "lint": "eslint src --ext .ts,.tsx",
50
46
  "lint:fix": "eslint src --ext .ts,.tsx --fix",
51
47
  "lint:prettier": "prettier --check \"src/**/*.{ts,tsx,js,jsx,json,css,md}\"",
@@ -86,24 +82,24 @@
86
82
  "@commitlint/cli": "^19.0.0",
87
83
  "@commitlint/config-conventional": "^19.0.0",
88
84
  "@release-it/conventional-changelog": "^8.0.0",
89
- "@testing-library/cypress": "^10.1.0",
90
85
  "@testing-library/dom": "^10.4.1",
91
86
  "@testing-library/jest-dom": "^6.9.1",
92
87
  "@testing-library/react": "^16.3.0",
93
88
  "@types/jest": "^29.5.12",
94
- "@types/node": "^20.11.24",
89
+ "@types/node": "^20.19.39",
95
90
  "@types/react": "^18.2.61",
96
91
  "@types/react-dom": "^18.3.7",
97
92
  "@types/testing-library__jest-dom": "^5.14.9",
98
93
  "@typescript-eslint/eslint-plugin": "^8.59.1",
99
94
  "@typescript-eslint/parser": "^8.59.1",
100
- "ajv": "^8.18.0",
95
+ "ajv": "^8.20.0",
96
+ "ajv-formats": "^3.0.1",
101
97
  "babel-loader": "^10.0.0",
102
98
  "clean-webpack-plugin": "^4.0.0",
103
99
  "commitizen": "^4.3.0",
104
100
  "core-js": "3.41.0",
105
101
  "css-loader": "^7.1.2",
106
- "cypress": "^15.7.0",
102
+ "echarts": "^5.6.0",
107
103
  "eslint": "^9.39.4",
108
104
  "eslint-config-prettier": "^10.1.8",
109
105
  "eslint-import-resolver-typescript": "^4.3.2",
@@ -120,6 +116,7 @@
120
116
  "marked": "^12.0.2",
121
117
  "mini-css-extract-plugin": "^2.9.2",
122
118
  "prettier": "^3.2.5",
119
+ "react": "^18.2.0",
123
120
  "react-dom": "^18.3.1",
124
121
  "release-it": "^17.0.0",
125
122
  "rimraf": "^5.0.5",
@@ -130,13 +127,14 @@
130
127
  "ts-loader": "^9.5.2",
131
128
  "typedoc": "^0.28.2",
132
129
  "typedoc-plugin-markdown": "^3.17.1",
133
- "typescript": "^5.3.3",
130
+ "typescript": "^5.9.3",
134
131
  "vitepress": "^1.6.4",
135
132
  "webpack": "^5.90.3",
136
133
  "webpack-bundle-analyzer": "^4.10.2",
137
134
  "webpack-cli": "^5.1.4",
138
135
  "webpack-dev-server": "^5.0.4",
139
- "whatwg-fetch": "^3.6.20"
136
+ "whatwg-fetch": "^3.6.20",
137
+ "zrender": "^5.6.1"
140
138
  },
141
139
  "dependencies": {
142
140
  "@babel/runtime": "^7.28.4",
@@ -147,7 +145,6 @@
147
145
  "@tarojs/runtime": "^3.6.0",
148
146
  "@tarojs/taro": "^3.6.0",
149
147
  "echarts": "^5.4.3",
150
- "react": "^18.2.0",
151
148
  "zrender": "^5.4.3"
152
149
  },
153
150
  "peerDependenciesMeta": {
@@ -179,8 +176,6 @@
179
176
  "url": "https://github.com/agions/taroviz/issues"
180
177
  },
181
178
  "overrides": {
182
- "ajv": "^8.18.0",
183
- "ajv-formats": "^3.0.0",
184
179
  "brace-expansion": "^3.0.1",
185
180
  "esbuild": "^0.24.2",
186
181
  "systeminformation": "^5.22.0",
@@ -23,7 +23,7 @@ interface ExtendedH5AdapterOptions extends H5AdapterOptions {
23
23
  height?: number | string;
24
24
  theme?: string | object;
25
25
  option?: EChartsOption;
26
- onInit?: (instance: EChartsType) => void;
26
+ onInit?: (_instance: EChartsType) => void;
27
27
  containerRef?: HTMLElement | { current: HTMLElement | null };
28
28
  direction?: 'ltr' | 'rtl';
29
29
  }
@@ -46,7 +46,7 @@ class H5Adapter implements Adapter {
46
46
  /**
47
47
  * 图表实例
48
48
  */
49
- private instance: EChartsType | null = null;
49
+ private _instance: EChartsType | null = null;
50
50
  private options: ExtendedH5AdapterOptions;
51
51
  private containerRef: ExtendedH5AdapterOptions['containerRef'] = undefined;
52
52
  private canvasId: string;
@@ -70,8 +70,8 @@ class H5Adapter implements Adapter {
70
70
  * 初始化图表
71
71
  */
72
72
  init(_options?: EChartsOption): EChartsType {
73
- if (this.instance) {
74
- return this.instance;
73
+ if (this._instance) {
74
+ return this._instance;
75
75
  }
76
76
 
77
77
  // 获取容器元素
@@ -85,16 +85,16 @@ class H5Adapter implements Adapter {
85
85
 
86
86
  // 初始化图表
87
87
 
88
- this.instance = echarts.init(container as HTMLElement, this.options.theme, {
88
+ this._instance = echarts.init(container as HTMLElement, this.options.theme, {
89
89
  // 性能优化选项
90
90
  useDirtyRect: true, // 使用脏矩形渲染,减少重绘区域
91
91
  renderer: this.options.renderer || 'canvas',
92
92
  }) as unknown as EChartsType;
93
93
 
94
94
  // 设置性能优化相关的全局配置
95
- if (this.instance) {
95
+ if (this._instance) {
96
96
  // 渐进式渲染配置
97
- this.instance.setOption(
97
+ this._instance.setOption(
98
98
  {
99
99
  animation: this.options.option?.animation !== false,
100
100
  animationDurationUpdate: 300,
@@ -107,31 +107,31 @@ class H5Adapter implements Adapter {
107
107
  }
108
108
 
109
109
  // 设置初始化选项,使用lazyUpdate优化性能
110
- if (this.options.option && this.instance) {
111
- this.instance.setOption(this.options.option, false, true);
110
+ if (this.options.option && this._instance) {
111
+ this._instance.setOption(this.options.option, false, true);
112
112
  }
113
113
 
114
114
  // 执行初始化回调
115
- if (this.options.onInit && this.instance) {
116
- this.options.onInit(this.instance);
115
+ if (this.options.onInit && this._instance) {
116
+ this.options.onInit(this._instance);
117
117
  }
118
118
 
119
- return this.instance as EChartsType;
119
+ return this._instance as EChartsType;
120
120
  }
121
121
 
122
122
  /**
123
123
  * 获取图表实例
124
124
  */
125
125
  getInstance(): EChartsType | null {
126
- return this.instance;
126
+ return this._instance;
127
127
  }
128
128
 
129
129
  /**
130
130
  * 设置图表选项
131
131
  */
132
132
  setOption(option: EChartsOption, notMerge?: boolean, lazyUpdate?: boolean): void {
133
- if (this.instance) {
134
- this.instance.setOption(option, notMerge, lazyUpdate);
133
+ if (this._instance) {
134
+ this._instance.setOption(option, notMerge, lazyUpdate);
135
135
  } else {
136
136
  this.options.option = option;
137
137
  }
@@ -142,9 +142,9 @@ class H5Adapter implements Adapter {
142
142
  */
143
143
  setTheme(theme: string | object): void {
144
144
  this.options.theme = theme;
145
- if (this.instance) {
145
+ if (this._instance) {
146
146
  // 使用类型断言来访问私有方法
147
- (this.instance as any).setTheme?.(theme);
147
+ (this._instance as any).setTheme?.(theme);
148
148
  }
149
149
  }
150
150
 
@@ -152,14 +152,14 @@ class H5Adapter implements Adapter {
152
152
  * 获取图表宽度
153
153
  */
154
154
  getWidth(): number {
155
- return this.instance?.getWidth() || 0;
155
+ return this._instance?.getWidth() || 0;
156
156
  }
157
157
 
158
158
  /**
159
159
  * 获取图表高度
160
160
  */
161
161
  getHeight(): number {
162
- return this.instance?.getHeight() || 0;
162
+ return this._instance?.getHeight() || 0;
163
163
  }
164
164
 
165
165
  /**
@@ -178,15 +178,15 @@ class H5Adapter implements Adapter {
178
178
  pixelRatio?: number;
179
179
  backgroundColor?: string;
180
180
  }): string | undefined {
181
- return this.instance?.getDataURL(opts);
181
+ return this._instance?.getDataURL(opts);
182
182
  }
183
183
 
184
184
  /**
185
185
  * 清空图表
186
186
  */
187
187
  clear(): void {
188
- if (this.instance) {
189
- this.instance.clear();
188
+ if (this._instance) {
189
+ this._instance.clear();
190
190
  }
191
191
  }
192
192
 
@@ -194,8 +194,8 @@ class H5Adapter implements Adapter {
194
194
  * 绑定事件
195
195
  */
196
196
  on(event: string, handler: EventHandler): void {
197
- if (this.instance) {
198
- this.instance.on(event, handler as any);
197
+ if (this._instance) {
198
+ this._instance.on(event, handler as any);
199
199
  }
200
200
  }
201
201
 
@@ -203,8 +203,8 @@ class H5Adapter implements Adapter {
203
203
  * 解绑事件
204
204
  */
205
205
  off(event: string, handler?: EventHandler): void {
206
- if (this.instance) {
207
- this.instance.off(event, handler as any);
206
+ if (this._instance) {
207
+ this._instance.off(event, handler as any);
208
208
  }
209
209
  }
210
210
 
@@ -212,8 +212,8 @@ class H5Adapter implements Adapter {
212
212
  * 显示加载动画
213
213
  */
214
214
  showLoading(opts?: object): void {
215
- if (this.instance) {
216
- this.instance.showLoading(opts);
215
+ if (this._instance) {
216
+ this._instance.showLoading(opts);
217
217
  }
218
218
  }
219
219
 
@@ -221,8 +221,8 @@ class H5Adapter implements Adapter {
221
221
  * 隐藏加载动画
222
222
  */
223
223
  hideLoading(): void {
224
- if (this.instance) {
225
- this.instance.hideLoading();
224
+ if (this._instance) {
225
+ this._instance.hideLoading();
226
226
  }
227
227
  }
228
228
 
@@ -250,9 +250,9 @@ class H5Adapter implements Adapter {
250
250
  * 销毁图表
251
251
  */
252
252
  dispose(): void {
253
- if (this.instance) {
254
- this.instance.dispose();
255
- this.instance = null;
253
+ if (this._instance) {
254
+ this._instance.dispose();
255
+ this._instance = null;
256
256
  }
257
257
  }
258
258
 
@@ -260,8 +260,8 @@ class H5Adapter implements Adapter {
260
260
  * 触发图表行为
261
261
  */
262
262
  dispatchAction(payload: { type: string; [key: string]: unknown }): void {
263
- if (this.instance) {
264
- this.instance.dispatchAction(payload);
263
+ if (this._instance) {
264
+ this._instance.dispatchAction(payload);
265
265
  }
266
266
  }
267
267
 
@@ -269,15 +269,15 @@ class H5Adapter implements Adapter {
269
269
  * 获取DataURL
270
270
  */
271
271
  getDataURL(opts?: object): string | undefined {
272
- return this.instance?.getDataURL(opts);
272
+ return this._instance?.getDataURL(opts);
273
273
  }
274
274
 
275
275
  /**
276
276
  * 处理图表大小变化
277
277
  */
278
278
  resize(opts?: object): void {
279
- if (this.instance) {
280
- this.instance.resize(opts);
279
+ if (this._instance) {
280
+ this._instance.resize(opts);
281
281
  }
282
282
  }
283
283
 
@@ -6,6 +6,8 @@
6
6
  */
7
7
 
8
8
  import { PlatformType } from '../core';
9
+ import { detectRuntime } from '../core/utils/runtime';
10
+ import type { RuntimeInfo } from '../core/utils/runtime';
9
11
  import type { AdapterOptions, Adapter } from './types';
10
12
 
11
13
  /**
@@ -31,40 +33,37 @@ const PLATFORM_CONFIGS: Record<PlatformType, PlatformConfig> = {
31
33
  [PlatformType.HARMONY]: { name: 'HarmonyOS', requireComponent: true },
32
34
  };
33
35
 
36
+ /** Map RuntimeInfo miniAppType to PlatformType */
37
+ const MINI_APP_TO_PLATFORM: Record<string, PlatformType> = {
38
+ weapp: PlatformType.WEAPP,
39
+ alipay: PlatformType.ALIPAY,
40
+ swan: PlatformType.SWAN,
41
+ tt: PlatformType.TT,
42
+ qq: PlatformType.QQ,
43
+ jd: PlatformType.JD,
44
+ dd: PlatformType.DD,
45
+ qywx: PlatformType.QYWX,
46
+ lark: PlatformType.LARK,
47
+ kwai: PlatformType.KWAI,
48
+ };
49
+
34
50
  /**
35
51
  * 检测当前运行的平台环境
52
+ *
53
+ * Delegates to the unified detectRuntime() and maps the result to PlatformType.
54
+ * Also checks for HarmonyOS via userAgent, which is not a mini-app.
36
55
  */
37
56
  export function detectPlatform(): PlatformType {
38
- if (typeof window === 'undefined') {
39
- return PlatformType.H5;
57
+ const runtime: RuntimeInfo = detectRuntime();
58
+
59
+ if (runtime.platform === 'miniapp' && runtime.miniAppType) {
60
+ return MINI_APP_TO_PLATFORM[runtime.miniAppType] ?? PlatformType.H5;
40
61
  }
41
62
 
42
- const win = window as Window & {
43
- wx?: { getSystemInfoSync?: unknown; qy?: unknown };
44
- my?: { getSystemInfoSync?: unknown };
45
- swan?: { getSystemInfoSync?: unknown };
46
- tt?: { getSystemInfoSync?: unknown; env?: { appName?: string } };
47
- qq?: { getSystemInfoSync?: unknown };
48
- jd?: { getSystemInfoSync?: unknown };
49
- dd?: { getSystemInfoSync?: unknown };
50
- };
51
-
52
- const checks: Array<{ test: () => boolean; platform: PlatformType }> = [
53
- { test: () => !!win.wx?.getSystemInfoSync && !win.wx?.qy, platform: PlatformType.WEAPP },
54
- { test: () => !!win.my?.getSystemInfoSync, platform: PlatformType.ALIPAY },
55
- { test: () => !!win.swan?.getSystemInfoSync, platform: PlatformType.SWAN },
56
- { test: () => !!win.tt?.getSystemInfoSync, platform: PlatformType.TT },
57
- { test: () => !!win.qq?.getSystemInfoSync, platform: PlatformType.QQ },
58
- { test: () => !!win.jd?.getSystemInfoSync, platform: PlatformType.JD },
59
- { test: () => !!win.dd?.getSystemInfoSync, platform: PlatformType.DD },
60
- { test: () => !!win.wx?.qy, platform: PlatformType.QYWX },
61
- { test: () => win.tt?.env?.appName === 'lark', platform: PlatformType.LARK },
62
- { test: () => navigator.userAgent.includes('HarmonyOS'), platform: PlatformType.HARMONY },
63
- ];
64
-
65
- for (const check of checks) {
66
- if (check.test()) {
67
- return check.platform;
63
+ // HarmonyOS: detected via userAgent in browser context
64
+ if (runtime.platform === 'browser' && typeof navigator !== 'undefined') {
65
+ if (navigator.userAgent.includes('HarmonyOS')) {
66
+ return PlatformType.HARMONY;
68
67
  }
69
68
  }
70
69
 
@@ -75,13 +74,12 @@ export function detectPlatform(): PlatformType {
75
74
  * 判断运行环境
76
75
  */
77
76
  export function getEnv(): 'h5' | 'weapp' | 'unknown' {
78
- if (typeof window !== 'undefined' && typeof document !== 'undefined') {
77
+ const runtime = detectRuntime();
78
+
79
+ if (runtime.isBrowser) {
79
80
  return 'h5';
80
81
  }
81
- if (
82
- typeof global !== 'undefined' &&
83
- (global as Global & { wx?: { getSystemInfoSync?: unknown } })?.wx?.getSystemInfoSync
84
- ) {
82
+ if (runtime.isMiniApp && runtime.miniAppType === 'weapp') {
85
83
  return 'weapp';
86
84
  }
87
85
  return 'unknown';
@@ -131,7 +129,7 @@ export async function getAdapter(options: AdapterOptions): Promise<Adapter> {
131
129
  }
132
130
  case PlatformType.HARMONY: {
133
131
  const { HarmonyAdapter } = (await import('./harmony')) as unknown as {
134
- HarmonyAdapter: { create: (opts: object) => Adapter };
132
+ HarmonyAdapter: { create: (_opts: object) => Adapter };
135
133
  };
136
134
  return HarmonyAdapter.create(options);
137
135
  }
@@ -22,7 +22,7 @@ export interface AdapterOptions {
22
22
  theme?: string | object;
23
23
  option?: unknown;
24
24
 
25
- onInit?: (instance: EChartsType) => void;
25
+ onInit?: (_instance: EChartsType) => void;
26
26
  style?: CSSProperties;
27
27
  autoResize?: boolean;
28
28
  devicePixelRatio?: number;
@@ -49,57 +49,25 @@ export interface WeappAdapterOptions extends AdapterOptions {
49
49
  component?: object;
50
50
  }
51
51
 
52
- /**
53
- * 支付宝小程序适配器选项
54
- */
55
- export interface AlipayAdapterOptions extends AdapterOptions {}
56
-
57
- /**
58
- * 百度小程序适配器选项
59
- */
60
- export interface SwanAdapterOptions extends AdapterOptions {}
61
-
62
- /**
63
- * 鸿蒙OS适配器选项
64
- */
65
- export interface HarmonyAdapterOptions extends AdapterOptions {}
66
-
67
- /**
68
- * 钉钉小程序适配器选项
69
- */
70
- export interface DDAdapterOptions extends AdapterOptions {}
71
-
72
- /**
73
- * 抖音小程序适配器选项
74
- */
75
- export interface TTAdapterOptions extends AdapterOptions {}
76
-
77
- /**
78
- * QQ小程序适配器选项
79
- */
80
- export interface QQAdapterOptions extends AdapterOptions {}
81
-
82
- /**
83
- * 京东小程序适配器选项
84
- */
85
- export interface JDAdapterOptions extends AdapterOptions {}
86
-
87
- /**
88
- * 快手小程序适配器选项
89
- */
90
- export interface KwaiAdapterOptions extends AdapterOptions {}
91
-
92
- /**
93
- * 企业微信小程序适配器选项
94
- */
95
- export interface QywxAdapterOptions extends AdapterOptions {}
96
-
97
- /**
98
- * 飞书小程序适配器选项
99
- */
100
- export interface LarkAdapterOptions extends AdapterOptions {}
101
-
102
- /**
103
- * 小程序通用适配器选项
104
- */
105
- 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;
@@ -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, (params: ECElementEvent) => void>;
13
+ onEvents?: Record<string, (_params: ECElementEvent) => void>;
14
14
  loading?: boolean;
15
15
  loadingOption?: LoadingOptions;
16
16
  theme?: string;
17
- onChartReady?: (chart: EChartsType) => void;
17
+ onChartReady?: (_chart: EChartsType) => void;
18
18
  opts?: {
19
19
  devicePixelRatio?: number;
20
20
  renderer?: 'canvas' | 'svg';
@@ -64,7 +64,7 @@ const BaseChartWrapper: React.FC<BaseChartProps & { chartType: string }> = ({
64
64
  const seriesData = useMemo(() => extractSeriesData(option), [option]);
65
65
  const ariaLabel = useMemo(() => buildAriaLabel(chartType, option), [chartType, option]);
66
66
 
67
- // Keyboard handler for zoom/pan — attached to the chart container
67
+ // Keyboard _handler for zoom/pan — attached to the chart container
68
68
  const handleKeyDown = useCallback((e: React.KeyboardEvent<HTMLDivElement>) => {
69
69
  const instance = chartInstance.current;
70
70
  if (!instance) return;
@@ -161,12 +161,12 @@ const BaseChartWrapper: React.FC<BaseChartProps & { chartType: string }> = ({
161
161
  chartInstance.current = instance;
162
162
 
163
163
  if (onEvents) {
164
- Object.entries(onEvents).forEach(([eventName, handler]) => {
164
+ Object.entries(onEvents).forEach(([_eventName, _handler]) => {
165
165
  (
166
166
  instance as unknown as {
167
- on: (event: string, handler: (...args: unknown[]) => void) => void;
167
+ on: (_event: string, _handler: (..._args: unknown[]) => void) => void;
168
168
  }
169
- ).on(eventName, handler);
169
+ ).on(_eventName, _handler);
170
170
  });
171
171
  }
172
172
 
@@ -181,6 +181,7 @@ const BaseChartWrapper: React.FC<BaseChartProps & { chartType: string }> = ({
181
181
  });
182
182
 
183
183
  const adapter = await getAdapter(initConfig);
184
+ const adapterRef = adapter; // store for cleanup
184
185
 
185
186
  if (!isMountedRef.current) {
186
187
  return;
@@ -189,11 +190,12 @@ const BaseChartWrapper: React.FC<BaseChartProps & { chartType: string }> = ({
189
190
  adapter.init();
190
191
 
191
192
  cleanupRef.current = () => {
193
+ adapterRef.dispose?.();
192
194
  const instance = chartInstance.current;
193
195
  if (instance) {
194
196
  if (onEvents) {
195
- Object.entries(onEvents).forEach(([eventName]) => {
196
- (instance as unknown as { off: (event: string) => void }).off(eventName);
197
+ Object.entries(onEvents).forEach(([_eventName]) => {
198
+ (instance as unknown as { off: (_event: string) => void }).off(_eventName);
197
199
  });
198
200
  }
199
201
  instance.dispose();
@@ -286,7 +288,7 @@ const BaseChartWrapper: React.FC<BaseChartProps & { chartType: string }> = ({
286
288
 
287
289
  {/*
288
290
  Chart container with role="application" + keyboard navigation.
289
- role="application" tells assistive tech to pass through keyboard events.
291
+ role="application" tells assistive tech to pass through keyboard _events.
290
292
  aria-describedby links to the hidden data table above.
291
293
  */}
292
294
  <div
@@ -9,37 +9,25 @@ import BaseChartWrapper from './common/BaseChartWrapper';
9
9
  import type { BaseChartProps } from './types';
10
10
 
11
11
  /**
12
- * 创建标准图表组件
12
+ * 创建图表组件
13
13
  * @param displayName 组件名称
14
14
  * @param chartType ECharts 图表类型
15
+ * @param needOptionCast 是否需要 option 类型转换(用于 boxplot、parallel 等)
15
16
  * @returns 带 displayName 的 memo 组件
16
17
  */
17
18
  export function createChartComponent<P extends BaseChartProps = BaseChartProps>(
18
19
  displayName: string,
19
- chartType: string
20
- ): React.FC<P> {
21
- const Chart: React.FC<P> = memo((props) => (
22
- <BaseChartWrapper {...(props as unknown as BaseChartProps)} chartType={chartType} />
23
- ));
24
- Chart.displayName = displayName;
25
- return Chart;
26
- }
27
-
28
- /**
29
- * 创建需要 EChartsOption 类型转换的图表组件
30
- * 用于 boxplot、parallel 等使用自定义 Props 类型但需要转换 option 的图表
31
- * @param displayName 组件名称
32
- * @param chartType ECharts 图表类型
33
- * @returns 带 displayName 的 memo 组件
34
- */
35
- export function createChartComponentWithOptionCast<P extends Record<string, unknown>>(
36
- displayName: string,
37
- chartType: string
20
+ chartType: string,
21
+ needOptionCast = false
38
22
  ): React.FC<P> {
39
23
  const Chart: React.FC<P> = memo((props) => (
40
24
  <BaseChartWrapper
41
25
  {...(props as unknown as BaseChartProps)}
42
- option={(props as { option?: EChartsOption }).option as EChartsOption}
26
+ option={
27
+ needOptionCast
28
+ ? ((props as { option?: EChartsOption }).option as EChartsOption)
29
+ : (props as unknown as BaseChartProps).option
30
+ }
43
31
  chartType={chartType}
44
32
  />
45
33
  ));
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Factory for charts that follow the buildXxxOption + render pattern.
3
+ * Eliminates the repeated null-check + BaseChart wrapper code.
4
+ */
5
+ import React from 'react';
6
+ import BaseChart from '@/core/components/BaseChart';
7
+ import type { BaseChartProps } from './types';
8
+
9
+ interface OptionBuilderProps {
10
+ optionMerge?: Record<string, unknown>;
11
+ }
12
+
13
+ /**
14
+ * Creates a chart component from a buildOption function.
15
+ * @param displayName Component display name
16
+ * @param buildOption Function that builds ECharts option from props, returns null if invalid
17
+ */
18
+ export function createOptionChartComponent<Props extends OptionBuilderProps>(
19
+ displayName: string,
20
+ buildOption: (props: Props) => Record<string, unknown> | null
21
+ ): React.FC<Props & Omit<BaseChartProps, 'option' | 'data'>> {
22
+ const Component: React.FC<Props & Omit<BaseChartProps, 'option' | 'data'>> = (props) => {
23
+ const { optionMerge, ...rest } = props;
24
+ const option = buildOption(props as Props);
25
+ if (!option) {
26
+ return null;
27
+ }
28
+ return <BaseChart option={option as any} {...(rest as BaseChartProps)} />;
29
+ };
30
+ Component.displayName = displayName;
31
+ return Component;
32
+ }