ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

ECharts离线地图china.js下载与注册全指南

ECharts离线地图china.js下载与注册全指南

简介:这份资源提供ECharts地图功能所需的核心文件china.js,面向使用ECharts进行Web数据可视化的前端开发者与数据分析人员,解决新版ECharts因版权原因不再内置中国地图数据、导致无法直接渲染中国地图的问题。压缩包为rar格式,内含1个js文件,体积约43KB,即包含中国各省份及地区经纬度坐标与边界信息的地理数据文件,引入后即可配合ECharts实例的geo与series配置展示中国地图。资源描述中梳理了下载、引入、配置地图实例、加载区域数据、调整样式与交互等完整思路,并提醒注意地图数据的版权合规使用,对需要快速补齐地图能力的项目有直接参考价值。目前已有3243人学习下载,适合希望在新版ECharts中继续使用中国地图的开发者参考取用。

1. echarts地图china.js下载:一个被低估的离线地图方案

做数据大屏的同行大概率都遇到过这个场景:内网环境部署可视化项目,地图组件加载到一半卡住,控制台报 404,原因就是 echarts 默认的地图数据依赖在线 CDN。这时候china.js这个文件就成了救命稻草——它是把中国地图的 GeoJSON 数据注册进 echarts 的一个脚本文件,引入后echarts.registerMap('china', ...)就能在完全离线的环境下渲染地图。很多人第一次搜「echarts地图china.js下载」,其实真正想要的不是文件本身,而是搞清楚这个文件从哪来、怎么用、为什么官网找不到了。这篇笔记就按这个思路,把下载、注册、配置、排错整条链路讲透,适合正在做内网大屏、需要地图下钻、又不想依赖外部接口的前端和数据工程师。

2. china.js 到底是什么:从 GeoJSON 到 registerMap 的完整链路

2.1 为什么 echarts 5 之后不再内置地图数据

echarts 在 4.x 时代,echarts/map/js/china.js是随包发布的,直接import 'echarts/map/js/china'就能用。但从 5.0 开始,官方把地图数据从主包里剥离了,原因有两个:一是地图数据的版权和合规问题需要单独处理,二是主包体积太大,地图数据对很多项目来说是冗余的。这个变化导致大量老教程失效,新手照着 4.x 的写法在 5.x 上跑,必然报Map china not exists。

常见做法是去 echarts 官方示例仓库或者一些镜像站找china.js,但版本参差不齐,有的还是 2018 年的老数据,省份边界和现在对不上。我一般会先确认自己需要的是「全国地图」还是「省市下钻」,前者一个china.js就够,后者需要一整套省市 JSON。

2.2 GeoJSON、registerMap 和 series-map 三者的关系

理解这条链路,后面所有配置都不会迷路:

  • GeoJSON:一种描述地理边界的 JSON 格式,包含features数组,每个 feature 有properties.name(省份名)和geometry.coordinates(边界坐标)。
  • registerMap:echarts 提供的注册接口,echarts.registerMap('china', geoJson),第一个参数是地图名,第二个是 GeoJSON 对象。注册后这个地图名就能在series-map或geo组件里引用。
  • series-map:真正渲染地图的系列类型,type: 'map',通过map: 'china'关联已注册的地图。

china.js的本质就是一段执行了registerMap的脚本,它内部把 GeoJSON 数据和一个自执行函数打包在一起。所以你也可以不用china.js,直接下载china.json,自己调registerMap,效果完全一样,而且更灵活。

2.3 三种获取方式对比:npm 包、JSON 文件、自建脚本

方式来源优点缺点适用场景
npm 包某些第三方 map 数据包安装方便,版本可锁包质量参差,可能停维护快速原型
纯 JSON 文件公开 GeoJSON 数据源数据透明,可裁剪需自己写注册逻辑生产项目
自建 china.js用 JSON 转脚本一次引入,全局可用需构建步骤多页面复用

我一般推荐生产项目用第二种,把china.json放在public或assets目录,在入口文件里注册一次。这样数据来源清晰,后续要换数据或裁剪省份也方便。下面给出具体操作。

2.4 用 Node 脚本把 GeoJSON 转成可引入的 china.js

假设你已经拿到了china.json,想把它转成china.js,可以写一个简单的构建脚本:

// build-china-map.js const fs = require('fs'); const path = require('path'); // 读取原始 GeoJSON 数据 const geoJson = JSON.parse( fs.readFileSync(path.resolve(__dirname, 'china.json'), 'utf-8') ); // 生成注册脚本,UMD 风格,兼容 script 标签和模块引入 const content = `(function (root, factory) { if (typeof define === 'function' && define.amd) { define(['echarts'], factory); } else if (typeof exports === 'object') { factory(require('echarts')); } else { factory(root.echarts); } }(this, function (echarts) { var geoJson = ${JSON.stringify(geoJson)}; echarts.registerMap('china', geoJson); }));`; fs.writeFileSync(path.resolve(__dirname, 'china.js'), content, 'utf-8'); console.log('china.js 生成完成,大小:', (content.length / 1024).toFixed(1), 'KB');

