简介:面向Web前端与数据可视化开发者的ECharts中国地图JSON数据包,包含全国及各省、地市级行政区划的边界坐标、地区编码及嵌套子区域信息,可直接用于地图注册、数据绑定与区域着色,解决ECharts地图开发中地理数据获取与格式匹配的常见问题。压缩包共424个json文件,整体约7.96MB,文件按行政区划代码命名,既有全国总图,也有分省、分地市文件,便于按需加载和地图下钻场景使用。已有3349人学习下载。通过该数据包,读者可省去手动整理GeoJSON的繁琐步骤,快速搭建中国地图可视化页面;配合ECharts的registerMap与setOption接口,能够实现点击高亮、悬浮提示等交互效果。资源适配数据大屏、管理后台、区域统计报告等常见项目,适合具备一定JavaScript基础、正在实践ECharts地图功能的开发者参考使用。 做前端可视化这块,凡是跟中国地图沾边的需求,几乎绕不开 ECharts。而 ECharts 画地图的前提,就是得有一份能用的中国地图 JSON 文件。这个文件说大不大,说小不小,但真到用的时候,坑是一个接一个:要么地图显示不出来,要么数据对不上号,要么拿到的 GeoJSON 坐标系有问题。这篇就把我实际折腾 ECharts 中国地图 JSON 文件的经验完整梳理一遍,从文件来源、格式结构、注册方式到常见报错,一次性讲透,给正在被地图数据折磨的各位一个能直接抄作业的参考。
1. 为什么 ECharts 画中国地图必须先有 JSON 文件
先聊一个基础问题:ECharts 本身是不带任何地图数据的,它只是一个纯粹的绘图引擎。你把 ECharts 引入项目后,它能画折线图、柱状图、饼图,因为这些图形是它自己用 Canvas 或 SVG 绘制的,不需要外部数据源。但地图不一样,地图的边界轮廓、省市分布、经纬度坐标,这些信息必须由外部的地理数据来提供,ECharts 只是负责把这个数据渲染出来。
这个外部数据就是 GeoJSON 格式的 JSON 文件。你可以把它理解成一份“地理信息清单”,里面记录了每个省、每个市、每个县的边界坐标点集合。ECharts 拿到这份清单后,才能知道“北京市”的轮廓是由哪些坐标点连成的,“广东省”又是由哪些坐标点围出来的。没有这份文件,你调用echarts.registerMap('china', ...)的时候直接就会报错,地图区域在图表里就是一个空白。
这里有个特别容易混淆的概念,很多人以为echarts官方包或者 CDN 上那个china.js文件就是地图数据本身。实际上,china.js只是一个封装好的脚本文件,它内部做的就是一件事:把一份 GeoJSON 数据通过echarts.registerMap('china', geoJson)注册到 ECharts 实例里。所以你完全可以不用china.js,自己找一份 JSON 文件,手动调用registerMap注册,效果一模一样。理解了这一层,后面遇到各种地图不显示的奇怪问题,排查方向就清晰多了。
2. 中国地图 GeoJSON 的获取途径与选型思路
既然 JSON 文件是刚需,那这个文件从哪来?我前前后后试过不下十种来源,真正稳定靠谱的就那么几个。这里按优先级排序,并说明各自适合什么场景。
2.1 DataV.GeoAtlas 阿里云数据可视化平台
这个是我现在的主力数据源,地址是 datav.aliyun.com/portal/school/atlas/geo_selector。它提供全国、各省、各市的 GeoJSON 下载,数据更新及时,坐标系是 GCJ-02 火星坐标系。
使用方式很简单:打开页面后,点击具体省份,右侧会出现一个 JSON 链接,直接右键另存为就能拿到文件。这个数据源最大的优点是细粒度到区县级别,比如你需要做某个省的地图,连省级边界带市级边界的文件都能直接下载,不需要自己用工具切割。
一个小提醒:DataV 的 JSON 文件里带有features数组,每个 feature 的properties字段里有name、adcode、center等信息。adcode是行政区划代码,这个是做数据映射时的黄金钥匙,后面会详细说。
2.2 echarts-maps 等 npm 包
如果你用的是 npm 管理项目,可以直接安装echarts-maps这类包。装完之后在 node_modules 里能找到china.json或者china.js。但这方式有个问题:包里的数据相对陈旧,而且很多包已经停止维护了,数据中的行政区划变动(比如某些地区代码调整)不会及时跟上。
我自己的习惯是:先用 npm 包快速验证地图能不能渲染,真正上线前再换成 DataV 或自己裁剪的数据。这样做的好处是开发阶段速度快,import chinaJson from 'echarts-maps/china.json'一行就能搞定,省去手动下载文件的步骤。
2.3 从 Highcharts 等其它图表库转包
网上有些老教程会教你去别的图表库源码里提取 GeoJSON,比如从 Highcharts 的 mapdata 模块里找。这个方法在早期挺实用,因为很多图表库把地图数据公开在 GitHub 上。但现在我不太推荐,原因有两个:一是这些数据可能是 WGS84 坐标系(后面会讲坐标系的坑),二是提取过程繁琐,要处理文件格式差异。
2.4 自己用工具生成裁剪
如果你需要的是非标准的自定义区域(比如某一个县、某几个市拼起来),现成的数据源可能不够用。这时候需要借助地图编辑工具。常见做法是用 GeoJson.io 这个在线编辑器,把下载的完整中国地图拖进去,手动选中需要的区域删除其余部分,然后导出新的 GeoJSON。
用 GeoJson.io 有个细节值得注意:导出格式要选GeoJSON,不要选TopoJSON。ECharts 对 TopoJSON 的原生支持不好,你需要额外用topojson-client转换后才能用。省一步是一步,直接导出 GeoJSON 最省心。
2.5 数据来源对比总结
| 获取方式 | 数据粒度 | 更新速度 | 操作难度 | 推荐度 |
|---|---|---|---|---|
| DataV.GeoAtlas | 省/市/区县 | 较及时 | 低 | 很高 |
| npm 包 | 省/市 | 一般 | 低 | 中等 |
| 其它图表库转包 | 省/市 | 低 | 较高 | 不推荐 |
| GeoJson.io 自剪 | 自定义 | 手动 | 中等 | 按需 |
3. GeoJSON 文件的核心结构与坐标系避坑指南
拿到一份中国地图 JSON 文件后,先别急着上代码,建议用文本编辑器打开看一眼结构。虽然 GeoJSON 的字段不多,但理解了它,后面调试地图显示问题会顺畅很多。
3.1 中国地图 GeoJSON 的标准结构
一份合法的 GeoJSON 通常长这样:
{ "type": "FeatureCollection", "features": [ { "type": "Feature", "properties": { "name": "北京市", "adcode": 110000, "center": [116.405285, 39.904989] }, "geometry": { "type": "MultiPolygon", "coordinates": [[[...]]] } } ] }这里有几个字段需要理解:
type:最外层固定是FeatureCollection,表示这是一个要素集合。features:数组,里面每一项代表一个地理区域(省、市等)。properties.name:区域名称,这个通常是做数据关联的键。properties.adcode:行政区划代码,唯一标识一个区域,比名称更可靠。geometry:几何信息,记录了边界坐标点。Polygon表示单个闭合多边形,MultiPolygon表示由多个多边形组成(像广东省有众多岛屿,用到的就是 MultiPolygon)。
3.2 坐标系陷阱:GCJ-02 还是 WGS84
坐标系这个问题,新手基本都会踩一次坑。中国地图的地理数据主要存在两套坐标系:
- WGS84:国际通用的 GPS 坐标系,GPS 设备直接输出的就是它。
- GCJ-02:中国国测局加密坐标系,也叫“火星坐标系”。国内绝大多数地图服务商(高德、DataV 等)使用这套。
ECharts 本身对坐标系没有强制要求,但如果你把 GCJ-02 的地图数据和 WGS84 的坐标点混在一起用,就会出现点位偏移。比如你用 WGS84 经纬度在 GCJ-02 地图上标注某个城市的位置,标记点可能会飞到几十公里外。
实操中的建议是:地图数据用哪套坐标系,标注点数据尽量也统一。如果你的业务数据是 GPS 设备采集的 WGS84 坐标,而地图用的是 DataV 的 GCJ-02 数据,就需要对坐标做转换。网上有 GCJ-02 和 WGS84 互转的算法代码,直接搜“coordtransform”就行,或者用gcoord这个 npm 库来转换。
3.3 属性名称规范化
还有一个小细节:不同来源的 JSON 文件,properties里的字段名可能不一样。有的叫name,有的叫NAME,有的是na。ECharts 默认用name字段作为区域名称。如果你的 JSON 文件里字段名不是name,需要在注册地图前做一次字段映射,否则地图上的区域名显示不出来。
比如你拿到一份字段名是NAME的 JSON,可以这样处理:
geoJson.features.forEach(item => { item.properties.name = item.properties.NAME; });4. 完整实操:从注册地图到数据上色
理论说完了,接下来是实战环节。我用一个完整的例子演示:如何把一份中国地图 JSON 文件加载进项目,并给不同省份按数值上色。这个例子覆盖了大部分地图场景,包括基础渲染、数据关联、分段颜色。
4.1 准备基础环境与文件
假设你用的是 Vue 3 + Vite 项目,先安装 ECharts:
npm install echarts然后在项目src/assets/目录下放一份china.json文件(从 DataV 下载)。注意,JSON 文件放本地后,用import引入即可,Vite 和 Webpack 都支持直接导入 JSON。
4.2 加载并注册地图
import * as echarts from 'echarts'; import chinaJson from './assets/china.json'; // 注册地图,第一个参数是地图名称,后面使用时要保持一致 echarts.registerMap('china', chinaJson);registerMap一旦调用,全局的 ECharts 实例都能使用名为china的地图。这里有个很多人不知道的细节:如果你将chinaJson对象直接传入,之后又修改了这个对象的内容,地图是不会自动刷新的,需要重新调用registerMap。所以如果你有动态更新地图数据的需求,记得在更新前再次注册。
4.3 配置 series-map 与 visualMap
注册完之后,写最基础的可视化配置。需求场景:展示各省份的某个业务指标,比如销售额,数值越高颜色越深。
const chart = echarts.init(document.getElementById('mapContainer')); chart.setOption({ tooltip: { trigger: 'item', formatter: params => `${params.name}: ${params.value || 0}` }, visualMap: { type: 'piecewise', pieces: [ { min: 10000, label: '1万以上' }, { min: 5000, max: 9999, label: '5000-9999' }, { min: 1000, max: 4999, label: '1000-4999' }, { min: 0, max: 999, label: '0-999' } ], left: 20, bottom: 20 }, series: [{ type: 'map', map: 'china', roam: true, label: { show: true, fontSize: 10 }, data: [ { name: '北京市', value: 12000 }, { name: '广东省', value: 8000 } // 其他省份数据... ] }] });这段代码里面的关键点:
series.type是map,map字段填的是registerMap时自定义的字符串。data数组中的name字段必须与 JSON 中properties.name一一对应,对不上就显示不出来。visualMap负责图例和颜色映射。type是piecewise还是continuous取决于业务需求。分段型适合少数几个区间对比,连续型适合数值梯度较平滑的场景。
4.4 让地图自适应容器大小
地图画完后,浏览器窗口改变大小,图不会自动跟着变,需要监听 resize 事件:
window.addEventListener('resize', () => { chart.resize(); });在 Vue 组件中,记得在onUnmounted里移除监听,并调用chart.dispose()释放实例,避免内存泄漏。
4.5 处理偏远岛屿等小区域显示问题
中国地图有个经典问题:南海诸岛默认在地图右下角以插图形式展示,但有时候你放大南海区域会发现它是一块空白。这个问题通常是数据源导致的,DataV 的全国 JSON 里,南海诸岛是包含在图内的,但 ECharts 渲染时默认的视角可能没把它显示全。
解决办法是在series里设置center和zoom来控制地图的显示范围:
series: [{ type: 'map', map: 'china', center: [104, 35], // 中心点经纬度,大约在中国几何中心 zoom: 1.2 // 缩放比例 }]如果你只关注大陆区域,可以适当加大 zoom,但要注意别把南海诸岛的图例挤出画布。这里没有完美的参数,只能根据实际效果微调。
5. 热门场景扩展:3D 地图、城市标记与分段颜色优化
做完基础的 2D 地图,再看几个高频的进阶需求。这些需求在热词里频繁出现,也是我实际接到过不少次的需求类型。
5.1 用 echarts-gl 做 3D 中国地图
3D 地图的核心是echarts-gl扩展包。安装方式:
npm install echarts-gl使用时的配置思路和 2D 地图完全不同。3D 地图通常用map3D系列,配合geo3D、scatter3D组合使用。这里贴一段简化版的代码:
import 'echarts-gl'; chart.setOption({ geo3D: { map: 'china', roam: true, itemStyle: { color: '#1a2b52', opacity: 1, borderWidth: 1, borderColor: '#5b9bd5' }, label: { show: false }, light: { main: { intensity: 1.2, shadow: true } }, viewControl: { distance: 100, alpha: 40, beta: 0 } }, series: [{ type: 'scatter3D', coordinateSystem: 'geo3D', data: [[116.405285, 39.904989, 100], [113.264385, 23.129112, 80]] // 每个元素是 [经度, 纬度, 数值] }] });这里值得多说两句:geo3D只负责底层的 3D 地理空间,真正要展示业务指标,通常在scatter3D或者bar3D里做。比如你要展示某个城市的数值,就在scatter3D的data里给出该城市的经纬度和大小,这样点会悬浮在 3D 地图的对应位置上。
3D 地图的常见问题是性能。数据量大时,3D 渲染会把浏览器卡死。我的经验是:scatter3D的数据点控制在 1000 个以内,geo3D的地图 JSON 最好做一次简化(减少边界坐标点数量),否则移动端设备基本带不动。
5.2 给指定城市标记数量
“怎么给某些市标记数量”——这是做省级地图时最常见的需求。你有一份市级数据,地图底图是省级 JSON,这时候需要拆分为两步:
第一步,拿到包含市级边界的地图 JSON。如果你下载的是某个省的地图 JSON,它的features已经是市级粒度,那直接用即可。但如果你只有全国 JSON,要展示市级数据,就需要用 GeoJson.io 把对应省的区域单独裁剪出来。
第二步,在series.data里配置每个市的数据:
series: [{ type: 'map', map: 'jiangsu', // 假设你注册了江苏省地图 data: [ { name: '南京市', value: 120 }, { name: '苏州市', value: 200 }, { name: '无锡市', value: 80 } ] }]如果你用的底图是全国 JSON,name就对应省份名称。所以你的数据粒度决定了你用哪份 JSON,别拿省级数据配全国底图,那是对不上的。
5.3 visualMap pieces 调整分段(从 9 段变 10 段)
热词里有一条很具体:echarts visualmap pieces和echarts地图9段图变10段图。这其实就是在说分段图例的配置。ECharts 的visualMap.pieces可以配置任意数量的分段,没有默认 9 段的限制。
比如原来你的图例是 9 段,想拆成 10 段,只需要在pieces数组里加一段即可:
pieces: [ { min: 10000 }, { min: 8000, max: 9999 }, { min: 6000, max: 7999 }, { min: 4000, max: 5999 }, { min: 2000, max: 3999 }, { min: 1000, max: 1999 }, { min: 500, max: 999 }, { min: 100, max: 499 }, { min: 0, max: 99 } ]这是 9 段,想变 10 段,就在最前面或最后面再插入一段。分段原则是覆盖所有数据范围,且区间不重叠。这里有个易错点:如果数据里有负值,min要设置成负数范围,否则负值没有对应颜色。
6. 常见问题排查实录与避坑技巧汇总
最后这部分,我按真实工作中排查问题的思路,整理了高频报错和现象,以及对应的解决路径。
6.1 地图区域全部空白,控制台报错 “Map china not exists”
这个报错说明china这个地图名称没有通过registerMap注册。排查顺序:
- 检查
echarts.registerMap('china', data)是否在setOption之前执行。 - 检查
registerMap的第一个参数是否和series.map的值一致。 - 检查 JSON 数据是否为
undefined,可能是文件路径写错了或者异步加载没等返回就setOption。
如果 JSON 是异步获取的,务必在setOption前等待数据返回:
const response = await fetch('/map/china.json'); const chinaJson = await response.json(); echarts.registerMap('china', chinaJson); chart.setOption(option);6.2 地图能渲染,但部分省份没有颜色
这几乎都是数据关联的问题:data数组里的name跟 JSON 里properties.name不一致。典型情况是数据源里写的是“广东”,JSON 里是“广东省”,对不上,颜色就上不去。
排查办法是在setOption前打印出 JSON 里所有区域的名称:
console.log(chinaJson.features.map(f => f.properties.name));然后跟你的 data 做对比。对不上的统一改成一致就行。这里建议以 JSON 文件里的name为准,因为那是渲染的基准。
6.3 地图渲染出来了但是有杂线/区块异常
出现杂线通常是你用的 JSON 文件格式不干净,或者坐标系投影导致边界错乱。遇到这种情况,可以先换一个数据源试试。如果所有数据源都这样,检查是不是浏览器兼容问题(老版 Safari 对大型 JSON 解析有时会异常),换 Chrome 试一下。
另一种情况是:你用的是 TopoJSON 格式但直接当成 GeoJSON 传给registerMap了。这两个格式完全不同,TopoJSON 的边界是编码压缩过的,必须先用topojson-client的feature方法解压,不能直接用。如果你发现自己的文件里有arcs字段,那肯定是 TopoJSON,不是 GeoJSON。
6.4 地图在 Vue/React 中多次切换数据不更新
框架集成时容易遇到一个怪问题:第一次渲染正常,换一批数据后地图不变。这是因为 ECharts 的setOption默认是合并配置,不是全量替换。如果你的data数组从 30 个省份变成 5 个省份,那些没有被新数据覆盖的省份还保留旧值。
解决办法是在二次更新时加上notMerge参数:
chart.setOption(newOption, true);如果还是不行,试试先chart.clear()再setOption。另外,Vue 最好在nextTick之后再初始化图表,否则容器还没有真实宽高,图表会画不出来。
6.5 JSON 文件太大加载慢
完整的中国地图 JSON(区县级)可能有好几 MB,首次加载会卡顿。优化方式有两种:
一是做数据简化,推荐用mapshaper这个免费工具,在浏览器里上传 JSON,设置简化比例(比如 0.1%)输出,可显著降低文件体积。简化后边界会有一点变形,但肉眼基本看不出来。
二是改成按需加载,比如用省级图就只加载省级 JSON,别把区县级的全量数据引入。
6.6 地图文字标签重叠严重
省名或市名文字挤在一起,尤其在西南省份密集区域。解决方式:在label里关闭重叠检测,或者自定义formatter,只对关键区域显示标签:
label: { show: true, formatter: params => { const importantNames = ['北京市', '上海市', '广东省']; return importantNames.includes(params.name) ? params.name : ''; } }这种方法在实际项目中很实用,既保留了重点区域的信息,又不至于让标签糊成一团。
7. 一点个人经验之谈
做了这么多年可视化,地图算是坑最多的一类图表,但坑的原因大都一样:数据源不稳、格式不对、坐标系混乱。我的建议是,地图 JSON 文件最好在项目里单独建一个目录管理,记录下载时间、数据来源、坐标系、简化比例,形成一份数据资产的台账。这样遇到问题能快速追溯到源头,而不是每次都靠猜。
另外,DataV 的数据源虽然好,但它的name字段有些是简称(比如“内蒙古”),有些是全称(比如“黑龙江省”),不同版本之间不完全统一。如果你要做存档或者长期维护,建议拿到 JSON 后先统一规范化一遍字段和名称,再投入使用。别看这一步琐碎,真到上线时候能省下很多事。
本文还有配套的精品资源,点击获取