
简介一份汇集世界地图与主要国家边界数据的 GeoJSON 地图资源包面向需要在地图可视化中快速使用国界数据的开发者适配 ECharts、D3.js、Mapbox 等主流图表与地理信息库尤其适合制作数据大屏、区域统计和地图下钻功能。资源内共 25 个文件其中 23 个为 JSON 格式的地理边界数据覆盖世界地图以及美国、俄罗斯、日本、印度、澳大利亚、巴西、加拿大、法国、德国、挪威、南非、新加坡等多个主要国家另有 2 个 MHT 格式的 D3.js 学习参考文档用来辅助理解地图数据加载、投影与交互实现。压缩包整体约 11.31MB文件命名直观清晰按国家名即可快速找到目标数据。由于原始数据精度较高、体积偏大作者建议使用 mapshaper.org 在线工具按需简化降低渲染开销。当前已有 6263 人下载学习可帮助节省逐个收集数据与格式转换的时间所获文件可直接接入前端项目。1. 世界地图 GeoJSON可视化项目的第一步选对底图就成功了一半接手过一个跨平台系统的地图模块数据都准备好了结果地图死活渲不出来。排查半天问题出在底图 GeoJSON 上——文件是网上下载的坐标系不对部分国家边界还是二十年前的老版本。从那以后我养成了习惯拿到地图系列资源的第一件事不是急着画图而是先验证 GeoJSON 本身的精度、边界和坐标系。这份「世界地图和主要国家的 JSONGeoJson」资源包解决的就是这个前置问题——它把世界地图和主要国家的地图边界数据整理成了标准 GeoJSON 格式供 ECharts、Leaflet、D3 等前端地图库直接加载免去自己造轮子、到处找数据的麻烦。适合三类人做销售数据区域分布的前端工程师做地理信息系统的数据分析师以及所有被地图数据源折磨过的可视化开发者。它不包含任何复杂依赖就是一个可以拿来即用的地图数据底座。2. 认识 GeoJSON 地图数据结构、选型与预处理2.1 读懂 GeoJSON 的关键字段从 FeatureCollection 到坐标大多数地图可视化项目底层数据就是一个或多个 GeoJSON 文件。拿到资源包以后第一步是先把它打开确认结构是否满足你的使用场景。一个标准的 GeoJSON 地图文件顶层是一个 FeatureCollection 对象里面装着多个 Feature每个 Feature 的 geometry 字段描述了一块区域的边界形状。{ type: FeatureCollection, features: [ { type: Feature, properties: { name: 某区域, id: AREA_001 }, geometry: { type: MultiPolygon, coordinates: [ [ [[102.0, 20.0], [103.0, 21.0], [104.0, 20.5], [102.0, 20.0]] ] ] } } ] }这段 JSON 是一个最小可用的世界地图 GeoJSON 片段。逻辑说明最外层的 type 固定为 FeatureCollection表示这是一个要素集合features 数组里每一项是一个独立区域比如一个国家properties 存放区域的元数据name 是显示用的名称id 用于和业务数据关联geometry 里的 type 决定了边界的数据结构Polygon 是单一多边形MultiPolygon 是由多个多边形组成的复杂区域国家有飞地或岛屿时很常见。参数说明coordinates 数组里每一层方括号都代表一个层级从「多边形集合 → 单个多边形 → 环线性环→ 坐标点」坐标点必须是 [经度, 纬度] 的顺序。如果搞反成 [纬度, 经度]地图会沿着奇怪的方向拉伸变形这是初学 GeoJSON 时最常见的翻车点。2.2 地图引擎选型ECharts、Leaflet 与 D3 的适配差异同一个 GeoJSON 文件在不同地图引擎里的接入方式差别不小选型直接决定后续开发量。引擎GeoJSON 接入方式适合场景注意点EChartsregisterMap 注册后直接用 series-map数据仪表盘、报告图表需要 name 与业务数据名完全匹配LeafletL.geoJSON() 直接渲染Web GIS 应用、交互地图坐标系需为 WGS84EPSG:4326D3.jsd3-geo 的 geoPath 生成 SVG自定义交互、动画需自己处理投影参数ECharts 最省事因为它内置了地图投影和渲染逻辑GeoJSON 注册后无需关心投影细节Leaflet 则需要确保 GeoJSON 的坐标系是 WGS84 经纬度不然叠加瓦片图层时位置会对不上D3 的灵活性最高但也意味着工作量最大——投影方式、缩放级别、路径生成全都要自己配置。资源包里如果同时提供了世界地图和主要国家两个层级的文件我一般会在 ECharts 项目里注册两套地图世界一级用于宏观概览点进具体国家再切换该国的高精度边界这样首屏加载和交互体验都能兼顾。2.3 预处理工具链从原始数据到简洁可用的 GeoJSON下载下来的 GeoJSON 往往有几十 MB属性字段冗余直接在项目里用会有两个隐患首屏加载慢浏览器解析卡顿。我一般会让数据过一遍轻量预处理工具不固定根据需求选。用文本编辑器或 Node 脚本检查字段结构确定 name、id 等关键字段名用 MapShaper在线工具做边界简化可以在保持视觉形状基本不变的前提下大幅压缩文件体积用 QGIS 打开做空间校正检查几何是否自相交坐标范围是否符合经纬度范围经度 -180 到 180纬度 -90 到 90。最笨但最有效的验证方法把文件拖进 QGIS叠加 OpenStreetMap 底图肉眼比对轮廓。我遇到过某邻国边界在 GeoJSON 里整体偏移了两三个像素的情况叠加底图后一眼就暴露了纯靠代码检查很难发现这种问题。这些预处理做完数据再进前端踩坑概率会小很多。3. 在 ECharts 中接入世界地图 GeoJSON注册、绑定与调参3.1 加载文件并注册地图ECharts 从 5.x 版本开始不再内置地图数据需要外部传入 GeoJSON。这个资源包正好补上这一步。先把世界地图的 JSON 文件通过 fetch 请求拉回来再用 registerMap 注册成 ECharts 可用的地图实例。import * as echarts from echarts; const response await fetch(/maps/world.json); const worldGeoJson await response.json(); echarts.registerMap(world, worldGeoJson); const chart echarts.init(document.getElementById(map-container)); chart.setOption({ series: [{ type: map, map: world, roam: true }] });逻辑说明fetch 拿到的是文本流必须经过 response.json() 解析成对象registerMap 才能识别注册名称 world 是当前项目内唯一的标识后续 setOption 里的 map 字段必须和它一致否则图表会渲染成空白。参数说明roam: true 开启鼠标滚轮缩放和平移拖拽如果你希望初始视角聚焦到某个区域可以在 series-map 里配 center 和 zoomcenter 传 [经度, 纬度] 数组zoom 是缩放级别数值越大看得越近。3.2 业务数据绑定name 匹配与数据映射地图能跑起来只是第一步真实场景里要把销售额、人口、指标等业务数据映射到对应区域。ECharts 的 map 系列通过 data 数组和 GeoJSON 里的 name 属性进行关联。chart.setOption({ series: [{ type: map, map: world, roam: true, label: { show: true, fontSize: 10 }, data: [ { name: 某区域A, value: 12800 }, { name: 某区域B, value: 8600 } ], visualMap: { type: continuous, min: 0, max: 20000, text: [高, 低], calculable: true, inRange: { color: [#e0f3f8, #abd9e9, #74add1, #313695] } } }] });逻辑说明data 数组里的 name 必须和 GeoJSON 中 properties.name 完全一致一个字符都不能差。ECharts 遍历 GeoJSON 的每个区域拿 data 里的 name 去匹配匹配不上的区域就不会高亮上色但地图轮廓还在。参数说明visualMap 是颜色映射的核心配置min 和 max 决定映射范围超出范围的数值会被截断到端点颜色calculable 开启后图表上会出现一个可拖拽的手柄用户能动态筛选数据范围inRange.color 是一个颜色数组数据从小到大依次映射。这里有个隐藏细节如果某些区域你没传数据ECharts 默认会用 visualMap 里最低档的颜色渲染和「数值为 0」的表现一样。如果业务上需要区分「无数据」和「数据为 0」可以在 data 里显式给该项传 value: null再配合 visualMap 的 showLabel 做区分。3.3 区域下钻点击国家切换到该国地图宏观世界地图通常只承担「总览」角色用户点击某个国家后最好能下钻到该国的省级或更精细边界。这个资源包里的「主要国家」JSON 文件恰好覆盖了这一步——以某国家 GeoJSON 为例下钻逻辑可以这样实现。chart.on(click, function (params) { const countryName params.name; const filePath /maps/countries/${countryName}.json; fetch(filePath) .then(res res.json()) .then(geoJson { echarts.registerMap(countryName, geoJson); chart.setOption({ series: [{ type: map, map: countryName, roam: true }] }); }) .catch(() { console.warn(该国家暂未提供下钻地图数据); }); });逻辑说明点击事件触发后拿到当前区域的 name用模板字符串拼出对应的 GeoJSON 文件路径注册该国家的地图并切换 series-map 的 map 字段就完成了从世界地图到国家地图的钻取。参数说明文件名必须与 GeoJSON 中 properties.name 严格一致不然请求会 404。中文名最容易出问题——有的资源包文件名用英文代码如 CN有的用中文如某国家名称实际拿到后先列一下目录统一约定命名规则。子图切换后返回按钮可以用 dispatchAction 的 back 事件实现。chart.getZr().on(click, function (event) { if (event.target) return; chart.dispatchAction({ type: back }); });这段逻辑说明点击地图空白区域时触发返回上一级视图。event.target 为空表示点击的是画布空白处而非地图区域。dispatchAction 传 type: back 让 ECharts 回退到上一个地图层级无需自己维护历史栈。4. 常见问题与避坑世界地图 GeoJSON 的五个典型翻车现场4.1 区域边界对不上这块区域怎么多了一块 / 少了一块现象渲染出来后某个国家的形状和印象中对不上或者整体轮廓明显变形。原因文件本身数据版本太旧或者下载源在矢量化的过程中丢了一部分岛屿和飞地。另一个高发场景是坐标系串了——拿到的 GeoJSON 是投影坐标系如墨卡托投影米制坐标直接喂给 ECharts它按经纬度解析图形直接被压缩成一条线。解决先确认文件里的坐标值——正常经纬度范围经度在 -180 到 180纬度在 -90 到 90如果是几百万的数值说明坐标已经被投影过需要先用 QGIS 或 ogr2ogr 转回 WGS84 经纬度坐标再进前端。4.2 地图渲染空白控制台也没有报错现象ECharts 实例创建成功series 配置了 type: map但界面上只有坐标轴空白没有地图轮廓。原因registerMap 没有在 setOption 之前执行成功或者注册名和 series.map 不一致。这类问题的隐蔽点在于——ECharts 对不存在的 map 不会报错只会安静地画一个空坐标系。解决在 registerMap 后加一行console.log(register success)或者在 setOption 前打印 chart.getOption() 确认地图配置注入如果 fetch 的是本地 JSON 文件还要留意开发服务器的静态资源路径是否写对。4.3 properties.name 匹配不上部分区域不上色现象visualMap 设置了数据也传了但地图上有一两个区域始终是空白底色。原因业务数据里的 name 和 GeoJSON properties.name 存在细微差异——常见的有全角半角空格、「某共和国」和「某」的简称差异、大小写不一致。解决写一个脚本遍历 GeoJSON 的 properties.name打印成数组再和业务数据表做一次差集比对把不一致的映射关系落成别名表。这是最费时间但最有效的办法别名表的维护可以做成一个常量文件并长期迭代。4.4 GeoJSON 文件体积过大首屏加载卡顿现象页面加载完整地图需要 3 秒以上网络请求显示文件有 30MB。原因原始 GeoJSON 包含精确到小数点后 6 位以上的坐标相邻点之间差距极小冗余极高。解决用 MapShaper 简化边界保留精度设置在 0.1km 到 1km 之间文件体积通常可以缩小到原来的十分之一以下如果只做国家层级的下钻预览也可以直接把低精度版本作为首屏地图点击下钻时再加载高精度版本。4.5 岛屿和边界归属有争议直接照搬会惹麻烦现象地图渲染后某些区域显示归属错误或者在项目评审时被挑出来指正。原因不同来源的 GeoJSON 对争议区域的归属处理不一致有的把岛屿划给了一侧有的则单独处理。解决项目里涉及敏感边界时需要找权威的边界数据源进行比对不能照单全收。处理边界数据本来就是地图开发里的常态——先用脚本圈出争议区域做单独的属性变更再渲染时用不同颜色标注「数据待确认」给产品确认的时间。老经验边界数据的审核优先级永远高于样式和交互。5. 数据加工进阶从世界地图中裁剪出需要的区域5.1 提取指定国家的边界从世界文件中切出子集很多场景不需要全世界的边界数据只需要某一个国家的详细边界。直接用整个世界地图文件会增加前端解析开销。可以用一个小脚本从世界地图 GeoJSON 里提取目标国家。import json with open(world.json, r, encodingutf-8) as f: data json.load(f) target_name 某国家 target_features [ feature for feature in data[features] if feature[properties][name] target_name ] output { type: FeatureCollection, features: target_features } with open(country.json, w, encodingutf-8) as f: json.dump(output, f, ensure_asciiFalse)逻辑说明json.load 读取整个世界地图列表推导式按 properties.name 过滤出目标国家的所有 Feature重新封装成 FeatureCollection 并写出到新文件。参数说明如果目标国家的边界分布在多个 Feature 里典型的是包含飞地、离岛target_features 会包含多个元素必须全部保留不能只取第一个。如果你希望输出的字段更精简可以在推导式里用 dict 过滤 properties只留 name 和 id这样单文件体积还能再小一截。5.2 合并相邻区域把多个小国合并成一个聚合块做区域分析时经常需要把地理相邻但行政上独立的区域合并显示比如「某地区板块」。GeoJSON 的合并不能直接拼接数组——因为合并后需要消除内部边界不然渲染出来会多出内部的线。from shapely.geometry import shape, mapping from shapely.ops import unary_union target_names [某区域A, 某区域B, 某区域C] geometries [] for feature in data[features]: if feature[properties][name] in target_names: geometries.append(shape(feature[geometry])) merged_geom unary_union(geometries) new_feature { type: Feature, properties: {name: 聚合区域}, geometry: mapping(merged_geom) }逻辑说明shape 把 GeoJSON 几何对象转成 Shapely 可计算的几何对象unary_union 是核心——它做的不只是把多个图形放进同一个数组而是真正计算几何并集消除内部重叠边界。mapping 再把结果转回 GeoJSON 兼容的字典结构。参数说明unary_union 的处理结果是 Polygon 还是 MultiPolygon 取决于几何是否连续相接。如果合并后产生多个不相连的块geometry.type 会是 MultiPolygon在 ECharts 里仍能正常渲染但如果下游系统不支持 MultiPolygon需要拆分成多个 Feature 输出。5.3 GeoJSON 转 TopoJSON当文件体积仍然偏大时GeoJSON 的冗余在于相邻区域的共享边界存储了两遍坐标数据。TopoJSON 通过共享边界的拓扑关系来消除这种冗余体积通常可以再压缩 50% 到 80%。geo2topo world.geo.json world.topo.json toposimplify -F -P 0.1 world.topo.json world.simplified.topo.json逻辑说明geo2topo 做格式转换本质是把重复的边界点合并成共享弧段toposimplify 做进一步简化保留拓扑正确性的前提下删除不重要的点。参数说明-P 0.1 表示简化精度为 0.1 弧度数值越大文件越小但边界变形越明显。实际用下来世界地图 -P 0.1 是视觉效果和性能的均衡点如果你渲染的是单个国家建议 -P 0.05 以内不然海岸线细节会有可感知的锯齿。ECharts 支持直接加载 TopoJSON但需要引入 topojson-client 来解析成 GeoJSON 再注册。import * as topojson from topojson-client; const response await fetch(/maps/world.topo.json); const topoData await response.json(); const geoJson topojson.feature(topoData, topoData.objects.countries); echarts.registerMap(world, geoJson);逻辑说明topojson.feature 接收两个参数——TopoJSON 数据和对象名。对象名是 TopoJSON 内部定义的 key取决于生成时的配置。如果不确定可以在拿到数据后先打印 topoData.objects看一下里面有哪些键名。这条链路跑通后世界地图的加载体积基本可以控制到 1MB 以内。6. 验证 GeoJSON 的几何正确性三道检查让地图不翻车地图数据上线前我会强制自己走一遍几何检查流程。别嫌麻烦你永远不会想在演示现场遇到「某块区域扭曲成一团乱麻」的尴尬。第一道坐标范围检查。遍历所有坐标点确认经度在 -180 到 180、纬度在 -90 到 90 之间。超出这个范围说明文件里混入了投影坐标或脏数据直接定位到具体 Feature 排查。def check_coords(geometry): if geometry[type] Polygon: rings geometry[coordinates] elif geometry[type] MultiPolygon: rings [ring for poly in geometry[coordinates] for ring in poly] else: return for ring in rings: for lon, lat in ring: assert -180 lon 180, f经度越界: {lon} assert -90 lat 90, f纬度越界: {lat}第二道几何自相交检查。用 Shapely 的 is_valid 方法它可以识别出「环自相交」「重复点」「悬挂线段」等几何错误。无效几何在浏览器里通常表现为区域填充出现奇怪的缺口或细线但控制台不会报错。from shapely.geometry import shape valid_count 0 for feature in data[features]: geom shape(feature[geometry]) if geom.is_valid: valid_count 1 else: print(无效几何:, feature[properties].get(name)) print(f有效 {valid_count}/{len(data[features])})第三道面积敏锐度检查。计算每个区域的面积和真实世界面积做量级对比。GeoJSON 的经纬度坐标可以直接用 Shapely 的 area 方法结果不代表真实平方公里数但同一数据源内的相对量级应该合理。如果出现某个大陆区域面积比一个小岛还小的情况大概率是坐标顺序写反了——Polygon 环的坐标顺序确实会影响几何解释。从那以后我每拿到一份新的 GeoJSON都会先跑一遍这三道检查再进项目。十分钟的常规操作能在后续开发里省下大半天排错时间。希望这份世界地图与主要国家 GeoJSON 资源包能帮你跳过找数据的环节把时间花在真正的地图交互和业务实现上。本文还有配套的精品资源点击获取