这段脚本的逻辑很直白:读 JSON,把 JSON 字符串塞进一个 UMD 包装里,调用registerMap。参数说明:JSON.stringify(geoJson)会把对象序列化成字符串,注意如果 GeoJSON 里有undefined会被丢掉,但标准 GeoJSON 不会有这个问题。生成后的china.js可以直接用<script>引入,也可以在 webpack/vite 项目里import './china.js'。

提示:如果 GeoJSON 文件超过 2MB,建议做精度简化,否则打包体积会很难看。常见做法是用 mapshaper 这类工具先压缩边界点。

3. 在项目里跑通地图:从注册到渲染的最小可复现步骤

3.1 本地引入 china.js 并注册地图

最直接的方式,在 HTML 里先引 echarts,再引china.js:

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>离线地图示例</title> <!-- 引入 echarts,本地文件或 CDN 均可 --> <script src="./echarts.min.js"></script> <!-- 引入生成的 china.js,内部会自动 registerMap --> <script src="./china.js"></script> </head> <body> <div id="map" style="width: 800px; height: 600px;"></div> <script> // 初始化实例,注意这里不需要再手动 registerMap var chart = echarts.init(document.getElementById('map')); var option = { series: [{ type: 'map', map: 'china', // 对应 registerMap 的第一个参数 roam: true, // 允许缩放和拖拽 label: { show: true, fontSize: 10 }, emphasis: { label: { show: true } } }] }; chart.setOption(option); </script> </body> </html>

逻辑说明:china.js在加载时已经执行了registerMap('china', geoJson),所以option里直接写map: 'china'即可。参数说明:roam: true开启鼠标缩放和平移,大屏场景建议开启;label.show控制省份名称显示,数据量大时可以关掉提升性能。

3.2 在 Vue/React 项目里按需注册

现代前端项目一般不会用 script 标签,而是模块化引入。以 Vue 为例:

// main.js 或单独的 map-setup.js import * as echarts from 'echarts'; import chinaGeoJson from './assets/china.json'; // 注册地图,只执行一次 echarts.registerMap('china', chinaGeoJson); // 组件内使用 export default { mounted() { const chart = echarts.init(this.$refs.mapEl); chart.setOption({ tooltip: { trigger: 'item' }, visualMap: { min: 0, max: 1000, left: 20, bottom: 20, text: ['高', '低'], calculable: true, inRange: { color: ['#e0f3f8', '#4575b4'] } }, series: [{ type: 'map', map: 'china', data: [ { name: '广东', value: 800 }, { name: '浙江', value: 600 } ] }] }); } };

这里的关键是registerMap只执行一次,放在入口文件或单独的初始化模块里。参数说明:visualMap的inRange.color控制数据映射的颜色区间,min/max要和你的数据范围匹配,否则颜色会失真。

3.3 数据绑定:series-map 的 data 格式与名称匹配规则

地图渲染最常见的翻车点就是数据不显示,十有八九是name对不上。series-map的data格式是[{ name: '省份名', value: 数值 }],其中name必须和 GeoJSON 里properties.name完全一致。

// 正确写法 data: [ { name: '北京', value: 120 }, { name: '内蒙古', value: 45 } ] // 错误写法:用了简称或全称不一致 data: [ { name: '北京市', value: 120 }, // GeoJSON 里可能是「北京」 { name: '内蒙', value: 45 } // 简称对不上 ]

排查方法:在控制台打印echarts.getMap('china').geoJson.features.map(f => f.properties.name),看看实际有哪些名称,然后对齐。这个坑我踩过不止一次,尤其是「新疆」「西藏」「内蒙古」这些名称,不同数据源写法不一样。

3.4 用 geo 组件做省市下钻的注册流程

下钻的本质是点击省份后,注册该省的地图并切换map值:

