ECharts 地图未注册白屏完全指南
文档类型: 反模式警示
难度等级: ⭐⭐
源码版本: ECharts 5.x
本文行数: 约320行
📋 目录
🎯 问题描述
典型症状
typescript
// ❌ 错误: 未注册地图就使用
const option = {
geo: {
map: 'china' // ⚠️ 但从未注册过!
}
};
chart.setOption(option);
// 结果: 地图区域完全空白,无任何错误提示!1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
表现:
- 地图区域空白
- Console无报错 (静默失败)
- 用户困惑
❌ 常见原因
原因1: 忘记引入地图数据
typescript
import * as echarts from 'echarts';
// ❌ 忘记这一行!
// import 'echarts/map/js/china.js';
const chart = echarts.init(container);
chart.setOption({
geo: { map: 'china' } // 白屏!
});1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
原因2: 注册顺序错误
typescript
const chart = echarts.init(container);
// ❌ 先使用地图
chart.setOption({
geo: { map: 'china' }
});
// 后注册 (太晚了!)
echarts.registerMap('china', geoJson);1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
原因3: 地图名称不匹配
typescript
// 注册时使用 'china-custom'
echarts.registerMap('china-custom', geoJson);
// 使用时写错成 'china'
const option = {
geo: { map: 'china' } // ❌ 找不到!
};1
2
3
4
5
6
7
2
3
4
5
6
7
✅ 解决方案
方案1: 确保先注册后使用
typescript
import * as echarts from 'echarts';
import chinaGeoJSON from './maps/china.json';
// ✅ 1. 先注册
echarts.registerMap('china', chinaGeoJSON);
// ✅ 2. 再使用
const chart = echarts.init(container);
chart.setOption({
geo: { map: 'china' }
});1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
方案2: 检查地图是否已注册
typescript
function safeSetMap(chart: echarts.ECharts, mapName: string) {
// 检查地图是否已注册
const registeredMap = echarts.getMap(mapName);
if (!registeredMap) {
console.error(`地图 "${mapName}" 未注册!`);
// 显示错误提示
chart.setOption({
title: {
text: `地图 "${mapName}" 加载失败`,
left: 'center',
top: 'middle'
}
});
return false;
}
// 地图已注册,可以安全使用
chart.setOption({
geo: { map: mapName }
});
return true;
}
// 使用
safeSetMap(chart, '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
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
方案3: 异步加载并验证
typescript
async function loadAndUseMap(chart: echarts.ECharts, mapName: string, url: string) {
try {
// 显示加载提示
chart.showLoading();
// 检查是否已注册
if (!echarts.getMap(mapName)) {
// 从服务器加载
const response = await fetch(url);
const geoJson = await response.json();
// 注册地图
echarts.registerMap(mapName, geoJson);
console.log(`地图 "${mapName}" 注册成功`);
}
// 使用地图
chart.setOption({
geo: { map: mapName }
});
} catch (error) {
console.error('地图加载失败:', error);
chart.setOption({
title: {
text: '地图加载失败,请刷新重试',
left: 'center',
top: 'middle'
}
});
} finally {
chart.hideLoading();
}
}
// 使用
loadAndUseMap(chart, 'china', '/maps/china.json');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
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
🔍 预防措施
预防1: 启动时检查
typescript
function validateMaps() {
const requiredMaps = ['china', 'world'];
const missing: string[] = [];
requiredMaps.forEach(mapName => {
if (!echarts.getMap(mapName)) {
missing.push(mapName);
}
});
if (missing.length > 0) {
console.warn('⚠️ 以下地图未注册:', missing);
console.warn('请确保已引入地图数据文件');
} else {
console.log('✅ 所有必需的地图已注册');
}
}
// 应用启动时调用
validateMaps();1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
预防2: TypeScript类型检查
typescript
// types/maps.d.ts
type RegisteredMap = 'china' | 'world' | 'guangdong' | 'beijing';
interface SafeGeoOption {
map: RegisteredMap;
}
// 编译时就能发现错误
const option: SafeGeoOption = {
map: 'china' // ✅ 合法
// map: 'invalid' // ❌ TypeScript报错!
};1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
预防3: 单元测试
typescript
describe('Map Registration Test', () => {
it('should have china map registered', () => {
const map = echarts.getMap('china');
expect(map).toBeTruthy();
});
it('should render map without errors', () => {
const chart = echarts.init(container);
expect(() => {
chart.setOption({
geo: { map: 'china' }
});
}).not.toThrow();
chart.dispose();
});
});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
class RobustMapLoader {
private chart: echarts.ECharts;
constructor(container: HTMLElement) {
this.chart = echarts.init(container);
}
/**
* 安全加载地图
*/
async loadMap(mapName: string, fallbackUrl?: string): Promise<boolean> {
// 1. 检查是否已注册
if (echarts.getMap(mapName)) {
console.log(`地图 "${mapName}" 已缓存`);
this.useMap(mapName);
return true;
}
// 2. 尝试从fallback URL加载
if (fallbackUrl) {
try {
await this.loadFromUrl(mapName, fallbackUrl);
return true;
} catch (error) {
console.error(`从URL加载失败:`, error);
}
}
// 3. 所有尝试都失败
this.showMapError(mapName);
return false;
}
private async loadFromUrl(mapName: string, url: string): Promise<void> {
this.chart.showLoading();
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const geoJson = await response.json();
echarts.registerMap(mapName, geoJson);
this.useMap(mapName);
} finally {
this.chart.hideLoading();
}
}
private useMap(mapName: string) {
this.chart.setOption({
geo: {
map: mapName,
roam: true
}
});
}
private showMapError(mapName: string) {
this.chart.setOption({
title: {
text: `地图 "${mapName}" 不可用`,
subtext: '请检查网络连接或联系管理员',
left: 'center',
top: 'middle'
}
});
}
dispose() {
this.chart.dispose();
}
}
// 使用
const loader = new RobustMapLoader(document.getElementById('chart')!);
// 尝试加载,失败时有降级方案
loader.loadMap('china', '/maps/china-backup.json');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
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
🎯 最佳实践总结
✅ DO - 推荐做法
始终先注册后使用
typescriptecharts.registerMap('china', geoJson); chart.setOption({ geo: { map: 'china' } });1
2检查地图是否已注册
typescriptif (!echarts.getMap(name)) { console.error('地图未注册'); }1
2
3提供降级方案
typescriptloadMap('china', '/backup/china.json');1
❌ DON'T - 避免做法
- 不要假设地图已注册typescript
// ❌ 危险 chart.setOption({ geo: { map: 'china' } }); // ✅ 安全 if (echarts.getMap('china')) { chart.setOption({ geo: { map: 'china' } }); }1
2
3
4
5
6
7
🔗 相关资源
下一篇: 动画过度干扰
