
简介一套面向ECharts可视化开发的世界地图GeoJSON数据包共包含3443个文件其中3442个为各国区域json地图文件另附1个word.js辅助脚本整体大小仅2.59MB。数据覆盖世界主要国家与地区以标准GeoJSON格式存储边界坐标可直接加载到ECharts的geo或map系列中用于绘制世界地图、按指标填充配色、绑定点击或悬停事件也便于结合大数据分析展示人口、经济等多维信息。压缩包内还提供了各洲及国别json文件方便按需单独引入减少页面加载负担。目前已有383人学习下载适合前端开发者、数据分析师及地理可视化爱好者快速搭建交互式地图应用省去自行爬取和格式转换的繁琐流程。 最近又在群里看到有人拿着 ECharts 4 时代的代码问为什么map: world不显示了这个问题基本每周都会出现一次。ECharts 从 5.0 开始不再内置任何地图数据包括世界地图数据所以你想用世界地图数据配合 ECharts 做全球业务分布、航线轨迹可视化第一步不是急着写 option而是先准备一张结构正确、坐标合规的 GeoJSON 地图再用registerMap注册进去。这篇文章把我从找数据、验数据到出图、叠加飞线和散点、再到 Vue2 工程化接入的完整流程写一遍重点标注那些没人提醒但一定会踩的坑。新手照着能落地老手也能查漏补缺。1. 为什么 ECharts 5 的 world 地图“消失”了以及现在的地图数据该从哪找1.1 地图数据本来就是 ECharts 之外的事ECharts 本质上是图形渲染引擎地图只是它支持的一种特殊坐标系类型。在 ECharts 4 及以前官方为了方便把世界地图和部分中国地图数据一起打包进框架所以map: world一行就能用。但从 5.0 开始为了控制包体积也为了避免地图数据的更新跟不上现实变化官方把内置地图全部剥离GeoJSON 数据一律由使用者自己准备后再注册。这个设计本身没毛病坏就坏在大量老教程还在用旧写法新手照抄自然白屏。现在标准做法是fetch(./world.json) .then(res res.json()) .then(geoJson { echarts.registerMap(world, geoJson); });你只要记住一句话地图数据不显示先别怀疑 option99% 是 GeoJSON 没有成功注册或者注册名和map: world对不上。这个排查逻辑能帮你节省大量时间。1.2 世界地图 GeoJSON 的几个靠谱来源我在不同项目里试过很多数据源真正值得长期使用的就这几个数据来源获取方式适用场景注意事项ECharts 官方示例仓库 world.jsonecharts-examples 仓库的 data/asset/geo 目录下快速验证 Demo、开发调试国家名以英文为主精度约为 110mNatural Earthnaturalearthdata.com 下载 shapefile 后转 GeoJSON生产级地图底图数据公开有 110m / 50m / 10m 三档精度MapShapermapshaper.org 在线简化压缩 GeoJSON 体积任何来源的数据都可以用它减重DataV.GeoAtlas阿里云 DataV 的地图选择器中国及省市县级地图做全国地图更方便世界地图场景较少选型建议很简单快速做 Demo直接用官方 world.json正式项目从 Natural Earth 的 110m 或 50m 精度开始转成 GeoJSON 后按你的业务需要整理国家名再用 MapShaper 压缩体积。不要一上来就下载 10m 精度的世界数据一个 10m 的世界 GeoJSON 动辄几 MB 甚至十几 MB浏览器解析起来非常吃力后面会专门说这件事。Natural Earth 下载下来的是 shapefile需要转格式。电脑上装了 GDAL 的话一条命令搞定ogr2ogr -f GeoJSON world.geojson ne_110m_admin_0_countries.shp如果不想折腾命令行就用 QGIS 打开 shapefile 后右键图层导出 GeoJSON效果一样。2. 拿到 GeoJSON 后先做三件事结构检查、坐标确认、名称对齐2.1 FeatureCollection 才是 ECharts 能用的结构很多从网上下载的“世界地图数据”其实是另一种老格式比如{ China: [[x, y], ...] }或者是一个 JS 文件直接把数组赋值给全局变量。这些 ECharts 5 都不认。能被registerMap接受的标准结构长这样{ type: FeatureCollection, features: [ { type: Feature, properties: { name: China }, geometry: { type: MultiPolygon, coordinates: [ [ [ [117.4, 49.2], [120.1, 48.3] ] ] ] } } ] }判断标准就一条最外层必须是FeatureCollection内部有features数组每个 feature 里geometry.type是Polygon或MultiPolygon。拿到数据后先不要急着写页面用 geojson.io 打开看一眼既能确认边界是否正常也能顺手检查 properties 里有哪些字段。这一步花两分钟能省后面两个小时的排错时间。2.2 坐标系和经纬度散点飘到海里去的大部分原因GeoJSON 默认坐标系是 WGS84 经纬度ECharts 地图系列的内部处理也是按经纬度来算的。所以你在图上叠加的所有点、线、飞线坐标都必须用[经度, 纬度]的顺序。判断坐标有没有写反有个土办法中国国境的大致范围是经度 73 到 135纬度 18 到 53美国本土经度在 -125 到 -70 之间。如果你的中国城市坐标看起来像[30, 120]那大概率是把纬度和经度写反了。另外提醒一句如果业务要结合高德地图绘制真实行驶路线轨迹注意高德返回的坐标是基于 GCJ-02 的加密偏移坐标而你手里的世界地图 GeoJSON 是 WGS84两套坐标不统一就直接叠上去点位会整体偏移缩放到城市级时偏差非常明显。先做坐标转换再把路径点填进 ECharts 的 lines 系列才不会出现“路线和图对不上”的诡异现象。2.3 properties.name 是所有匹配的钥匙地图上每个国家的名称、提示框内容甚至飞线fromName/toName的坐标解析都依赖 GeoJSON 里features[].properties.name。ECharts 渲染时会把每个 feature 的 name 当作唯一标识用来和 series 里的 data 项做匹配。如果你的数据源是英文名而业务数据是国家中文名图例和 visualMap 都会匹配不上图表里要么一片空白要么全是 NAN。这个问题非常隐蔽因为地图轮廓照样能画出来只是没有颜色变化很多人会误以为是 visualMap 配置错了。正确做法是提前确认地图 data 里的 name 和 GeoJSON properties.name 完全一致。不一致的用第 3 章提到的两种方式统一。3. 把世界地图数据接入 ECharts从 registerMap 到首屏出图3.1 最简接入流程先注册再 setOption这里给一个完整可运行的最小示例div idchart stylewidth: 100%; height: 600px;/divconst chart echarts.init(document.getElementById(chart)); fetch(./world.json) .then(res res.json()) .then(geoJson { echarts.registerMap(world, geoJson); chart.setOption({ series: [ { type: map, map: world, roam: true, label: { show: true, fontSize: 10 }, data: [ { name: China, value: 1439 }, { name: United States of America, value: 331 } ] } ] }); });两个细节值得说清楚。第一chart.setOption必须在registerMap之后调用否则 ECharts 找不到名为 world 的地图控制台会提示地图还未注册。第二如果是在本地file://协议下直接打开 HTMLfetch会被浏览器拦截建议起一个本地静态服务或者把 JSON 作为对象直接引入import worldGeoJson from ./world.json; echarts.registerMap(world, worldGeoJson);在 Webpack、Vite 这类构建工具项目里第二种方式更常见还能享受打包缓存和压缩。3.2 让国家颜色随数据变化map 系列 visualMap只有data还不够要让国家颜色随数值变化必须配 visualMapchart.setOption({ visualMap: { min: 0, max: 2000, left: 20, bottom: 20, text: [高, 低], inRange: { color: [#e0f3f8, #abd9e9, #2c7bb6] }, seriesIndex: 0 }, series: [ { type: map, map: world, name: GDP 指标, itemStyle: { areaColor: #0f1326 }, data: [ { name: China, value: 1439 }, { name: United States of America, value: 331 } ] } ] });visualMap 不生效最常见的原因有两个一是 data 里的 value 写成了字符串比如value: 100ECharts 不会帮你自动转换匹配不上数值区间二是没有指定seriesIndex在有多个系列时 visualMap 的作用范围混乱。建议给 series 加上namevisualMap 里用seriesIndex: 0精确限定别偷懒。itemStyle.areaColor填的是默认填充色能让没有匹配到 data 的国家保持暗色和热力区形成对比视觉层次会好很多。3.3 中文国家名nameMap 和直接改数据的取舍世界地图数据大多是英文国家名但国内业务的数据表里存的几乎都是中文。统一命名有两种路子。方式一在 series 里配 nameMap不改原始数据series: [ { type: map, map: world, nameMap: { China: 中国, United States of America: 美国 } } ]方式二直接改 GeoJSON 里每个 feature 的 properties.name再存成中文版 world.jsonconst nameMap { China: 中国, United States of America: 美国 }; worldGeoJson.features.forEach(feature { if (nameMap[feature.properties.name]) { feature.properties.name nameMap[feature.properties.name]; } });我的经验是nameMap 适合临时演示不改原文件但映射表一旦超过几十个就容易漏。正式项目最好在构建阶段把 world.json 统一转成中文名版本提交到代码仓库后续所有图表直接写中文名开发时心智负担最小。转好之后用 geojson.io 再打开检查一遍确保没有因为批量替换把不该改的字段改坏。4. 世界地图上的进阶玩法多条路线轨迹、全球散点与滑动缩放4.1 用 lines 系列画多条路线轨迹最近很多人问“地图结合高德绘制多条路线轨迹”本质就是把路线坐标点填进 ECharts 的 lines 系列。做一个全球航线图效果大概是这样的series: [ { type: lines, coordinateSystem: geo, zlevel: 2, effect: { show: true, period: 4, trailLength: 0.3, symbol: arrow, symbolSize: 6 }, lineStyle: { width: 1, opacity: 0.6, color: #ffd666 }, data: [ { coords: [[116.4, 39.9], [121.47, 31.23]] }, { coords: [[121.47, 31.23], [-74.006, 40.7128]] } ] } ]这里明确一点lines 系列只会把你给出的坐标点按顺序连起来不会自动生成弯曲的航线。如果想让路线带弧度你需要自己在两个城市之间按球面大圆插值生成一串中间坐标再整体填进 coords。最笨也最可控的做法是把两个城市之间的经纬度做线性插值然后对经度做一点偏移修正看起来就是弧线了。如果结合高德路线规划接口把返回的坐标点数组经过坐标转换后填进 coords就能画出真实道路轨迹。每条路线是一个 data 项多填几条就是多路线轨迹。trailLength越小流光尾巴越短period控制一圈的耗时。节奏感和业务要求的观感有关建议上线前多调几次。4.2 全球散点effectScatter 叠加到地图上散点是在地图上标注城市、港口、仓库位置的常用方式series: [ { type: effectScatter, coordinateSystem: geo, data: [ { name: 北京, value: [116.4, 39.9, 100] }, { name: 纽约, value: [-74.006, 40.7128, 80] } ], symbolSize: function (val) { return val[2] / 10; }, rippleEffect: { brushType: stroke } } ]注意 value 数组的前两位是经纬度第三位开始才是业务指标。symbolSize 用函数动态计算能实现“数值越大点越大”的效果。如果散点没有出现先看 coordinateSystem 是不是写成了geo再看经纬度是否写反这两条占散点问题原因的八成。4.3 地图缩放滑动 vs 坐标轴放大别把 dataZoom 用在 map 上热词里经常有“echart 坐标轴放大缩小滑动”那一般指的是直角坐标系里的 dataZoom 组件。地图上要实现同样的效果用的是roam两者完全是两套机制series: [ { type: map, map: world, roam: true, scaleLimit: { min: 1, max: 5 } } ]roam: true允许鼠标滚轮缩放和拖拽scaleLimit控制缩放范围避免用户不小心把地图放大到找不着北。dataZoom 是针对 xAxis / yAxis 的对 map 系列没有任何作用给 map 配 dataZoom 是无效配置这是很多人踩过的坑。如果你需要根据当前缩放状态联动其他图表可以监听georoam事件拿到当前的缩放级别和中心点再处理联动逻辑。地图自身的缩放交互做到这一步基本就够真实业务用了。5. 真实项目中的高频坑性能优化、Vue2 集成与数据合规5.1 GeoJSON 过大导致页面卡顿世界地图数据的体积差异非常大。110m 精度的 world.json 通常在 100KB 到 200KB 之间50m 可能到 1MB 左右10m 轻松超过 10MB。浏览器要解析、要构建地图投影数据越大渲染越卡移动端尤其明显。生产项目里我建议从 110m 或 50m 起步再用 MapShaper 做一次简化。操作路径是上传 GeoJSON 到 mapshaper.org在控制台执行simplify保留 0.1% 到 1% 的顶点然后导出 GeoJSON。实际操作时保留多少要看你对边界细节的要求原则是轮廓看起来不畸形文件越小越好。简化完记得用 geojson.io 复查一遍重点看岛屿和国家边界有没有被简化掉。另外前端部署时给 world.json 开一下 gzip 压缩传输体积能再降不少。如果地图是静态不变的还可以考虑直接打包进 JS 里减少一次网络请求。5.2 标签重叠与国家名显示不全世界地图上国家多默认把所有 label 都显示出来必然重叠。ECharts 5 提供了 labelLayout 配置可以自动隐藏重叠标签series: [ { type: map, map: world, label: { show: true, fontSize: 10 }, labelLayout: { hideOverlap: true } } ]如果你的 ECharts 版本比较老没有labelLayout就只能手动控制 label比如只给重点国家显示标签或者用 formatter 根据数据值决定是否显示。标签和视觉映射叠加在一起时优先保证重点区域的可见性次要国家的标签隐藏掉不影响大局。5.3 在 Vue2 项目里接入的注意点Vue2 项目接入 ECharts 的常规流程是先安装依赖npm install echarts然后在需要地图的组件里引入并注册地图template div refchart styleheight: 600px;/div /template script import * as echarts from echarts; export default { data() { return { chart: null }; }, mounted() { this.chart echarts.init(this.$refs.chart); this.loadWorldMap(); }, methods: { async loadWorldMap() { const res await fetch(/map/world.json); const geoJson await res.json(); echarts.registerMap(world, geoJson); this.chart.setOption({ series: [ { type: map, map: world } ] }); } }, beforeDestroy() { this.chart this.chart.dispose(); } }; /script这种写法有两个关键点。第一fetch 是异步的不能指望 mounted 里同步 setOption 就有数据必须先拿到 GeoJSON 再注册再渲染顺序错了就是白图。第二beforeDestroy里一定要调用dispose()释放实例否则路由来回切换会导致内存泄漏页面上会出现“Cannot read properties of undefined”之类的诡异报错。如果你用的是 vue-echarts 或者 lime-ui 这类封装好的组件库核心原理也一样组件只是把 echarts 实例的生命周期帮你管好了地图数据依然需要自己注册。遇到地图不显示先绕开组件库用原生方式验证一遍 registerMap 是否成功再回来查组件配置。5.4 数据合规提醒最后必须提醒一句地图数据不是随便找个开源文件就能上线的。涉及中国国界、南海诸岛等区域展示时一定要确保使用合法合规、有审图依据的数据源不同来源的 GeoJSON 在边界绘制上存在明显差异正式上线前务必自查。做世界地图时如果业务会切换到中国区域要准备好切换到合规数据。地图数据这种基础资产源文件、处理脚本、最终成品都应该用版本管理管起来一旦出问题能回溯别让一个数据文件成为整个项目的隐患。最后再分享一个小技巧。我在本地会维护两份地图数据一份低精度 110m 的英文版用于日常开发调试页面秒开一份按业务需求处理好的精简中文版用于生产上线。开发环境和生产环境的数据分开上线前再固定生产数据的版本号避免哪天数据源悄悄更新导致地图显示突然变化。地图数据看着不起眼但版本一旦混乱排查起来比业务 bug 还难受把它当成正经前端资产来管理后面所有地图相关需求都会顺很多。本文还有配套的精品资源点击获取