chart.on('click', function (params) { if (params.componentType === 'series' && params.seriesType === 'map') { const provinceName = params.name; // 假设省市 JSON 已按名称存放在 mapData 对象里 const provinceJson = mapData[provinceName]; if (provinceJson) { echarts.registerMap(provinceName, provinceJson); chart.setOption({ series: [{ type: 'map', map: provinceName, data: provinceData[provinceName] || [] }] }); } } });

逻辑说明:点击事件拿到省份名,从预加载的mapData里取对应 GeoJSON,注册后重新setOption。参数说明:mapData建议按需加载,不要一次性把所有省份 JSON 都打进主包,否则首屏体积会爆炸。常见做法是动态import()或放在public目录用 fetch 拉取。

4. 避坑指南:china.js 下载和使用中的 5 个高频问题

4.1 报错 Map china not exists:注册时机和顺序问题

现象:控制台报Map china not exists,地图区域空白。

原因:registerMap没有执行,或者执行在setOption之后。模块化项目里,如果china.js是异步加载的,很容易出现时序问题。

解决:确保registerMap在setOption之前完成。可以在入口文件同步引入,或者在异步加载后用await等待注册完成再初始化图表。检查方式:在setOption前打印echarts.getMap('china'),如果是undefined就是没注册成功。

4.2 地图边界错位或省份缺失:数据版本太老

现象:某些省份边界明显不对,或者少了几个省。

原因:下载到的china.js是多年前的老数据,行政区划调整后没有更新。

解决:换用较新的 GeoJSON 数据源,重新生成china.js。判断数据新旧可以看 feature 数量,全国地图一般在 34 个左右。如果只有 30 个出头,大概率是旧版。

4.3 打包体积暴涨:GeoJSON 精度过高

现象:引入china.js后,打包体积增加好几 MB,首屏加载变慢。

原因:原始 GeoJSON 的坐标点非常密集,精度越高体积越大。

解决:用 mapshaper 做简化,命令示例:

# 安装 mapshaper 后执行,保留 10% 的坐标点 mapshaper china.json -simplify 10% -o format=geojson china-simple.json

参数说明:-simplify 10%表示保留 10% 的顶点,视觉上几乎看不出差别,但体积能降一个数量级。生产环境建议简化到 5%~15% 之间,根据大屏分辨率调整。

4.4 名称匹配失败:数据里的 name 和地图对不上

现象:data里明明有值,地图上就是不上色。

原因:name字段和 GeoJSON 的properties.name不一致,常见于简称/全称、空格、特殊字符。

解决:统一用 GeoJSON 里的名称作为基准,在数据侧做映射。可以写一个映射表:

const nameMap = { '北京市': '北京', '内蒙古自治区': '内蒙古', '广西壮族自治区': '广西' }; // 转换数据 const normalized = rawData.map(item => ({ name: nameMap[item.name] || item.name, value: item.value }));

4.5 内网部署时字体和 tooltip 异常

现象:内网环境下地图能显示,但 tooltip 里的中文变成方块,或者样式丢失。

原因:echarts 默认 tooltip 用的是浏览器字体,内网机器如果缺少中文字体就会显示异常;另外某些 CDN 上的主题文件在内网加载不到。

解决:在 CSS 里显式指定中文字体栈,font-family: "Microsoft YaHei", "PingFang SC", sans-serif;。主题文件下载到本地引入,不要依赖在线地址。这个坑在内网大屏项目里非常典型,提前处理能省很多调试时间。

5. 进阶技巧:让离线地图更接近生产可用

5.1 用 geoJSON 裁剪只保留业务需要的省份

很多业务只需要展示几个省,没必要加载全国数据。可以用脚本过滤 features:

const fs = require('fs'); const geoJson = JSON.parse(fs.readFileSync('china.json', 'utf-8')); const keep = ['广东', '浙江', '江苏', '上海']; // 过滤 features,只保留目标省份 geoJson.features = geoJson.features.filter(f => keep.includes(f.properties.name) ); fs.writeFileSync('china-part.json', JSON.stringify(geoJson)); console.log('裁剪后 feature 数量:', geoJson.features.length);

逻辑说明:filter按properties.name筛选,保留目标省份。参数说明:keep数组里的名称必须和 GeoJSON 一致。裁剪后体积能降到原来的几分之一,对首屏性能帮助明显。

5.2 地图与散点图、飞线的组合配置

纯地图往往不够,生产大屏通常要叠加散点和飞线:

option = { geo: { map: 'china', roam: true, itemStyle: { areaColor: '#0b1c3a', borderColor: '#1e90ff' } }, series: [ { type: 'effectScatter', // 带涟漪效果的散点 coordinateSystem: 'geo', data: [ { name: '广州', value: [113.27, 23.13, 100] } ], symbolSize: 10 }, { type: 'lines', // 飞线 coordinateSystem: 'geo', data: [ { coords: [[113.27, 23.13], [121.47, 31.23]] } ], lineStyle: { color: '#ffcc00', width: 1, curveness: 0.2 } } ] };

参数说明:coordinateSystem: 'geo'表示系列使用 geo 组件的坐标系,所以地图由geo渲染而不是series-map。curveness控制飞线弯曲程度,0 是直线,0.2 左右比较自然。注意geo和series-map不要同时用,否则会渲染两层地图。

5.3 验证地图数据是否正确的三个检查点

上线前我一般会做三个检查:第一,打印 feature 数量,全国地图应该在 34 个左右;第二,随机抽三个省份,用echarts.getMap('china').geoJson确认边界坐标存在;第三,把data里所有name和 GeoJSON 名称做一次交集比对,确保没有对不上的。这三个检查能拦住 90% 的地图显示问题。

5.4 一个我踩过的坑:registerMap 重复注册导致内存泄漏

最后说一个血泪经验。早期做多页面应用时,我在每个页面都引入了china.js,结果registerMap被重复执行,地图数据在内存里存了多份,页面切换几次后内存明显上涨。后来改成在入口文件注册一次,其他页面只引用地图名,问题就消失了。如果你用的是 SPA,这个问题不明显;但如果是多页应用或者微前端,一定要把注册逻辑收敛到一处。这个习惯我保持到现在,每次做地图项目第一件事就是确认registerMap的调用位置。

希望帮到你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进