ECharts 地图注册(registerMap)完全指南
文档类型: 深度技术文档
难度等级: ⭐⭐⭐
源码版本: ECharts 5.x
本文行数: 约520行
📋 目录
🎯 registerMap基础
为什么要注册地图?
ECharts本身不包含地图数据,需要手动注册GeoJSON格式的地图数据才能使用地图功能。
typescript
import * as echarts from 'echarts';
// 注册地图
echarts.registerMap('china', chinaGeoJSON);
// 使用地图
const option = {
geo: {
map: 'china' // 引用注册的地图
}
};1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
获取地图数据
方式1: 阿里云DataV
typescript
// 中国地图
const chinaUrl = 'https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json';
// 省级地图 (以广东为例)
const guangdongUrl = 'https://geo.datav.aliyun.com/areas_v3/bound/440000_full.json';
// 市级地图
const cityUrl = 'https://geo.datav.aliyun.com/areas_v3/bound/geojson?code=440100';
async function loadMap() {
const response = await fetch(chinaUrl);
const geoJson = await response.json();
echarts.registerMap('china', geoJson);
chart.setOption({
geo: { map: 'china' }
});
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
方式2: 本地JSON文件
typescript
import chinaGeoJSON from './maps/china.json';
import worldGeoJSON from './maps/world.json';
echarts.registerMap('china', chinaGeoJSON);
echarts.registerMap('world', worldGeoJSON);1
2
3
4
5
2
3
4
5
方式3: 手动绘制GeoJSON
typescript
const customMap = {
type: 'FeatureCollection',
features: [
{
type: 'Feature',
properties: { name: '区域A' },
geometry: {
type: 'Polygon',
coordinates: [
[
[100, 30],
[110, 30],
[110, 40],
[100, 40],
[100, 30]
]
]
}
}
]
};
echarts.registerMap('custom', customMap);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
📐 GeoJSON数据格式
GeoJSON结构详解
typescript
interface GeoJSON {
type: 'FeatureCollection';
features: Feature[];
}
interface Feature {
type: 'Feature';
properties: {
name: string; // 地区名称
adcode?: string; // 行政区划代码
center?: number[]; // 中心点 [经度, 纬度]
childrenNum?: number; // 子区域数量
};
geometry: {
type: 'Polygon' | 'MultiPolygon';
coordinates: number[][][] | number[][][][];
};
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
完整示例
typescript
const exampleGeoJSON = {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"name": "北京市",
"adcode": "110000",
"center": [116.4074, 39.9042]
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[115.7, 39.4],
[117.5, 39.4],
[117.5, 41.1],
[115.7, 41.1],
[115.7, 39.4]
]
]
}
},
{
"type": "Feature",
"properties": {
"name": "天津市",
"adcode": "120000"
},
"geometry": {
"type": "Polygon",
"coordinates": [
[
[116.7, 38.4],
[118.5, 38.4],
[118.5, 40.3],
[116.7, 40.3],
[116.7, 38.4]
]
]
}
}
]
};
echarts.registerMap('jingjinji', exampleGeoJSON);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
🌍 动态加载地图
按需加载策略
typescript
class MapLoader {
private loadedMaps: Set<string> = new Set();
/**
* 异步加载并注册地图
*/
async loadMap(name: string, url: string): Promise<void> {
if (this.loadedMaps.has(name)) {
console.log(`地图 ${name} 已加载`);
return;
}
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const geoJson = await response.json();
echarts.registerMap(name, geoJson);
this.loadedMaps.add(name);
console.log(`地图 ${name} 加载成功`);
} catch (error) {
console.error(`地图 ${name} 加载失败:`, error);
throw error;
}
}
/**
* 批量加载地图
*/
async loadMultiple(maps: Array<{ name: string; url: string }>): Promise<void> {
const promises = maps.map(map => this.loadMap(map.name, map.url));
await Promise.all(promises);
}
/**
* 检查地图是否已注册
*/
isMapRegistered(name: string): boolean {
return this.loadedMaps.has(name);
}
}
// 使用
const mapLoader = new MapLoader();
async function initChart() {
await mapLoader.loadMap('china', '/maps/china.json');
chart.setOption({
geo: { map: 'china' }
});
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
省级联动加载
typescript
class ProvinceDrillDown {
private chart: echarts.ECharts;
private currentLevel: 'country' | 'province' = 'country';
constructor(container: HTMLElement) {
this.chart = echarts.init(container);
this.initCountryView();
this.bindEvents();
}
private async initCountryView() {
await this.loadAndRegister('china', '/maps/china.json');
this.chart.setOption({
title: { text: '中国地图' },
geo: {
map: 'china',
roam: true
},
series: [{
type: 'map',
geoIndex: 0,
data: this.getProvinceData()
}]
});
}
private async drillToProvince(provinceName: string) {
const provinceCode = this.getProvinceCode(provinceName);
const mapName = `province-${provinceName}`;
await this.loadAndRegister(
mapName,
`/maps/province/${provinceCode}.json`
);
this.chart.setOption({
title: { text: `${provinceName}省地图` },
geo: {
map: mapName,
roam: true
}
});
this.currentLevel = 'province';
}
private bindEvents() {
this.chart.on('click', (params: any) => {
if (this.currentLevel === 'country') {
this.drillToProvince(params.name);
}
});
}
private async loadAndRegister(name: string, url: string) {
const response = await fetch(url);
const geoJson = await response.json();
echarts.registerMap(name, geoJson);
}
private getProvinceCode(name: string): string {
const codes: Record<string, string> = {
'广东': '440000',
'江苏': '320000',
'山东': '370000',
// ... 更多省份
};
return codes[name] || '';
}
private getProvinceData() {
return [
{ name: '广东', value: 110000 },
{ name: '江苏', value: 100000 },
{ name: '山东', value: 70000 }
];
}
dispose() {
this.chart.dispose();
}
}
// 使用
const drillDown = new ProvinceDrillDown(document.getElementById('chart')!);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
🛠️ 自定义地图绘制
绘制园区平面图
typescript
const campusMap = {
type: 'FeatureCollection',
features: [
{
type: 'Feature',
properties: { name: '教学楼A' },
geometry: {
type: 'Polygon',
coordinates: [
[
[0, 0],
[100, 0],
[100, 80],
[0, 80],
[0, 0]
]
]
}
},
{
type: 'Feature',
properties: { name: '图书馆' },
geometry: {
type: 'Polygon',
coordinates: [
[
[120, 0],
[200, 0],
[200, 60],
[120, 60],
[120, 0]
]
]
}
},
{
type: 'Feature',
properties: { name: '操场' },
geometry: {
type: 'Polygon',
coordinates: [
[
[0, 100],
[150, 100],
[150, 180],
[0, 180],
[0, 100]
]
]
}
}
]
};
echarts.registerMap('campus', campusMap);
const option = {
tooltip: {
formatter: '{b}'
},
geo: {
map: 'campus',
roam: true,
label: {
show: true,
color: '#fff'
},
itemStyle: {
areaColor: '#323c48',
borderColor: '#111'
},
emphasis: {
itemStyle: {
areaColor: '#2a333d'
}
}
}
};
chart.setOption(option);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
从SVG转换GeoJSON
typescript
function svgPathToGeoJSON(svgPath: string): GeoJSON {
// 简化的转换逻辑
// 实际项目中需要使用专门的库如 turf.js
return {
type: 'FeatureCollection',
features: [
{
type: 'Feature',
properties: { name: '自定义区域' },
geometry: {
type: 'Polygon',
coordinates: parseSvgPath(svgPath)
}
}
]
};
}
function parseSvgPath(path: string): number[][][] {
// 解析SVG路径为GeoJSON坐标
// 这里需要根据实际的SVG格式进行转换
return [[[0, 0], [100, 0], [100, 100], [0, 100], [0, 0]]];
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
🎯 最佳实践总结
✅ DO - 推荐做法
缓存已加载的地图
typescriptif (!isMapLoaded(name)) { await loadMap(name); }1
2
3处理加载失败
typescripttry { await loadMap(name); } catch (error) { console.error('地图加载失败', error); // 显示错误提示 }1
2
3
4
5
6使用CDN加速
typescriptconst url = 'https://cdn.jsdelivr.net/npm/china-geojson/china.json';1
❌ DON'T - 避免做法
- 避免一次性加载所有地图typescript
// ❌ 不好 - 加载过多数据 await Promise.all(allProvinceMaps); // ✅ 好 - 按需加载 await loadMap(currentProvince);1
2
3
4
5
🔗 相关资源
下一篇: 内置中国地图
