简介这是一份基于 ECharts 的全国省份地图 JSON 数据集覆盖全国主要省份、自治区、直辖市及港澳台地区并收录各区域主要城市经纬度坐标面向需要制作地图可视化的前端工程师、数据分析师及可视化学习者可解决官方地图数据不完整或需长期依赖在线图源的问题。压缩包共35个 JavaScript 文件大小约844KB每个 JS 文件对应一个省份或地区的 GeoJSON 边界与城市坐标数据全部离线可用项目部署时直接引入对应脚本即可。这套数据已有2056人浏览学习属于 ECharts 地图开发中常用的数据补充包。开发者不必自行绘制行政区边界或逐省份爬取坐标直接引入对应省份的 JS 文件即可在 ECharts 中渲染出带省份轮廓的地理分布图显著减少地图数据准备与调试成本。文件命名清晰、路径简单适用于管理后台、大屏展示、数据报表等场景可显著提升地理数据可视化的开发效率与体验。1. 为什么做图先要拿到一套“能用的”地图JSON与经纬度数据接到一个数据可视化大屏需求往往第一件事就是打开ECharts示例复制代码但地图区域一片空白控制台只有一条GeoJSON加载失败。问题通常不在ECharts本身而是你手里的地图JSON数据不对、坐标不对、名称对不上。本篇文章围绕“echarts地图json数据全国个省份主要城市经纬度数据文件”这条组合把GeoJSON的结构、经纬度数据如何生成与校验以及这两类数据怎么喂给ECharts讲清楚。适合用Vue3、React或原生JS接ECharts做可视化大屏的前后端工程师也适合需要在地图上叠加散点、飞线、下钻的团队。看完你就能自己搭一套可复用的地图数据工作流而不是每次换项目都重新踩一遍坐标偏移的坑。2. 读懂ECharts地图背后的GeoJSON坐标、精度与层级2.1 从“全国个省份”到坐标集合GeoJSON的Feature结构ECharts官方地图和多数第三方地图包都遵循GeoJSON规范。一个中国地图文件本质上是一个FeatureCollection其中每个Feature代表一个省级行政区geometry记录该省边界的经纬度坐标串。常见做法是打开名为china.json的文件你会看到类似结构{ type: FeatureCollection, features: [ { type: Feature, properties: { name: 北京市, adcode: 110000 }, geometry: { type: MultiPolygon, coordinates: [ [ [ [116.058, 40.365], [116.131, 40.374] ] ] ] } } ] }这里coordinates层层嵌套对应面、环、点。ECharts地图运行时只读取properties.name和geometry。也就是说注册时用这个JSON里的name与map参数对应即可adcode主要用于下钻请求关联。2.1.1 坐标顺序与经纬度精度坐标数组里的每个点形如[经度, 纬度]经度范围约为[73, 135]纬度范围约为[18, 54]。很多初学者把高德地图拾取到的坐标直接塞进GeoJSON结果地图挤成一团或飞线乱跑就是因为坐标系不一致。ECharts地图默认使用经纬度表示内部再做投影。常见的阿里云DataV GeoJSON、ECharts示例数据多为WGS-84近似值但高德API和天地图坐标拾取器返回的是GCJ-02或CGCS2000。边界数据本身受精度政策影响存在几十米到几百米的偏移地图上看不明显但和GPS采集点叠加时就会暴露。数据来源坐标系是否需要纠偏ECharts官方地图WGS-84近似不需要高德地图API/拾取器GCJ-02叠加GPS点需转换天地图坐标拾取CGCS2000边界需转换GPS设备WGS-84在高德底图上需转GCJ-02如果你用高德地图瓦片作底图再用ECharts散点叠加必须把GPS经纬度先转成高德经纬度GCJ-02。这一步常用Python脚本做。2.1.2 省级边界数据精度的影响边界数据文件大小通常在几MB到几十MB。全国省级地图的边界精度要求其实不高每个省几十到几百个点即可城市级、区县级地图则可能需要上千点。如果文件过大页面交互会卡顿需要在生成JSON时做抽稀常用的是Douglas-Peucker算法。2.2 主要城市经纬度数据独立于边界的坐标点集合标题里的“全国个省份主要城市经纬度数据文件”其实有两类用途一是为散点图、标注点提供坐标二是配合省份名做地图下钻。城市经纬度数据通常不表示为GeoJSON而是一个数组结构如下[ {name: 北京市, value: [116.4074, 39.9042]}, {name: 上海市, value: [121.4737, 31.2304]}, {name: 广州市, value: [113.2806, 23.1251]} ]注意这里的value是[经度, 纬度]与ECharts中scatter和effectScatter的数据要求一致。在画地理坐标点时ECharts会先通过geo坐标系定位到地图再按坐标映射。如果这两类数据中的一个坐标系不对就会产生“点在海上”的效果。3. 全国省份与主要城市经纬度JSON数据的获取与清洗3.1 获取GeoJSON的基础来源与选型常见做法是直接用DataV.GeoAtlas提供的全国省份及城市GeoJSON它按adcode组织访问形如https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json。这个地址依赖网络离线项目需要提前下载。按省份获取时请求{adcode}_full.json即可。获取方式有几种从DataV.GeoAtlas手动下载json文件用Python脚本批量拉取并保存用高德API获取行政区域边界并转GeoJSON但需要申请Key。我一般建议优先用DataV GeoAtlas因为它的边界数据已经适配ECharts常见用法且properties里带有adcode和name便于下钻。3.2 用Python批量生成省份城市经纬度JSON文件主要城市经纬度数据可以整理自公开行政区划表也可以根据城市名称保留“市辖区”的中心坐标。下面脚本读取包含城市名称和中心点经纬度的CSV输出可直接用于ECharts的JSON文件import json import csv def build_cities_json(csv_path, output_path): cities [] with open(csv_path, encodingutf-8) as f: reader csv.DictReader(f) for row in reader: cities.append({ name: row[city], value: [float(row[lng]), float(row[lat])] }) with open(output_path, w, encodingutf-8) as f: json.dump(cities, f, ensure_asciiFalse, indent2) print(f已生成 {len(cities)} 个城市坐标) if __name__ __main__: build_cities_json(cities.csv, cities.json)这段脚本逻辑很简单逐行读取CSV把字符串经纬度转为浮点数组装成ECharts散点数据格式。参数说明ensure_asciiFalse保证中文城市名不被转义indent2便于调试时人工检查。city列应当与GeoJSON里省份或城市地图的name一致否则ECharts会无法按名称关联。3.2.1 坐标转换从GPS到高德如果手上只有GPS设备采集的WGS-84坐标而底图用的是高德地图瓦片需要做坐标偏移转换。常见做法是用一个精简的WGS-84转GCJ-02脚本import math def wgs84_to_gcj02(lng, lat): a 6378245.0 ee 0.006693421622965943 # 转换逻辑主体计算经纬度偏移 d_lat transform_lat(lng - 105.0, lat - 35.0) d_lng transform_lng(lng - 105.0, lat - 35.0) rad_lat lat / 180.0 * math.pi magic math.sin(rad_lat) magic 1 - ee * magic * magic sqrt_magic math.sqrt(magic) d_lat (d_lat * 180.0) / ((a * (1 - ee)) / (magic * sqrt_magic) * math.pi) d_lng (d_lng * 180.0) / (a / sqrt_magic * math.cos(rad_lat) * math.pi) return lng d_lng, lat d_lat完整转换函数较长实践上直接使用coord_convert或pyproj库更稳妥。更稳定的方案是调用高德坐标转换API把批量坐标一次性转成GCJ-02。注意高德每天有免费配额批量场景要控制请求频率。3.2.2 批量获取城市中心点并核对省市映射很多城市经纬度数据的常见误区是只统计“地级市”导致省直辖县、自治州缺失。需要结合行政代码做层级过滤。一般数据结构会包含省的adcode、市的adcode和城市名。在生成时只保留城市级别记录。如果某个城市没有中心点数据可以根据其下属区县的中心点加权平均估算或者忽略并在图上用省中心点占位。我一般会额外生成一个province_city_map.json用于地图下钻时知道该省包含哪些城市{ 广东省: [广州市, 深圳市, 珠海市, 汕头市, 佛山市], 浙江省: [杭州市, 宁波市, 温州市, 嘉兴市] }这个文件与经纬度文件配合用于点击省级地图后切换城市地图。生成时注意城市名称与GeoJSON文件的properties.name一致。常见不一致广西“防城港市”在有些数据源写成“防城区”新疆“伊犁哈萨克自治州”直接写成“伊犁”。3.3 校验文件格式的三板斧拿到JSON文件先别急着写代码用三个方法快速校验用json.load检查是否可解析若报unexpected end of JSON input多半是下载不完整重新拉取。用console.log打印GeoJSON.features.map(f f.properties.name)检查名称是否缺失。用Leaflet或OpenLayers临时加载该GeoJSON查看边界是否变形。没有GIS工具时用Python的geopandas快速画边界。4. 在ECharts中注册地图JSON数据并叠加经纬度数据4.1 最小可运行图表从注册地图到绘制省份填充图打开一个HTML用CDN引入ECharts然后注册GeoJSON地图!DOCTYPE html html head meta charsetutf-8 script srchttps://cdn.jsdelivr.net/npm/echarts5/dist/echarts.min.js/script /head body div idmap stylewidth: 100%; height: 600px;/div script fetch(https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json) .then(res res.json()) .then(chinaJson { echarts.registerMap(china, chinaJson); const chart echarts.init(document.getElementById(map)); chart.setOption({ geo: { map: china, roam: true, itemStyle: { areaColor: #d7e8f5, borderColor: #333 } } }); }); /script /body /html这段代码做了三件事fetch获取GeoJSON、registerMap注册地图、setOption配置geo组件。参数说明roam: true允许缩放拖拽itemStyle控制区域颜色和边界geo组件本身不绘制业务数据要显示省份数值需要配series-map。4.1.1 用series-map展示省份数据填充图通常用series-map关键参数是map和data。data里name必须和GeoJSON的name完全一致包括“省”字series: [{ type: map, map: china, roam: true, data: [ { name: 广东省, value: 108 }, { name: 浙江省, value: 84 } ] }]这里没有匹配到的省份会保持默认色。常见坑是GeoJSON名称是“广西壮族自治区”而你写“广西”导致不显示。一个通用处理是在渲染前做名称归一化映射表。注意如果同时配置了geo和series-map两者会叠加。series-map中的geoIndex可以指定使用哪个geo组件。建议二选一要么只用geo加scatter要么用series-map完成填充图。混用时边界样式容易错乱。4.2 叠加主要城市经纬度散点与标注把cities.json加载进来用effectScatter叠加fetch(cities.json).then(res res.json()).then(cities { chart.setOption({ geo: { map: china, roam: true }, series: [{ type: effectScatter, coordinateSystem: geo, data: cities, symbolSize: 6, rippleEffect: { scale: 3 }, label: { show: true, formatter: {b}, position: right } }] }); });这里的coordinateSystem: geo告诉ECharts用刚才注册的地图坐标系来定位。城市数据里的value数组前两位是[经度, 纬度]第三位如果有值会被当成数据项的值参与symbolSize映射。我们在生成cities.json时只放了经纬度因此默认圆点大小相同。如果要让城市点根据业务数据大小变化可以改cities数据结构{name: 杭州市, value: [120.1551, 30.2741, 8800000]}然后在series里配置symbolSize: function(val) { return Math.max(4, Math.sqrt(val[2] / 10000)); }。这样人口多的城市点更大视觉上更有表现力。4.2.1 markPoint和markLine的坐标谜题有些教程会在series-map里配markPoint此时coord坐标需要是经纬度而series-scatter不需要name匹配。实际项目中我更喜欢把城市点单独抽成effectScatter或scatter层而不是markPoint因为markPoint的数据顺序和样式调整不灵活坐标读取规则也不同。使用markPoint时如果地图JSON注册得晚可能出现“点在左上角”或“位置全偏”。比较markPoint和scatter的差异维度markPointseries-scatter数据绑定性与map的name关联独立name与坐标坐标体系通常经纬度coordinateSystem: geo适合场景少量关键点成批城市点、飞线端点4.3 将经纬度数据文件应用到3D地图大屏项目常用到echarts echarts-gl做3D地图使用geo3d map3d scatter3d。做法是引入echarts-gl再注册同一份GeoJSON但series改用map3D或geo3Dscript srchttps://cdn.jsdelivr.net/npm/echarts-gl2/dist/echarts-gl.min.js/scriptchart.setOption({ geo3D: { map: china, shading: lambert, regionHeight: 2, itemStyle: { color: #2a5caa } } });echarts-gl的map3D同样依赖echarts.registerMap。与普通地图的区别是3D场景中的散点用scatter3D数据坐标是[经度, 纬度, 高度]第三位是海拔或数值不再是普通scatter那样第三位作为数据值。这个差异容易导致散点直接飞上天。解决方法是把城市json的value改成[lng, lat, 0]再单独用一个字段存业务值{name: 杭州市, value: [120.1551, 30.2741, 0], ext: 8800000}配合scatter3D的symbolSize回调读取dataItem.value[2]作为高度ext映射大小。注意geo3D和scatter3D同时存在时coordinateSystem必须设置为geo3D否则点不会贴到3D地图上。5. 省级地图下钻用一份省份城市经纬度文件切换省市两级5.1 下钻的数据组织方式下钻是指点击省份后切换到该省的城市地图。常见做法是监听map的click事件拿到params.name省份名再读取该省对应的GeoJSON并重新registerMap。chart.on(click, function(params) { if (params.name provinceAdcodes[params.name]) { fetch(https://geo.datav.aliyun.com/areas_v3/bound/${provinceAdcodes[params.name]}_full.json) .then(res res.json()) .then(cityJson { echarts.registerMap(province, cityJson); chart.setOption({ series: [{ type: map, map: province }] }); }); } });这里的provinceAdcodes需要一张省名与adcode的映射表。可以提前从全国GeoJSON的features[].properties.adcode生成。注意重新registerMap后必须把series里的map从china改成province否则点击无效。5.1.1 点击事件里区分“已下钻”和“返回全国”在下钻状态下再点击省份通常希望返回上一级。常见做法是设置一个isDrill标记并判断点击坐标是否在统一地图范围。一个取巧方法下钻后把地图的nameMap改成城市名当点击的城市名等于当前地图的城市名时注册回全国地图。或者直接在地图外放一个返回按钮避免误触。下钻时还要处理城市经纬度文件点击省份后该省的主要城市散点应从全国数据中过滤出来而不是全局叠加所有城市。所以在cities.json里每个城市数据项应带上省份字段{ name: 杭州市, province: 浙江省, value: [120.1551, 30.2741] }下钻后重新setOption时把data换成allCities.filter(c c.province params.name)。5.2 下钻时地图缩放动画与南海诸岛的处理当从全国地图切换到单独省份地图时ECharts会自动按GeoJSON边界缩放。常见问题是下钻后地图贴边视觉上缺少留白。解决方法是设置layoutCenter和layoutSizeseries: [{ type: map, map: province, layoutCenter: [50%, 55%], layoutSize: 80% }]layoutCenter指定地图在容器中的中心位置layoutSize指定缩放后的地图尺寸。全国地图通常不需要这两个参数但下钻后不设置时可能贴住容器上边和左边。另一个下钻难点是南海诸岛。全国GeoJSON通常带有“南海诸岛”的feature但你不希望在点击时把它当成省份进入。处理方式是注册地图前过滤掉这个名称const features chinaJson.features.filter(f f.properties.name ! 南海诸岛); echarts.registerMap(china, { type: FeatureCollection, features: features });注意过滤后全国地图右下角的小图可能消失影响不大但在业务展示时需要明确说明。6. 地图数据不显示、偏移、缺失时的排错与验证技巧6.1 地图空白与名称不匹配的快速定位遇到地图空白先打印注册对象echarts.registerMap(china, chinaJson); console.log(chinaJson.features.length);如果打印结果为0说明GeoJSON没有正确加载如果大于0但地图依旧空白检查geo.map和series.map的值是否都等于注册名。名称不匹配是另一个高频问题。用一行代码列出所有可用的名称和你的data中的name做比对const nameList chinaJson.features.map(f f.properties.name); console.log(nameList);常见差异是“内蒙古自治区”写成“内蒙古”“香港特别行政区”写成“香港”。在代码中维护一个nameMap对象在setOption之前把data里的name替换掉。6.2 验证经纬度数据文件可用性的三个步骤第一范围校验。写一个Python脚本检查经度是否在73~135纬度是否在18~54import json with open(cities.json, encodingutf-8) as f: cities json.load(f) bad [ c[name] for c in cities if not (73 c[value][0] 135 and 18 c[value][1] 54) ] print(异常城市:, bad if bad else 全部正常)第二坐标一致性。选一个已知城市把它在高德地图或天地图坐标拾取器里的坐标和JSON里的坐标对比。偏差大于0.1度就要检查坐标系。第三名称差集检查geo_names {f[properties][name] for f in geo_json[features]} city_names {c[name] for c in cities} print(不在边界数据中的城市:, city_names - geo_names)这个差集是下钻路由的关键依据。6.3 大文件地图的最后一招抽稀与按需加载GeoJSON体积过大时我一般会在服务端做两件事把经纬度从6位小数截断为4位以及用保留精度算法抽稀边界点。截断后地图视觉效果几乎不变文件体积能减少三分之一。再配合下钻时才加载对应省份JSON全国地图只保留省级边界可把首屏加载时间控制在1秒内。调试期还可以在geo配置里临时开启label: { show: true }用肉眼确认省名和散点位置是否合理。调试完再关闭。本文还有配套的精品资源点击获取