ECharts中国地图数据包:GeoJSON与JS格式解析及接入实战
简介:这份资源是面向前端开发与数据可视化学习者的中国地图数据包,聚焦 ECharts 地理图表与 H5 应用场景,解决地图底图数据获取与渲染配置的问题。压缩包共 76 个文件,以 38 个 json 与 37 个 js 为主,另有 1 个 txt 说明,整体约 2.71MB;json 文件承载中国及各省份、城市、世界范围的地理坐标与边界结构,js 文件则对应地图初始化、轮廓绘制与交互逻辑代码,可直接引入项目使用。目前已有 1834 人学习下载。借助这些数据,开发者能快速实现省份颜色填充、区域高亮、悬浮提示等效果,并在此基础上叠加经济指标、人口数据等业务信息,构建响应式动态地图,适用于数据分析报告、新闻展示与教学演示等场景,对提升 ECharts 地图开发与地理信息可视化能力有实际参考价值。
1. 拿到「最新中国地图js&json数据文件.zip」先别急着解压:它到底解决什么问题
做 ECharts 中国地图可视化的人,几乎都经历过同一个卡点:代码写完了,echarts.registerMap('china', geoJson)一跑,控制台报Map china not exists,或者地图出来了但南海诸岛、港澳台边界缺一块。问题不在 ECharts,而在你手上没有一份完整、合规、能直接喂给registerMap的地理边界数据。这个 zip 包要解决的,就是「地图底图数据从哪来、怎么用、怎么和 ECharts 对接」这件事。
它本质是一份中国省级行政区域的 GeoJSON 边界数据,外加一份可直接<script>引入的 JS 版本。GeoJSON 是 JSON 格式的地理数据,用FeatureCollection描述每个省的Polygon或MultiPolygon坐标;JS 版本则是把同样的数据包成window.chinaMapData = {...}或echarts.registerMap的调用形式,省去你手动 fetch 的步骤。适合三类人:做数据大屏的前端、用 ECharts 做区域分布图的运营分析、以及需要离线部署(内网、无外网 CDN)的场景。下面从数据长什么样讲到怎么跑通、参数怎么调、坑在哪。
2. 拆开这个包:GeoJSON 与 JS 两种格式的取舍和字段含义
2.1 GeoJSON 的 FeatureCollection 结构长什么样
一份标准的中国地图 GeoJSON,顶层是FeatureCollection,features数组里每个元素是一个省。关键字段只有四个:type、properties、geometry、以及properties里的name。name是 ECharts 做数据映射时的匹配键,写错一个字,那个省就渲染不出颜色。
{ "type": "FeatureCollection", "features": [ { "type": "Feature", "properties": { "name": "广东省", "adcode": 440000, "center": [113.280637, 23.125178], "level": "province" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [[113.1, 23.3], [113.2, 23.4], [113.15, 23.25]] ] ] } } ] }properties.name是 EChartsseries.data里name字段的匹配依据,必须和你的业务数据完全一致。adcode是行政区划代码,做下钻联动时用它比用中文名稳。center是省份中心点经纬度,打点、标线、飞线动画全靠它。geometry.type通常是MultiPolygon,因为一个省可能有岛屿,坐标是[经度, 纬度]顺序,别写反。
2.2 JS 版本为什么更适合直接引入
JS 版本把 JSON 包成了变量或注册调用,好处是省掉一次异步请求,页面加载即用。常见两种写法,一种是纯数据变量:
// china-map.js —— 挂到全局,供后续 registerMap 使用 window.chinaMapData = { type: "FeatureCollection", features: [ /* 同 GeoJSON 结构 */ ] };另一种是直接注册,引入即生效:
// 依赖已加载的 echarts 全局对象 echarts.registerMap('china', { /* FeatureCollection */ });第一种更灵活,你可以在注册前对数据做裁剪(比如只保留华东几省);第二种省事,但要求echarts必须先加载。选哪个取决于你是否需要动态改数据。内网大屏我一般用第一种,把数据文件和业务代码解耦。
2.3 两种格式的对比与选型
| 维度 | GeoJSON (.json) | JS 版本 (.js) |
|---|---|---|
| 加载方式 | fetch / import,异步 | <script>同步引入 |
| 可读性 | 纯数据,工具友好 | 带变量包装,需去壳 |
| 离线部署 | 需处理跨域 | 直接可用 |
| 动态裁剪 | 加载后随意改 | 需先拿到变量再改 |
| 体积 | 略小 | 多几行包装 |
选型结论:做静态大屏、内网部署,用 JS 版本最省心;做需要按权限裁剪区域、或数据来自后端的,用 GeoJSON 走 fetch。别两个都引,重复注册同名 map 会覆盖,排查起来很费时间。
3. 用 ECharts 把这份地图数据跑起来的最小可复现路径
3.1 引入顺序与 registerMap 的正确姿势
ECharts 地图渲染分两步:先注册地图数据,再在 option 里用geo或series-map引用。注册必须在setOption之前完成,否则报Map china not exists。下面是最小可跑通页面。
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>中国地图最小示例</title> <!-- 1. 先加载 echarts --> <script src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script> <!-- 2. 再加载地图数据(JS 版本,内部调用 registerMap) --> <script src="./china-map.js"></script> </head> <body> <div id="map" style="width: 900px; height: 600px;"></div> <script> // 3. 数据注册完成后才能初始化并 setOption const chart = echarts.init(document.getElementById('map')); chart.setOption({ series: [{ type: 'map', map: 'china', // 必须和 registerMap 的第一个参数一致 roam: true, // 允许缩放拖动 label: { show: false }, itemStyle: { areaColor: '#e8f0fe', borderColor: '#8ab4f8' }, emphasis: { itemStyle: { areaColor: '#fdd663' } } }] }); </script> </body> </html>逻辑说明:echarts.init只负责创建画布,真正决定画哪张地图的是series.map的值,它去 ECharts 内部的 map 注册表里查。registerMap('china', data)就是往这张表里塞数据。参数上,roam: true开启鼠标缩放平移,大屏常用;label.show控制省名显示,数据密集时关掉更干净;emphasis是 hover 高亮样式,不配的话默认是灰色,视觉上很突兀。
3.2 把业务数据映射到省份颜色
光有底图没意义,真正要的是「哪个省数值高,颜色就深」。这靠series.data和visualMap配合。
chart.setOption({ visualMap: { min: 0, max: 1000, left: 20, bottom: 20, text: ['高', '低'], inRange: { color: ['#e8f0fe', '#8ab4f8', '#1a73e8'] // 由浅到深 }, calculable: true }, series: [{ type: 'map', map: 'china', data: [ { name: '广东省', value: 980 }, { name: '江苏省', value: 760 }, { name: '四川省', value: 430 } ] }] });逻辑说明:visualMap把value映射到inRange.color的渐变色带上,min/max决定映射区间。series.data里的name必须和 GeoJSON 的properties.name逐字一致,差一个「省」字或繁简体,那个省就是默认色。参数上,calculable: true让用户能拖动筛选,做交互大屏时很实用;inRange.color建议三到五档,太多档人眼分不清。
3.3 下钻到市级:数据裁剪与二次注册
省级地图点进去看市级,是数据大屏的常见需求。做法是准备一份市级 GeoJSON,点击省时用chart.on('click')拿到省名,再注册对应市的地图。
chart.on('click', function (params) { if (params.componentType !== 'series') return; const province = params.name; // 例如「广东省」 // 假设 cityDataMap 是 { '广东省': {...市级FeatureCollection} } const cityGeo = cityDataMap[province]; if (!cityGeo) return; echarts.registerMap(province, cityGeo); // 用省名当新 map 名 chart.setOption({ series: [{ type: 'map', map: province, // 切到刚注册的市级地图 data: cityValueMap[province] || [] }] }); });逻辑说明:registerMap的 map 名可以自定义,这里直接用省名,避免命名冲突。params.name来自点击的省份,和 GeoJSON 的name一致才能对上。参数上,市级数据体积比省级大很多,别一次性全加载,按需 fetch 或按需注册。返回上一级时,重新registerMap('china', ...)再 setOption 即可,ECharts 不会自动帮你回退。
4. 避坑与排查:地图数据接入最常见的 5 个翻车现场
4.1 报错 Map china not exists
现象:控制台明确报Map china not exists,地图区域一片空白。原因:registerMap没执行,或执行在setOption之后。JS 版本如果<script>放在echarts.init之后,注册就晚了。解决:把地图数据脚本放在 echarts 之后、业务脚本之前;用 fetch 加载 GeoJSON 时,把setOption写进.then()里,别写在 fetch 外面。
4.2 地图出来了但某个省没颜色
现象:底图正常,业务数据里明明有「内蒙古」,地图上就是不上色。原因:properties.name和series.data.name不一致,常见于「内蒙古自治区」vs「内蒙古」、「广西壮族自治区」vs「广西」。解决:打印 GeoJSON 里所有name值,和你的数据做一次 diff,统一成短名或全名。这个坑我踩过不止一次,血泪经验是:先对齐名字,再谈样式。
4.3 南海诸岛和边界显示不全
现象:地图右下角缺南海诸岛,或九段线没画出来。原因:部分精简版 GeoJSON 为了减小体积裁掉了南海部分。解决:换用完整版数据,或在 option 里单独加一个geo图层补上。合规的地图展示有明确要求,别用来源不明的裁剪数据,这是底线问题,不是技术问题。
4.4 内网部署时 fetch 报跨域
现象:本地file://打开或内网服务器加载.json报 CORS。原因:浏览器对file://和跨域 fetch 有限制。解决:改用 JS 版本直接<script>引入,绕开 fetch;或者把 JSON 放到同源服务器下。内网大屏我一般直接用 JS 版本,省掉这整类问题。
4.5 地图渲染卡顿、拖动掉帧
现象:省级地图还好,一切到市级或全国县级,拖动就卡。原因:坐标点太多,MultiPolygon顶点数上万,SVG 渲染扛不住。解决:切 Canvas 渲染(ECharts 默认就是 canvas,确认没被改成 svg);对精度要求不高的场景,用简化过的边界数据;roam时关掉label和emphasis的复杂样式。参数上,series.map的silent: true能关掉鼠标事件,纯展示时提速明显。
5. 进阶:让中国地图数据在真实大屏里稳住的三个技巧
第一个技巧是数据与底图解耦。别把业务数值写死在 option 里,用dataset或外部变量注入,地图数据只负责「形状」,业务数据只负责「颜色」。这样换数据不用动地图代码,换地图也不用动业务逻辑。我习惯把registerMap封装成一个loadMap(name, url)函数,返回 Promise,业务侧await后再 setOption,加载顺序再也不会乱。
第二个技巧是坐标校验。properties.center是打点和飞线的锚点,但不同来源的数据 center 精度不一,有的偏到隔壁省。上线前用一个小脚本把所有 center 打在地图上肉眼过一遍,偏得离谱的手动修。这个动作花十分钟,能省掉上线后被业务方追问「为什么这个点飘到海里」的后悔药。
第三个技巧是版本与体积管理。全国省级 GeoJSON 通常在几百 KB 到 1MB 出头,市级、县级会成倍增长。别把全国县级数据一次性打进主包,按需加载。判断标准很简单:首屏只需要省级,那就只引省级;下钻时再请求。下面这个加载函数是我常用的骨架。
// 按需加载并注册地图,避免主包体积膨胀 const mapCache = {}; async function loadMap(mapName, url) { if (mapCache[mapName]) return mapCache[mapName]; // 命中缓存直接返回 const res = await fetch(url); if (!res.ok) throw new Error(`地图数据加载失败: ${url}`); const geoJson = await res.json(); echarts.registerMap(mapName, geoJson); mapCache[mapName] = geoJson; // 缓存,避免重复请求 return geoJson; } // 使用:先加载再渲染 loadMap('china', '/geo/china.json').then(() => { chart.setOption({ series: [{ type: 'map', map: 'china' }] }); });逻辑说明:mapCache用对象做内存缓存,同一个地图只 fetch 一次。registerMap放在 fetch 成功之后,保证顺序。参数上,url建议走同源或 CDN,内网就换成 JS 版本。异常分支里throw出去,让调用方能感知失败,别静默吞掉。
最后说个习惯:每次拿到一份新的地图数据,先别写业务,用最小示例把它单独渲染出来,确认边界完整、名字对得上、南海诸岛在。这一步过了,后面所有样式和数据映射才有意义。地图数据这东西,底子不对,上层怎么调都是玄学。希望帮到你。
本文还有配套的精品资源,点击获取