ECharts自定义地图绘制详解手把手教你加载GeoJSON数据并配置省市边界样式
嘿,朋友!你是不是也被ECharts那个”地图插件必须手动注册”的问题搞疯过?别急,我来跟你聊聊这个事儿,咱们一起把自定义地图这块硬骨头啃下来。
地图这东西,到底是怎么画出来的?
ECharts做地图,核心就俩东西:GeoJSON数据和注册名字。
GeoJSON你可以理解成一张”地图轮廓线稿”,它告诉ECharts每个省、每个市边界长什么样。而注册名字就是给这张图牌个号,告诉ECharts”以后你叫我这个名字就行”。
我第一次学这个的时候,走了不少弯路,后来才搞清楚:90%的问题都是路径对不上或者JSON格式有坑。今天我把能踩的坑都给你先踩一遍,你就不用再走了。
第一步:搞到靠谱的GeoJSON数据
数据来源有几个渠道,我推荐这几个:
方式一:阿里云DataV.GeoAtlas
这是目前最好用的,打开 https://datav.aliyun.com/portal/school/atlas/area_selector ,选你需要的区域,直接下载JSON。支持全国、省、市、区县四级,精度很高。
方式二:国家地理信息公共服务平台
这个更官方,但接口稍微复杂一点,适合需要精确行政边界数据的朋友。
方式三:GitHub开源仓库
搜一下 echarts-map 或者 china-geojson ,有很多现成封装好的数据。
💡 一个小技巧:下载的JSON文件不要直接拖进浏览器看格式乱不乱,用VS Code或者在线JSON校验工具(比如 jsonlint.com)检查一下,很多报错其实是JSON格式残缺导致的。
第二步:基础案例——先把地图显示出来
这是最简化的完整代码,复制粘贴到HTML里就能跑:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>ECharts 自定义地图示例</title>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
</head>
<body>
<div id="map" style="width: 100%; height: 600px;"></div>
<script>
// 第一步:引入并注册GeoJSON
// 这里用fetch异步加载,也可以换成import或者本地数据
fetch('https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json')
.then(res => res.json())
.then(geoJson => {
// 第二步:注册地图,名字叫"china"
echarts.registerMap('china', geoJson);
// 第三步:初始化图表
const chart = echarts.init(document.getElementById('map'));
// 第四步:配置option
chart.setOption({
tooltip: {
trigger: 'item',
formatter: '{b}' // 显示省份名称
},
visualMap: {
min: 0,
max: 1000,
left: 'left',
top: 'bottom',
text: ['高', '低'],
calculable: true
},
series: [{
name: '中国地图',
type: 'map',
map: 'china', // 这里引用刚才注册的名字
roam: true, // 允许缩放和平移
zoom: 1.2,
label: {
show: true,
color: '#333'
},
// 关键样式配置,后面详细讲
itemStyle: {
borderColor: '#888',
borderWidth: 1,
areaColor: '#e8f4f8'
},
emphasis: {
itemStyle: {
areaColor: '#ffd700',
shadowBlur: 10,
shadowColor: 'rgba(0,0,0,0.3)'
},
label: {
color: '#000',
fontSize: 14,
fontWeight: 'bold'
}
},
select: {
disabled: true
},
data: [
{ name: '北京市', value: 850 },
{ name: '上海市', value: 920 },
{ name: '广东省', value: 780 },
{ name: '浙江省', value: 710 },
{ name: '江苏省', value: 690 },
{ name: '四川省', value: 450 },
{ name: '湖北省', value: 520 },
{ name: '湖南省', value: 480 }
]
}]
});
})
.catch(err => {
console.error('地图数据加载失败:', err);
});
</script>
</body>
</html>
跑起来之后你应该能看到一张中国地图,各省有颜色深浅区别。但如果只到此为止,那这篇教程就太浅了。咱们来聊聊真正的重点——样式配置。
样式配置,这才是核心
1. itemStyle:地图的本体样式
这是控制地图”长相”的核心配置,很多坑都在这:
itemStyle: {
// 区域填充色,支持颜色值、渐变色、图片
areaColor: '#d4e6f1', // 普通状态底色
borderColor: '#1a5276', // 边界线条颜色
borderWidth: 1.5, // 边界线宽度,0表示不显示
borderType: 'solid', // 线型:'solid' | 'dashed' | 'dotted'
opacity: 0.9, // 整体透明度,0-1
shadowBlur: 5, // 阴影扩散距离
shadowColor: 'rgba(0,0,0,0.2)', // 阴影颜色
shadowOffsetX: 2, // 阴影水平偏移
shadowOffsetY: 3 // 阴影垂直偏移
}
常见问题:如果你设置
borderWidth: 0但边界还是显示出来了,检查一下emphasis里是不是单独配置了。很多新手在这里栽跟头。
2. emphasis:鼠标悬停的高亮样式
这个配置决定鼠标移上去时的效果,建议做得明显一点,用户体验会好很多:
emphasis: {
itemStyle: {
areaColor: '#f39c12', // 悬停时背景色
borderColor: '#d35400',
borderWidth: 2,
shadowBlur: 15,
shadowColor: 'rgba(243, 156, 18, 0.5)'
},
label: {
show: true,
color: '#fff',
fontSize: 16,
fontWeight: 'bold',
textShadowBlur: 3,
textShadowColor: '#000'
}
}
3. select:选中状态样式
如果你需要支持框选或多选,可以配这个:
select: {
itemStyle: {
areaColor: '#3498db'
},
label: {
color: '#fff',
fontSize: 14
}
}
进阶玩法:渐变色地图
纯色地图看多了单调,用渐变色可以让地图瞬间高级起来:
itemStyle: {
// areaColor 支持渐变色配置
areaColor: {
type: 'linear',
x: 0, y: 0, x2: 0, y2: 1, // 从上到下的渐变
colorStops: [
{ offset: 0, color: '#667eea' }, // 顶部颜色
{ offset: 1, color: '#764ba2' } // 底部颜色
]
},
borderColor: '#fff',
borderWidth: 1
}
如果你想要径向渐变(从中心向外扩散),把type改成radial,然后调整坐标:
areaColor: {
type: 'radial',
x: 0.5, y: 0.5, r: 0.8, // 圆心在中心,半径80%
colorStops: [
{ offset: 0, color: '#f093fb' },
{ offset: 1, color: '#f5576c' }
]
}
按数值动态着色:visualMap配置
你肯定见过那种地图上不同省份颜色深浅不同的图,这就是visualMap的功劳:
visualMap: {
min: 0,
max: 1000,
left: 'left',
top: 'bottom',
text: ['高', '低'],
calculable: true, // 显示滑块
inRange: {
color: [
'#e8f8f5', // 低值颜色
'#a3e4d6',
'#6fcfbd',
'#27ae60', // 高值颜色
'#1a7a44'
]
},
seriesIndex: 0 // 只对这个series生效
},
series: [{
type: 'map',
map: 'china',
roam: true,
label: { show: true },
// 关键:data里的value决定颜色深浅
data: [
{ name: '北京市', value: 950 },
{ name: '上海市', value: 880 },
{ name: '广东省', value: 820 },
{ name: '浙江省', value: 790 },
{ name: '江苏省', value: 760 },
{ name: '西藏自治区', value: 50 },
{ name: '青海省', value: 80 },
{ name: '甘肃省', value: 150 }
]
}]
注意:如果某个省份没有在data里,它会被赋予默认颜色(通常是浅灰色)。所以如果你发现某些省份颜色不对,检查一下data里有没有这个名字。
全国地图 + 各省单独地图的切换
很多项目需要做”全国→省→市”的三级联动地图,实现思路是这样的:
let currentLevel = 'china'; // 当前层级
const geoJsonCache = {}; // 缓存已加载的GeoJSON
async function loadMap(level, name) {
let url;
switch(level) {
case 'china':
url = 'https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json';
break;
case 'province':
// 省份代码映射
const provinceCode = getProvinceCode(name);
url = `https://geo.datav.aliyun.com/areas_v3/bound/${provinceCode}_full.json`;
break;
case 'city':
const cityCode = getCityCode(name);
url = `https://geo.datav.aliyun.com/areas_v3/bound/${cityCode}_full.json`;
break;
}
// 如果已经加载过,直接用缓存
if (geoJsonCache[url]) {
renderMap(level, name, geoJsonCache[url]);
return;
}
try {
const res = await fetch(url);
const geoJson = await res.json();
geoJsonCache[url] = geoJson; // 存入缓存
renderMap(level, name, geoJson);
} catch (err) {
console.error('加载地图失败:', err);
// 这里可以加一个友好的错误提示
chart.clear();
chart.setOption({
graphic: [{
type: 'text',
left: 'center',
top: 'center',
style: {
text: '地图加载失败,请稍后重试',
fill: '#e74c3c',
fontSize: 18
}
}]
});
}
}
function renderMap(level, name, geoJson) {
echarts.registerMap(level, geoJson);
chart.setOption({
series: [{
type: 'map',
map: level,
roam: true,
zoom: level === 'china' ? 1.2 : 1,
label: { show: level !== 'china' },
itemStyle: {
borderColor: '#888',
borderWidth: 1,
areaColor: '#e8f4f8'
},
emphasis: {
itemStyle: {
areaColor: '#ffd700'
}
}
}]
});
// 绑定点击事件,进入下级
chart.on('click', function(params) {
if (level === 'china' && params.componentType === 'series') {
loadMap('province', params.name);
}
});
}
常见问题排查清单
下面是我从无数个报错里总结出来的”救命清单”:
问题1:地图显示不出来,控制台报series[0].map不存在
原因:没有正确注册地图。检查:
echarts.registerMap()是否成功执行map: '名字'里的名字和注册时是否一致- GeoJSON的数据是否正确(用JSON校验工具检查)
问题2:地图显示了一部分,但有些省份缺失
原因:GeoJSON数据问题。阿里云的数据一般不会缺,但如果你用的是第三方数据,很可能有缺失。解决方法是换阿里云的官方数据,或者手动补充。
问题3:点击没有反应
检查事件绑定是否正确:
chart.on('click', function(params) {
console.log(params.name); // 看有没有输出
});
如果没有输出,可能是roam: false导致交互被禁用,或者点击区域太小。
问题4:样式配置了但没生效
ECharts的样式有优先级:select > emphasis > itemStyle。检查你是不是在低优先级配置了样式,而被高优先级覆盖掉了。比如你在itemStyle里设了颜色,但emphasis里没设,那悬停时颜色会回到默认。
问题5:数据里的省份名和地图对不上
这是最常见的坑!GeoJSON里的name字段和你data里的name必须完全一致(包括空格和特殊字符)。建议先打印一下GeoJSON里的所有name:
const featureNames = geoJson.features.map(f => f.properties.name);
console.log(featureNames);
然后用这个列表来校对你的data。
性能优化建议
如果你的项目需要加载很多地图,这几个优化手段能让你少掉很多头发:
// 1. 使用缓存,避免重复加载
const mapCache = new Map();
async function getMap(name) {
if (mapCache.has(name)) return mapCache.get(name);
const res = await fetch(`/maps/${name}.json`);
const data = await res.json();
mapCache.set(name, data);
return data;
}
// 2. 按需加载,不要一次性加载所有地图
// 只在用户点击时加载对应层级的地图
// 3. 关闭不必要的动画
chart.setOption({
series: [{
animation: false // 关闭动画,渲染更快
}]
});
// 4. 大数据量时使用 simplified 版本的数据
// 阿里云支持不同精度的数据,精细度可选
最后说几句
学ECharts自定义地图,其实就记住三句话:搞到对的GeoJSON、注册对的名字、配对样式。前三步走通了,后面就是各种微调样式和交互了。
我写这段代码的时候也踩过不少坑,比如一开始用的是旧版GeoJSON数据,结果发现南海诸岛显示不对;又比如emphasis里的配置忘了写,导致鼠标悬停没有任何反馈,查了整整一个下午。所以这些坑我都帮你先填了,希望你不用重蹈覆辙。
地图这东西,可视化效果好了,老板看了高兴,用户看了明白,自己也觉得值了。希望这篇教程能帮你把这块硬骨头啃下来,有任何问题欢迎随时交流!
