tg-map-echarts 4.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,508 @@
1
+ # 从 ECharts `bmap` 迁移到 `tgMap`
2
+
3
+ 本文介绍如何把使用 ECharts 官方 `bmap` 扩展的图表迁移到 `tg-map-echarts`。迁移后,ECharts 的热力图、散点图和自定义图形仍由 ECharts 渲染,底图则通过 `tg-map-core` 创建,可以在 Baidu、Google 和 Talks 三种地图引擎之间复用同一份图表配置和业务坐标。
4
+
5
+ ## 迁移要点
6
+
7
+ | `bmap` | `tgMap` |
8
+ | --- | --- |
9
+ | `import 'echarts/extension/bmap/bmap'` | `echarts.use(TgMapExtension)` |
10
+ | 业务代码手动加载百度地图 SDK | `await loadCachedMap(engine)` |
11
+ | 顶层 `bmap` 配置 | 顶层 `tgMap` 配置 |
12
+ | `coordinateSystem: 'bmap'` | `coordinateSystem: 'tgMap'` |
13
+ | `center: [lng, lat]` | `mapOptions.center: { lng, lat, coord }` |
14
+ | `zoom` | `mapOptions.zoom` |
15
+ | `roam` | `mapOptions.gestureHandling` |
16
+ | 业务数据提前转换为 BD-09 | 保留原始坐标,并设置 `dataCoordType` |
17
+ | `getBMap()` | `getMap()`,返回 `tg-map-core` 的统一地图对象 |
18
+ | `bmaproam` | `tgmaproam` |
19
+
20
+ `heatmap`、`effectScatter`、`scatter`、`lines` 和 `custom` 等 series 的数据结构及样式配置通常不需要改变,只需替换 `coordinateSystem`。
21
+
22
+ ## 1. 安装依赖
23
+
24
+ ```sh
25
+ pnpm add echarts tg-map-core tg-map-echarts
26
+ ```
27
+
28
+ `tg-map-echarts` 的版本号与 `tg-map-core` 保持一致,建议安装相同的明确版本,避免加载两份不同版本的 `tg-map-core`。以 `4.2.12` 为例:
29
+
30
+ ```sh
31
+ pnpm add tg-map-core@4.2.12 tg-map-echarts@4.2.12
32
+ ```
33
+
34
+ 如果项目使用的 tg-map Vue 组件库已经重新导出了同一版本的 `tg-map-core`,可以继续从 Vue 组件库导入公共地图类型和工具;但 `tg-map-echarts` 仍需单独安装。可以通过 `pnpm why tg-map-core` 确认项目只解析到兼容版本;如果存在多个模块实例,从 Vue 插件写入的地图配置可能无法被 `tg-map-echarts` 依赖的实例读取。
35
+
36
+ ## 2. 注册扩展
37
+
38
+ `bmap` 通过副作用导入自动注册:
39
+
40
+ ```ts
41
+ import * as echarts from 'echarts'
42
+ import 'echarts/extension/bmap/bmap'
43
+ ```
44
+
45
+ `tg-map-echarts` 不会自动修改 ECharts,需要显式安装一次:
46
+
47
+ ```ts
48
+ import * as echarts from 'echarts'
49
+ import { TgMapExtension } from 'tg-map-echarts'
50
+
51
+ echarts.use(TgMapExtension)
52
+ ```
53
+
54
+ 可以在应用入口统一调用 `echarts.use`,也可以放在使用地图图表的模块顶层。ECharts 会对同一个扩展去重,不需要在组件实例创建时重复注册。
55
+
56
+ 如果使用 `echarts/core` 按需引入,需要同时安装用到的图表、组件和渲染器:
57
+
58
+ ```ts
59
+ import * as echarts from 'echarts/core'
60
+ import { EffectScatterChart, HeatmapChart } from 'echarts/charts'
61
+ import { TooltipComponent, VisualMapComponent } from 'echarts/components'
62
+ import { CanvasRenderer } from 'echarts/renderers'
63
+ import { TgMapExtension } from 'tg-map-echarts'
64
+
65
+ echarts.use([
66
+ EffectScatterChart,
67
+ HeatmapChart,
68
+ TooltipComponent,
69
+ VisualMapComponent,
70
+ CanvasRenderer,
71
+ TgMapExtension,
72
+ ])
73
+ ```
74
+
75
+ ## 3. 配置并加载地图引擎
76
+
77
+ 在创建图表前,先配置 `tg-map-core`。如果应用已经通过 tg-map 的 Vue 插件传入地图配置,则不需要重复调用 `setTgMapConfig`。
78
+
79
+ ```ts
80
+ import { setTgMapConfig } from 'tg-map-core'
81
+
82
+ setTgMapConfig({
83
+ baidu: {
84
+ key: 'BAIDU_MAP_KEY',
85
+ version: '3.0',
86
+ },
87
+ google: {
88
+ key: 'GOOGLE_MAP_KEY',
89
+ language: 'zh-CN',
90
+ },
91
+ talks: {
92
+ layerIds: ['bing'],
93
+ },
94
+ })
95
+ ```
96
+
97
+ 把页面中手写的 `<script>`、JSONP 加载以及用于等待 SDK 的延时替换为 `loadCachedMap`:
98
+
99
+ ```ts
100
+ import { loadCachedMap, TgMapType } from 'tg-map-core'
101
+
102
+ const engine = TgMapType.baidu
103
+ await loadCachedMap(engine)
104
+
105
+ const chart = echarts.init(chartElement)
106
+ chart.setOption(option)
107
+ ```
108
+
109
+ 必须在 `chart.setOption()` 前等待加载完成。`loadCachedMap` 会缓存同一种引擎的加载结果,多次调用不会重复加载 SDK。Talks 引擎不依赖厂商 SDK,也使用同一个入口:
110
+
111
+ ```ts
112
+ await loadCachedMap(TgMapType.talks)
113
+ ```
114
+
115
+ ## 4. 替换组件配置
116
+
117
+ 原来的 `bmap` 配置:
118
+
119
+ ```ts
120
+ const option = {
121
+ bmap: {
122
+ center: [113.2644, 23.1291],
123
+ zoom: 14,
124
+ roam: true,
125
+ },
126
+ }
127
+ ```
128
+
129
+ 迁移为:
130
+
131
+ ```ts
132
+ import {
133
+ CoordType,
134
+ GestureHandlingOptions,
135
+ TgMapType,
136
+ } from 'tg-map-core'
137
+ import type { TgMapComponentOption } from 'tg-map-echarts'
138
+
139
+ const tgMap: TgMapComponentOption = {
140
+ engine: TgMapType.baidu,
141
+ mapOptions: {
142
+ center: {
143
+ lng: 113.2644,
144
+ lat: 23.1291,
145
+ coord: CoordType.wgs84,
146
+ },
147
+ zoom: 14,
148
+ gestureHandling: GestureHandlingOptions.greedy,
149
+ },
150
+ dataCoordType: CoordType.wgs84,
151
+ }
152
+
153
+ const option = { tgMap }
154
+ ```
155
+
156
+ 中心点使用可序列化的 `LatLngLiteral`,不要把 `LatLng` 类实例直接放进 ECharts option。`coord` 表示传入中心点的坐标类型,`tg-map-core` 会在内部将其转换为当前地图引擎需要的坐标。
157
+
158
+ ### `roam` 的迁移
159
+
160
+ `tgMap` 不再提供独立的 `roam` 字段,交互选项统一放在 `mapOptions` 中:
161
+
162
+ | 原配置 | 新配置 |
163
+ | --- | --- |
164
+ | `roam: true` | `gestureHandling: GestureHandlingOptions.greedy` |
165
+ | `roam: false` | `gestureHandling: GestureHandlingOptions.none` |
166
+ | 页面滚动时希望按住 Ctrl 或使用双指缩放 | `gestureHandling: GestureHandlingOptions.cooperative` |
167
+ | 按地图和页面环境选择默认行为 | `gestureHandling: GestureHandlingOptions.auto` |
168
+
169
+ ECharts `bmap` 的 `roam: 'move'` 和 `roam: 'scale'` 可以分别只开放平移或缩放;统一的 `gestureHandling` 当前不表达这两个细粒度组合,无法一比一迁移。如果项目使用了它们,需要根据产品交互选择最接近的模式,或者通过 `map.innerMap` 保留引擎特有的控制逻辑。
170
+
171
+ ### 地图样式
172
+
173
+ `mapStyle` 属于 `mapOptions`。因为 ECharts 会深度合并 option,而地图样式通常是很大的对象,`tgMap` 要求先将样式序列化为 JSON 字符串。
174
+
175
+ 百度样式:
176
+
177
+ ```ts
178
+ tgMap: {
179
+ engine: TgMapType.baidu,
180
+ mapOptions: {
181
+ // 省略center和zoom
182
+ mapStyle: JSON.stringify({
183
+ baidu: { styleJson: baiduStyle },
184
+ }),
185
+ },
186
+ }
187
+ ```
188
+
189
+ Google 或 Talks 样式使用同一结构中的对应字段:
190
+
191
+ ```ts
192
+ mapStyle: JSON.stringify({
193
+ google: { styles: googleStyles },
194
+ talks: { theme: 'dark' },
195
+ })
196
+ ```
197
+
198
+ 因此,迁移后不必再在初始化完成后调用 `bmap.setMapStyleV2()`。
199
+
200
+ `mapOptions.hideLogo` 目前只有 Talks 引擎支持,Baidu 和 Google 引擎会忽略该选项。原页面中用于隐藏百度地图元素的 `.anchorBL` 样式不会被扩展自动替代;是否保留应根据实际页面及地图厂商要求决定。
201
+
202
+ ## 5. 替换 series 坐标系
203
+
204
+ 将所有使用百度地图坐标系的 series:
205
+
206
+ ```ts
207
+ {
208
+ type: 'heatmap',
209
+ coordinateSystem: 'bmap',
210
+ data: points,
211
+ }
212
+ ```
213
+
214
+ 改为:
215
+
216
+ ```ts
217
+ {
218
+ type: 'heatmap',
219
+ coordinateSystem: 'tgMap',
220
+ data: points,
221
+ }
222
+ ```
223
+
224
+ 每个 ECharts 实例只能配置一个 `tgMap` 组件。所有声明 `coordinateSystem: 'tgMap'` 的 series 会共享这张地图。
225
+
226
+ ### `effectScatter` 是否需要重写
227
+
228
+ 不需要。`effectScatter` 是带涟漪动画的散点图,常用于突出 Top N 站点、告警车辆或其他重点位置。它仍由 ECharts 绘制,迁移时只替换坐标系:
229
+
230
+ ```ts
231
+ {
232
+ name: 'Top 10',
233
+ type: 'effectScatter',
234
+ coordinateSystem: 'tgMap',
235
+ data: [
236
+ { name: '站点 A', value: [113.2644, 23.1291, 95] },
237
+ ],
238
+ encode: { value: 2 },
239
+ symbolSize: value => 8 + Number(value[2]) / 10,
240
+ rippleEffect: { brushType: 'stroke' },
241
+ }
242
+ ```
243
+
244
+ `value` 的前两项始终是 `[lng, lat]`,第三项及后续项仍可作为客流、权重或业务字段。`symbolSize`、`rippleEffect`、`label`、`itemStyle` 等配置不受地图引擎变化影响。
245
+
246
+ `custom` series 中的 `api.coord([lng, lat])` 也保持不变:
247
+
248
+ ```ts
249
+ renderItem(_params, api) {
250
+ const point = api.coord([api.value(0), api.value(1)])
251
+ return {
252
+ type: 'image',
253
+ style: {
254
+ image: carIcon,
255
+ x: point[0] - 16,
256
+ y: point[1] - 16,
257
+ width: 32,
258
+ height: 32,
259
+ },
260
+ }
261
+ }
262
+ ```
263
+
264
+ ## 6. 移除业务层坐标转换
265
+
266
+ 这是迁移中最重要的变化之一。旧 `bmap` 扩展直接接收百度地图坐标,因此 WGS-84 数据通常需要先转为 BD-09:
267
+
268
+ ```ts
269
+ const points = source.map(item => {
270
+ const point = LatLng
271
+ .fromLngLat(item[0], item[1], CoordType.wgs84)
272
+ .toBaidu(CoordType.bd09)
273
+ return [point.lng, point.lat, item[2]]
274
+ })
275
+ ```
276
+
277
+ 使用 `tgMap` 后应保留业务数据的原始坐标:
278
+
279
+ ```ts
280
+ const points = source.map(item => [item[0], item[1], item[2]])
281
+
282
+ const option = {
283
+ tgMap: {
284
+ engine: TgMapType.baidu,
285
+ mapOptions: {
286
+ center: { lng: 113.2644, lat: 23.1291, coord: CoordType.wgs84 },
287
+ zoom: 14,
288
+ },
289
+ dataCoordType: CoordType.wgs84,
290
+ },
291
+ series: [{
292
+ type: 'heatmap',
293
+ coordinateSystem: 'tgMap',
294
+ data: points,
295
+ }],
296
+ }
297
+ ```
298
+
299
+ `dataCoordType` 描述该 ECharts 实例中地图 series 的 `[lng, lat, ...]` 数据坐标类型,默认为 `CoordType.wgs84`。扩展会创建带坐标类型的 `LatLng`,再由 `tg-map-core` 根据当前引擎完成转换。
300
+
301
+ 如果接口原本返回 GCJ-02 或 BD-09,则不要先转成 WGS-84,只需准确声明:
302
+
303
+ ```ts
304
+ dataCoordType: CoordType.gcj02
305
+ // 或
306
+ dataCoordType: CoordType.bd09
307
+ ```
308
+
309
+ 同一个 `tgMap` 坐标系只有一个 `dataCoordType`。如果多个 series 的源数据坐标类型不同,应先在业务层把它们统一为同一种坐标,而不是为每个 series 分别设置。
310
+
311
+ ## 7. 获取地图与监听漫游
312
+
313
+ 原来的代码直接取得百度原生地图:
314
+
315
+ ```ts
316
+ const bmap = chart.getModel().getComponent('bmap').getBMap()
317
+ ```
318
+
319
+ 迁移后取得 `tg-map-core` 的统一地图对象:
320
+
321
+ ```ts
322
+ import type { BaseMap } from 'tg-map-core'
323
+
324
+ const map: BaseMap = chart.getModel().getComponent('tgMap').getMap()
325
+
326
+ const center = map.getCenter()
327
+ const zoom = map.getZoom()
328
+ map.setCenter(center)
329
+ map.setZoom(15)
330
+ ```
331
+
332
+ 应优先使用统一 API,以便同一页面切换地图引擎。确实需要调用厂商特有能力时,可以使用 `map.innerMap` 取得当前引擎的原生地图,但这会让代码重新依赖具体引擎。
333
+
334
+ 地图中心或缩放变化后,扩展会触发 `tgMapRoam` action。ECharts 事件名称会被规范为小写,推荐按下面的方式监听:
335
+
336
+ ```ts
337
+ chart.off('tgmaproam')
338
+ chart.on('tgmaproam', () => {
339
+ const map = model.getMap()
340
+ const center = map.getCenter().to(CoordType.wgs84)
341
+
342
+ saveViewport({
343
+ center: { lng: center.lng, lat: center.lat },
344
+ zoom: map.getZoom(),
345
+ })
346
+ })
347
+ ```
348
+
349
+ 也可以从 `chart.getOption()` 读取回写后的状态。注意 `tgMap` 是组件数组,中心点位于 `mapOptions` 内:
350
+
351
+ ```ts
352
+ const option = chart.getOption() as any
353
+ const { center, zoom } = option.tgMap[0].mapOptions
354
+ ```
355
+
356
+ ## 8. 完整迁移示例
357
+
358
+ 迁移前:
359
+
360
+ ```ts
361
+ import * as echarts from 'echarts'
362
+ import 'echarts/extension/bmap/bmap'
363
+ import { CoordType, LatLng } from '@transcodegroup/tg-map'
364
+
365
+ await loadBaiduByJsonp()
366
+
367
+ const points = source.map(item => {
368
+ const point = LatLng
369
+ .fromLngLat(item.lng, item.lat, CoordType.wgs84)
370
+ .toBaidu(CoordType.bd09)
371
+ return [point.lng, point.lat, item.value]
372
+ })
373
+
374
+ const chart = echarts.init(chartElement)
375
+ chart.setOption({
376
+ bmap: {
377
+ center: [113.2644, 23.1291],
378
+ zoom: 14,
379
+ roam: true,
380
+ },
381
+ series: [
382
+ {
383
+ type: 'heatmap',
384
+ coordinateSystem: 'bmap',
385
+ data: points,
386
+ pointSize: 5,
387
+ blurSize: 10,
388
+ },
389
+ {
390
+ type: 'effectScatter',
391
+ coordinateSystem: 'bmap',
392
+ data: top10,
393
+ rippleEffect: { brushType: 'stroke' },
394
+ },
395
+ ],
396
+ })
397
+
398
+ const bmap = chart.getModel().getComponent('bmap').getBMap()
399
+ bmap.setMapStyleV2({ styleJson: baiduStyle })
400
+ ```
401
+
402
+ 迁移后:
403
+
404
+ ```ts
405
+ import * as echarts from 'echarts'
406
+ import {
407
+ CoordType,
408
+ GestureHandlingOptions,
409
+ loadCachedMap,
410
+ TgMapType,
411
+ } from 'tg-map-core'
412
+ import { TgMapExtension } from 'tg-map-echarts'
413
+
414
+ echarts.use(TgMapExtension)
415
+
416
+ const engine = TgMapType.baidu
417
+ await loadCachedMap(engine)
418
+
419
+ // 接口返回WGS-84,因此不再转为BD-09。
420
+ const points = source.map(item => [item.lng, item.lat, item.value])
421
+
422
+ const chart = echarts.init(chartElement)
423
+ chart.setOption({
424
+ tgMap: {
425
+ engine,
426
+ mapOptions: {
427
+ center: {
428
+ lng: 113.2644,
429
+ lat: 23.1291,
430
+ coord: CoordType.wgs84,
431
+ },
432
+ zoom: 14,
433
+ gestureHandling: GestureHandlingOptions.greedy,
434
+ mapStyle: JSON.stringify({
435
+ baidu: { styleJson: baiduStyle },
436
+ }),
437
+ },
438
+ dataCoordType: CoordType.wgs84,
439
+ },
440
+ series: [
441
+ {
442
+ type: 'heatmap',
443
+ coordinateSystem: 'tgMap',
444
+ data: points,
445
+ pointSize: 5,
446
+ blurSize: 10,
447
+ },
448
+ {
449
+ type: 'effectScatter',
450
+ coordinateSystem: 'tgMap',
451
+ data: top10,
452
+ rippleEffect: { brushType: 'stroke' },
453
+ },
454
+ ],
455
+ })
456
+ ```
457
+
458
+ ## 9. Vue 组件生命周期与引擎切换
459
+
460
+ ECharts 容器必须具有明确宽高:
461
+
462
+ ```css
463
+ .chart {
464
+ width: 100%;
465
+ height: 100%;
466
+ }
467
+ ```
468
+
469
+ 组件销毁时释放 ECharts 实例:
470
+
471
+ ```ts
472
+ beforeDestroy() {
473
+ this.chart?.dispose()
474
+ this.chart = null
475
+ }
476
+ ```
477
+
478
+ 容器尺寸变化后仍调用标准的 `chart.resize()`。
479
+
480
+ 不要只通过 `setOption` 修改 `tgMap.engine`。地图引擎切换会改变 SDK、DOM 结构和地图实例,应由 Vue 层执行完整重建:
481
+
482
+ ```ts
483
+ async function switchEngine(engine: TgMapType) {
484
+ chart?.dispose()
485
+ chart = undefined
486
+
487
+ await loadCachedMap(engine)
488
+ chart = echarts.init(chartElement)
489
+ chart.setOption(createOption(engine))
490
+ }
491
+ ```
492
+
493
+ ## 10. 迁移检查清单
494
+
495
+ - 删除 `echarts/extension/bmap/bmap` 的副作用导入。
496
+ - 在模块顶层调用一次 `echarts.use(TgMapExtension)`。
497
+ - 在 `setOption` 前等待 `loadCachedMap(engine)`。
498
+ - 将顶层 `bmap` 改为 `tgMap`,并补充 `engine`、`mapOptions` 和 `dataCoordType`。
499
+ - 将所有 `coordinateSystem: 'bmap'` 改为 `'tgMap'`。
500
+ - 删除 `.toBaidu(CoordType.bd09)` 等仅为百度底图准备的坐标转换。
501
+ - 将 `roam` 改为 `mapOptions.gestureHandling`。
502
+ - 将地图样式放入 `mapOptions.mapStyle` 并使用 `JSON.stringify`。
503
+ - 将 `getBMap()` 改为 `getMap()`,业务代码优先调用统一地图 API。
504
+ - 将 `bmaproam` 监听改为 `tgmaproam`。
505
+ - 切换引擎时销毁并重新创建 ECharts 实例。
506
+ - Vue 组件销毁时调用 `chart.dispose()`,尺寸变化时调用 `chart.resize()`。
507
+
508
+ 完成以上修改后,原有 `heatmap`、`effectScatter` 和 `custom` series 一般不需要进一步改写。
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "tg-map-echarts",
3
+ "version": "4.3.0",
4
+ "author": "ipcjs",
5
+ "description": "基于 tg-map-core 的 ECharts 地图坐标系扩展",
6
+ "keywords": [
7
+ "echarts",
8
+ "google-map",
9
+ "baidu-map",
10
+ "here-map",
11
+ "maptalks"
12
+ ],
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "https://github.com/TranscodeGroup/tg-map/tree/master/packages/tg-map-echarts"
16
+ },
17
+ "homepage": "https://github.com/TranscodeGroup/tg-map/issues",
18
+ "license": "MIT",
19
+ "type": "module",
20
+ "main": "./dist/tg-map-echarts.cjs",
21
+ "module": "./dist/tg-map-echarts.mjs",
22
+ "types": "./dist/src/index.d.ts",
23
+ "exports": {
24
+ ".": {
25
+ "types": "./dist/src/index.d.ts",
26
+ "import": "./dist/tg-map-echarts.mjs",
27
+ "require": "./dist/tg-map-echarts.cjs"
28
+ }
29
+ },
30
+ "files": [
31
+ "dist",
32
+ "docs",
33
+ "!dist/**/*.map",
34
+ "!dist/tsconfig.tsbuildinfo"
35
+ ],
36
+ "dependencies": {
37
+ "tg-commons": "^1.2.12",
38
+ "tg-map-core": "4.3.0"
39
+ },
40
+ "peerDependencies": {
41
+ "echarts": "^5.2.1"
42
+ },
43
+ "devDependencies": {
44
+ "@rollup/plugin-node-resolve": "^16.0.3",
45
+ "@rollup/plugin-replace": "^6.0.2",
46
+ "@rollup/plugin-typescript": "^12.1.2",
47
+ "rollup": "^4.37.0",
48
+ "tslib": "^2.8.1",
49
+ "typescript": "~5.8.3"
50
+ },
51
+ "scripts": {
52
+ "dev": "rollup -c --watch --no-watch.clearScreen",
53
+ "build": "rollup -c"
54
+ }
55
+ }