简介:使用 ECharts 制作世界地图时,最大的障碍往往在于找不到结构规整、可直接注册的 GeoJSON 数据。这份资源正是面向前端工程师、数据可视化开发者和经常制作大屏报表的人员,提供了整理好的世界地图 JSON 文件,下载后通过 echarts.registerMap('world', worldJson) 即可加载,省去自行清洗坐标数据的环节。压缩包采用 RAR 格式,整体仅 279KB,只包含一个 JSON 文件;数据体积小巧,却覆盖完整的世界地图地理边界,适合直接放入项目作为地图底稿,也适合在需要内网部署或离线渲染的场景下使用。目前已有 1705 人学习/下载,说明它经受了大量同类项目的实际验证。拿到这份文件后,无论是快速搭建全球业务分布、访客来源统计等数据看板,还是学习 ECharts 的区域样式、标记点与事件绑定,都能直接上手,尤其适合需要快速迭代的演示项目或数据分析原型。 做数据可视化这几年,柱状图、折线图、饼图基本随手就能画,但轮到地图图表,我每次都不敢大意。原因很简单:Echarts本身只是一个绘图引擎,地图的边界数据并不会内置在框架里,你得先准备一份JSON文件——这恰恰是新手最容易卡住的地方。我最近在给一个全球业务项目的销售分布做看板,需要在Echarts里画世界地图并标出主要国家的数据,光是找齐、处理这些GeoJSON文件就花了两天。这里把完整思路和踩过的坑整理一下,包括JSON从哪里拿、怎么和Echarts对接,以及怎么只保留你真正需要的那几个国家。
1. 为什么地图必须靠JSON:GeoJSON到底解决了什么问题
1.1 一张世界地图其实就是一堆多边形
很多人第一次接触地图JSON时会懵:这不就是一个普通JSON文件吗,凭什么能画出地图?其实地图领域的“JSON”一般特指GeoJSON,它是一种专门描述地理空间数据结构的格式。你可以把它理解为:把地球上所有国家的边界,用一串串经纬度坐标点连成闭合的多边形,再给每个多边形附上国家名称、ISO代码等属性。
一个典型的GeoJSON长这样:
{ "type": "FeatureCollection", "features": [ { "type": "Feature", "properties": { "name": "China" }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [121.5, 31.2], [121.8, 31.5], [121.6, 31.8] ] ] ] } } ] }这里的coordinates是经纬度坐标数组,最内层两个数字分别代表经度和纬度。FeatureCollection是整个文件的容器,features数组里每一个元素就是一个国家或地区。Echarts拿到这份数据后,会把每个多边形映射到Canvas或SVG上,再通过填充颜色、描边等方式渲染出一张可交互的地图。
理解了这个结构,后面所有问题都能迎刃而解:地图不显示、区域名对不上、只想保留几个国家,本质上都是在操作这个JSON结构。
1.2 Echarts怎么把GeoJSON变成可视化地图
在Echarts 5.x版本里,使用地图的固定链路是:先调用echarts.registerMap('world', worldJson)注册地图,再在option的geo或series里声明map: 'world'。registerMap做的事情有点像一个“数据登记”:告诉Echarts,后续代码里凡是出现world这个地图名,就用这份GeoJSON去渲染。
得补充一个背景:从Echarts 5.0开始,官方不再随安装包一起提供地图数据。早几年大家用echarts/map/json/world.json这种路径直接引入,现在这条路已经走不通了。所以“自己准备地图JSON文件”不是可选项,而是必选项。这也解释了为什么网上关于Echarts地图的提问永远这么多——数据源这一环节就足以劝退一批人。
2. 世界地图和主要国家的JSON文件从哪里找:三个可靠来源
2.1 阿里云DataV地图选择器
个人最推荐的是阿里云DataV的地图选择器。它是一个在线可视化工具,界面左侧是地图列表,右侧可以直接点击选择你需要的区域,选完就能下载对应的GeoJSON文件。世界地图、中国地图、各个省份、地级市,甚至区县级别都有覆盖。国内访问速度快,数据更新也及时,我近几个项目的地图数据基本都是从这里拿的。
在DataV里可以免费下载单个国家的JSON文件,对于“只要主要国家”这类需求特别方便。下下来之后文件命名通常是world.json或者china.json,直接就能用。如果你对数据时效性要求不高,这个源基本是最省事的。
2.2 GeoJSON.cn和GitHub开源仓库
GeoJSON.cn是一个专门聚合世界各国GeoJSON数据的站点,支持按国家名称搜索,也提供中国省市区的数据。它的优点是数据组织结构清晰,一个页面就是一个国家,下载时不容易搞混。不过它是第三方整理的站点,偶尔会出现坐标精度不足或者部分地区边界信息缺失的情况,使用前建议做一次抽查。
GitHub上也能找到很多持续更新的地图数据仓库,搜索关键词countries geojson或world map geojson就能翻到。仓库数据通常按国家拆分成单独文件,适合写脚本批量拉取。但注意,GitHub仓库质量参差不齐,有的把坐标精度压得很低,有的很久没更新,动手之前先看一下last commit时间和download量,能避开大部分坑。
2.3 Natural Earth和其他专业数据源
如果你的项目对地理精度要求比较高,比如做GIS数据叠加、科研分析,那么Natural Earth这类专业数据集更合适。它提供全球范围、中高精度的矢量数据,覆盖国家、省界、河流、道路等多个图层,可以导出成GeoJSON格式。缺点是需要自己处理导出流程,不像前两个源那样拿来即用。对于大多数业务看板来说,用DataV或GeoJSON.cn就够了,不必杀鸡用牛刀。
这三个来源我整理成一张对照表,方便按需选择:
| 数据源 | 覆盖范围 | 下载方式 | 适用场景 |
|---|---|---|---|
| 阿里云DataV | 世界地图、中国省市 | 在线选择器下载 | 业务可视化报表,直接引入Echarts |
| GeoJSON.cn | 全球国家、中国省市 | 按国家/区域下载 | 快速获取单个国家边界时优先使用 |
| GitHub开源仓库 | 全球国家 | 克隆仓库或下载单文件 | 需要批量处理、脚本化操作时 |
| Natural Earth | 全球多图层 | 导出转换 | GIS精度要求较高的场景 |
3. 把JSON喂给Echarts:从加载到渲染的完整链路
3.1 加载JSON并注册地图
拿到JSON文件只是第一步,关键是让Echarts正确加载它。如果你的项目是纯静态页面,用fetch直接拿文件即可:
fetch('./world.geo.json') .then(res => res.json()) .then(worldJson => { echarts.registerMap('world', worldJson); const chart = echarts.init(document.getElementById('map-container')); chart.setOption({ ... }); });如果是Vue或React项目,建议直接import worldGeo from '@/assets/world.geo.json',把JSON作为模块依赖引入,构建时会自动打包,处理起来更方便。
registerMap的第一参数是自定义地图名,只要和option里使用的map值一致即可,不强制要求叫world。有人习惯叫worldMap或mainCountries,完全没问题。
3.2 geo坐标系和series-map怎么选
Echarts提供两种地图用法:geo组件和series中的map类型。两者的核心区别在于:geo是底层坐标系,适合作为散点图、线图、效果动态线条的地图背景;series-map则是MapSeries,更适合直接展示“每个区域的数值大小”,比如按国家聚合的销售额。
如果你要展示的是一张“国家对应数值”的经典地图热力,用series-map加visualMap最省事。如果还要在地图上叠加交易路线、动态粒子等效果,就需要geo配合series里的scatter、lines、effectScatter。很多项目其实两种方式会混合使用,比如我这次就是geo铺底,再叠一个effectScatter展示各国实时活跃用户,视觉效果比单用series-map好不少。
3.3 一个可直接运行的世界地图示例
下面是一个相对完整的世界地图示例,包含加载JSON、注册地图、配置数据和visualMap的完整逻辑:
fetch('./world.geo.json') .then(res => res.json()) .then(worldJson => { echarts.registerMap('world', worldJson); const chart = echarts.init(document.getElementById('map-container')); chart.setOption({ tooltip: { trigger: 'item' }, visualMap: { type: 'piecewise', pieces: [ { min: 1000, label: '1000 以上' }, { min: 100, max: 999, label: '100-999' }, { min: 1, max: 99, label: '1-99' } ], left: 20, bottom: 20 }, series: [{ type: 'map', map: 'world', roam: true, label: { show: false }, data: [ { name: 'China', value: 1200 }, { name: 'United States of America', value: 300 }, { name: 'Japan', value: 80 } ] }] }); });这里用了piecewise分段式visualMap,相当于把数据按区间分成多个颜色段,让图例更直观。roam: true允许用户拖拽、缩放地图,在大屏上几乎是标配。
4. 真实项目里最容易踩的坑
4.1 区域名对不上,地图死活不亮
这是我最常遇到的问题,没有之一。GeoJSON里每个国家都有properties.name,比如美国在大多数数据源里叫United States of America,中国叫China。而你的业务数据如果写的是“美国”“中国”,或者用ISO代码US、CN,两边就对不上,Echarts不会报任何错误,只是地图上对应区域不显示数据。
解决方案是写一个nameMap映射,把外部数据名转成GeoJSON里的标准名。例如:
const nameMap = { '美国': 'United States of America', '中国': 'China', '日本': 'Japan' };然后在数据预处理阶段统一替换。还有一种更稳的做法:先读取GeoJSON,遍历features取出所有properties.name,生成一份标准名称清单,再让自己的业务数据模型向它靠拢。我第一次做世界地图时没做这一步,结果图上三分之二的国家都没颜色,排查了半天才发现全是名称匹配问题,所以这个坑值得先提。
4.2 图出来了但一片空白,控制台只给一条无头无尾的报错
如果你在控制台看到can't get dom width or height. please check dom.clientWidth之类的提示,多半是初始化时机不对——map-container这个DOM还没有宽度或高度,echarts.init就已经执行了。常见场景是组件在v-if条件渲染、弹窗、Tab页签里初始化地图,容器初始是隐藏的,宽度高度为0。
解决办法是等容器显示后再初始化,或者在容器尺寸变化后调用chart.resize()。弹窗里放地图时,我一般会写一个nextTick再init,避免拿到空尺寸。还有个别情况是display:none导致,换成visibility:hidden保留占位也可以。
4.3 移动端无法点击,事件像被吞掉一样
地图在移动端点击无响应,通常会怀疑是Echarts问题,其实大部分是层级遮挡或zIndex问题。地图容器里如果还放了其他悬浮元素,或某个图层的z-index盖住了地图区域,触摸事件就传不到Canvas上。检查一下地图容器内是否有额外DOM元素,把遮挡元素的z-index调低,或者在容器的style里补一个touch-action: manipulation,一般都能解决。
另外移动端初始化时,Echarts默认会响应mousedown/mousemove/mouseup事件,某些Android浏览器对touch事件支持不彻底,会出现拖动缩放时偶尔“卡住”的情况。这时候可以监听chart.getZr()的mousedown事件来判断,而不是依赖内置的click事件。我踩过一轮后,现在移动端地图交互基本都会给roam加一个节流,避免手势识别冲突。
4.4 高纬度国家变形和文件体积失控
默认世界地图的投影方式会直接使用经纬度坐标,导致俄罗斯、加拿大这些高纬度地区在视觉上比实际大很多。如果只是业务看板,这种变形可以接受;如果追求更正的投影效果,Echarts 5.3以上的版本支持geo.projection配置,配合d3-geo库可以实现墨卡托等常用投影。不过这引入的额外依赖和算力消耗不小,需要慎重评估。
文件体积问题更实际。世界地图GeoJSON动辄1-3MB,如果在弱网环境加载,地图组件会出现长时间白屏。优化方式有两个:一是用mapshaper这类工具对GeoJSON做几何简化,只保留边界精度的80%左右,视觉影响很小;二是直接过滤掉用不到的国家,这也是我每次都做的一步,放到下一节细说。
5. 只想要主要国家怎么办:按需裁剪GeoJSON
5.1 为什么要自己裁剪
项目场景通常只需要“中国、美国、日本、英国、德国、法国”这几个主要国家,把整个世界地图都加载进来是很大的浪费。一是文件体积大,二是Echarts渲染时仍要处理所有国家边界,拖慢首屏渲染,三是数据处理时多了一堆无关区域,容易误触。所以“按需裁剪GeoJSON”几乎是世界地图项目里的必备操作。
5.2 用Python脚本按国家名过滤
裁剪GeoJSON的原理非常简单:读取features数组,只保留我们关心的properties.name匹配项,再写回新文件。用Python处理最方便,不需要安装额外库:
import json def filter_countries(src_path, dest_path, keep_names): with open(src_path, 'r', encoding='utf-8') as f: data = json.load(f) features = data.get('features', []) filtered = [ f for f in features if f.get('properties', {}).get('name') in keep_names ] data['features'] = filtered with open(dest_path, 'w', encoding='utf-8') as f: json.dump(data, f, ensure_ascii=False) if __name__ == '__main__': filter_countries( 'world.geo.json', 'world-main.geo.json', {'China', 'United States of America', 'Japan', 'United Kingdom'} )运行完会得到一个新的world-main.geo.json,里面只有你留下的国家,体积往往能降到原文件的十分之一。记得先打开源GeoJSON,确认目标国家的properties.name写法,再往keep_names里填。
5.3 裁剪后的命名对齐还是得做
裁剪之后,还要再做一遍命名对齐。因为我前面提过,不同数据源里英国可能叫United Kingdom,也可能叫UK,甚至有些老数据源里叫England。最保险的方式是直接查看裁剪后JSON里的properties.name,生成一个稳定的名称字典,让业务数据的名称和它完全一致。
做完裁剪和命名对齐,世界地图项目的地图部分基本就稳定了。后面再往上叠图表、做下钻、调样式,都只是锦上添花。
最后再分享一个小技巧:如果你需要经常重复“下载地图JSON -> 裁剪 -> 接Echarts”这套流程,可以把你常用的国家清单和Python脚本存成一个模板,下次新项目直接改两个参数就能跑。我在实际项目中就是这么做的,省掉了不少重复劳动,也减少了每次手动操作带来的命名错误和文件缺失。做地图可视化,数据准备阶段花的时间永远值得,前期理顺了,后面绘图阶段就能把精力放在业务表达上。
本文还有配套的精品资源,点击获取