
简介本资源是一套专为ECharts地理可视化开发准备的中国行政区划地图数据集面向前端开发者、数据可视化工程师及大数据分析学习者解决在Web端快速实现省市级联动地图展示的核心需求。压缩包共863个文件主体为610个省级与地市级JSON地理数据文件如xinjiang.js、sichuan.js等辅以250个配套JS工具脚本用于数据加载、坐标转换与交互配置整体体积12.62MB结构清晰、开箱即用。目前已有14516人学习下载热度高、实用性广。用户可直接将JSON数据接入ECharts series 配置快速构建支持缩放、平移、tooltip悬停提示的交互式中国地图同时获得全国34个省级单位及下属全部地级市的完整边界坐标与区域标识覆盖从宏观省份到微观城市的两级地理层级显著降低自定义地图开发门槛大幅提升人口、经济、环境等多维数据的空间表达效率。1. ECharts全国省地图市级下钻为什么90%的初学者卡在“地图不显示”和“点击没反应”这两步你不是第一个被 ECharts 地图坑到怀疑人生的开发者。标题里这个需求看似简单——“全国省地图 每个省对应的市地图”但实际落地时80% 的人会在三处彻底卡死第一echarts-gl 或 geoJSON 数据加载后地图一片空白控制台没报错却啥也不画第二省界能出来但一点击某省市级地图死活切不过去或者切过去后坐标歪斜、文字重叠、缩放失灵第三用网上搜到的“各省 JSON 文件”直接替换结果发现河北的唐山被画到了山西境内或者广东的深圳压根没数据点。这不是你代码写错了而是 ECharts 地图体系里藏着三个必须手动对齐的“隐性契约”地理坐标系geo与视觉坐标系grid的绑定关系、不同行政层级 JSON 数据的 projection 一致性、以及事件回调中params.name与 JSON 文件命名/属性字段的严格匹配。本文不讲“怎么引入 echarts.min.js”只聚焦于从零跑通「省级初始渲染 → 点击下钻至市级 → 返回省级」这一完整闭环所有步骤均基于 ECharts 5.4 官方推荐路径不依赖任何第三方插件或非标 geoJSON 源。适合正在做政企数据看板、区域运营分析系统、或教育类地理可视化 Demo 的前端/全栈工程师。2. 准备可验证的地理数据为什么必须自己生成省/市两级 geoJSON而不是用网上现成的ECharts 渲染地图的本质是把 geoJSON 中的features数组逐个转为 SVG 路径并挂载到 canvas 上。而市面上流传的“各省 JSON”文件95% 存在三类硬伤坐标系未统一WGS84 / GCJ02 / BD09 混用、行政区划版本过旧如仍含已撤销的巢湖市、边界精度不足县级单位缺失导致市级无法独立渲染。直接拿来用轻则位置偏移 5–10 公里重则整个 feature 渲染失败且无提示。正确做法是用国家基础地理信息中心公开的 2023 年版行政区域矢量数据1:100 万通过 ogr2ogr TopoJSON 工具链标准化生成两级 geoJSON。下面给出可复现的最小命令集全程离线完成不调用任何外部 API。2.1 下载并解压官方标准数据源无需注册国家基础地理信息中心提供免费下载的《中华人民共和国县级以上行政区划界线2023年》Shapefile 压缩包文件名形如2023_province_city_county.zip。解压后得到province.shp省级、city.shp地级市、county.shp县级三个图层。注意此处city.shp即为“每个省对应的市地图”的原始依据它包含PROVINCE省名、CITYNAME市名、ADCODE行政区划代码三个关键字段。提示若无法获取该数据可用npm install -g shapefile后执行shapefile download --levelprovince,city该命令会自动拉取经校验的 2023 版本原理是调用国家测绘地理信息局备案的镜像源非网络爬虫。2.2 用 ogr2ogr 统一坐标系并裁剪出单省市级数据ECharts 要求所有 geoJSON 使用 WGS84EPSG:4326坐标系。原始 Shapefile 多为 CGCS2000EPSG:4490需强制转换# 将 city.shp 转为 WGS84并按省份拆分为独立文件以江苏省为例 ogr2ogr -f GeoJSON -t_srs EPSG:4326 \ -where PROVINCE 江苏省 \ jiangsu-city.geojson city.shp此命令输出jiangsu-city.geojson其features中每个对象的properties必含CITYNAME字段如CITYNAME: 南京市这是后续 ECharts 点击事件匹配的关键。2.3 用 topojson-simplify 降低面片复杂度必做原始市级边界 geoJSON 单文件常超 5MB加载慢且拖垮渲染帧率。TopoJSON 可将相邻省界共享边线体积压缩 60%# 先转为 topojson再简化保留 95% 形状精度 topojson -o jiangsu-city.topo.json \ --simplify-proportion0.95 \ jiangsu-city.geojson最终得到jiangsu-city.topo.json文件大小通常压至 1.2MB 内且 ECharts 原生支持.topo.json后缀加载。2.4 验证数据有效性用 QGIS 快速肉眼检查将生成的jiangsu-city.topo.json拖入 QGIS免费开源 GIS 软件叠加高德地图底图重点检查三点① 所有地级市是否完整覆盖江苏全境无空洞② 南京市、无锡市等名称标注是否落在对应多边形内部而非边缘③ 与邻省如安徽、山东交界处是否无缝拼接无白缝或重叠。只有这三项全通过才进入 ECharts 编码环节。否则返回第 2.2 步调整-where条件或检查原始 Shapefile 字段映射。3. ECharts 初始化如何用 registerMap 正确注册省/市两级地图并绑定事件ECharts 不内置中国省/市地图必须通过echarts.registerMap()手动注入。但多数教程只贴一句registerMap(china, json)却没说清同一页面内注册多个同名地图如两次registerMap(jiangsu, ...)会导致后者覆盖前者且无任何警告。下钻场景必须实现“省地图”与“市地图”双注册并通过chartInstance.setOption()动态切换。以下是经过 3 个项目验证的最小初始化模板。3.1 创建双地图注册容器避免命名冲突// mapRegistry.js —— 地图注册中心集中管理所有 geoJSON import * as echarts from echarts; // 1. 注册全国省地图基础底图 fetch(/geo/china-province.geo.json) .then(res res.json()) .then(json { echarts.registerMap(china, json); }); // 2. 注册江苏省市级地图下钻目标 fetch(/geo/jiangsu-city.topo.json) .then(res res.json()) .then(json { // 关键注册时指定 name 为 jiangsu而非 china echarts.registerMap(jiangsu, json); });逻辑说明registerMap(name, geoJson)的name是后续series.map的值也是params.name的来源。全国图用china江苏图用jiangsu二者完全隔离。若误将市级图也注册为china则点击江苏后setOption切换地图时ECharts 会因找不到china新数据而静默失败。3.2 构建可下钻的 option 配置核心// initChart.js const chartDom document.getElementById(main); const myChart echarts.init(chartDom); // 初始渲染全国省地图 let currentMap china; // 当前激活的地图名 let prevMap null; // 上一级地图名用于返回 const baseOption { tooltip: { trigger: item, formatter: {b} // 显示省名 }, series: [{ type: map, map: currentMap, // 动态绑定地图名 label: { show: true }, emphasis: { label: { show: true } }, data: [] // 此处留空由后端或本地数据填充数值 }] }; myChart.setOption(baseOption); // 绑定点击事件仅对省地图生效 myChart.on(click, (params) { if (currentMap ! china) return; // 非全国图时不响应 const provinceName params.name; // 将中文省名转为拼音小写如 江苏省 → jiangsu用于匹配注册名 const mapName convertToMapName(provinceName); // 实现见 3.3 节 // 检查该省市级地图是否已注册 if (echarts.getMap(mapName)) { currentMap mapName; prevMap china; // 重新 setOption触发市级地图渲染 myChart.setOption({ series: [{ map: mapName, label: { show: true, fontSize: 12 }, // 市级文字需缩小字号 emphasis: { label: { show: true, fontSize: 14 } } }] }); } else { console.warn(市级地图 ${mapName} 未注册请检查数据文件); } });3.3 中文省名 → 地图注册名的转换函数避坑关键function convertToMapName(chineseName) { // 建立确定性映射表不可用拼音库动态转换 const mapNameMap { 北京市: beijing, 天津市: tianjin, 河北省: hebei, 山西省: shanxi, 内蒙古自治区: neimenggu, 辽宁省: liaoning, 吉林省: jilin, 黑龙江省: heilongjiang, 上海市: shanghai, 江苏省: jiangsu, 浙江省: zhejiang, 安徽省: anhui, 福建省: fujian, 江西省: jiangxi, 山东省: shandong, 河南省: henan, 湖北省: hubei, 湖南省: hunan, 广东省: guangdong, 广西壮族自治区: guangxi, 海南省: hainan, 重庆市: chongqing, 四川省: sichuan, 贵州省: guizhou, 云南省: yunnan, 西藏自治区: xizang, 陕西省: shaanxi, // 注意陕西是 shaanxi山西是 shanxi 甘肃省: gansu, 青海省: qinghai, 宁夏回族自治区: ningxia, 新疆维吾尔自治区: xinjiang, 台湾省: taiwan, 香港特别行政区: xianggang, 澳门特别行政区: aomen }; return mapNameMap[chineseName] || null; }参数说明convertToMapName()必须用静态映射表而非pinyinjs等库。因为“陕西”拼音是Shaanxi防与山西Shanxi混淆而库默认输出Shanxi会导致echarts.getMap(shanxi)查不到陕西地图。此表已覆盖全部 34 个省级单位复制即用。4. 下钻交互增强如何实现“点击市级 → 显示该市下辖区县”及“返回上一级”按钮仅实现省→市下钻是半成品。真实业务中用户常需进一步查看南京的鼓楼区、玄武区或从苏州市退回江苏省。ECharts 本身不提供“返回”能力需手动维护地图栈并重置series.map。同时市级下钻需解决新问题同一省内多个市名重复如“朝阳区”在北京、“朝阳市”在吉林导致params.name无法唯一标识。解决方案是绑定params.adcode行政区划代码它全国唯一。4.1 构建地图栈管理器支持无限级返回// mapStack.js class MapStack { constructor() { this.stack [china]; // 初始为全国图 } push(mapName) { // 避免重复入栈如连续点击同一省 if (this.stack[this.stack.length - 1] ! mapName) { this.stack.push(mapName); } } pop() { if (this.stack.length 1) return null; this.stack.pop(); return this.stack[this.stack.length - 1]; } getCurrent() { return this.stack[this.stack.length - 1]; } getPrev() { return this.stack.length 2 ? this.stack[this.stack.length - 2] : null; } } export const mapStack new MapStack();4.2 改造点击事件支持 adcode 匹配与多级下钻// 在 initChart.js 中替换原 click 事件 myChart.on(click, (params) { // 优先使用 adcode更可靠fallback 到 name const adcode params.adcode || ; const name params.name; // 若当前是市级地图且点击的是地级市adcode 长度为 6则下钻到该市的区县 if (currentMap ! china adcode.length 6) { // 根据 adcode 获取市级名称如 320100 → 南京市 const cityName getCityNameByAdcode(adcode); const districtMapName ${cityName}-district; // 如 nanjing-district if (echarts.getMap(districtMapName)) { mapStack.push(districtMapName); currentMap districtMapName; myChart.setOption({ series: [{ map: districtMapName }] }); return; } } // 否则按原逻辑处理省→市 if (currentMap china) { const mapName convertToMapName(name); if (mapName echarts.getMap(mapName)) { mapStack.push(mapName); currentMap mapName; myChart.setOption({ series: [{ map: mapName }] }); } } }); // 返回按钮事件 document.getElementById(back-btn).addEventListener(click, () { const prevMap mapStack.pop(); if (prevMap) { currentMap prevMap; myChart.setOption({ series: [{ map: prevMap }] }); } });4.3 生成区县级地图以南京市为例区县数据需从county.shp提取并按CITYNAME过滤# 生成南京市下辖区县 geoJSON含高淳区、溧水区等 ogr2ogr -f GeoJSON -t_srs EPSG:4326 \ -where CITYNAME 南京市 \ nanjing-district.geojson county.shp # 转为 topojson 并简化 topojson -o nanjing-district.topo.json \ --simplify-proportion0.85 \ nanjing-district.geojson注意区县图需注册为nanjing-district与 4.2 节districtMapName一致且nanjing-district.topo.json中每个feature.properties必须含COUNTYNAME字段供 tooltip 显示。4.4 优化市级地图的视觉表现解决文字重叠市级地图因区域小、数量多label 易重叠。启用label.layoutByEdge可强制文字沿边界外侧排列// 在市级地图的 series 配置中加入 series: [{ type: map, map: jiangsu, label: { show: true, fontSize: 12, layoutByEdge: true, // 关键文字贴边显示避免重叠 distance: 5 // 文字距边线距离px } }]5. 避坑指南5 个让 90% 开发者翻车的隐藏雷区与血泪解法ECharts 地图的坑不在代码语法而在数据、坐标、事件三者的隐式耦合。以下 5 条均为某跨平台系统实测踩坑记录每条都附带可立即验证的检测方法。5.1 现象地图渲染后一片空白控制台无报错原因geoJSON 中features的geometry.type为MultiPolygon但 ECharts 5.0 默认只识别Polygon或coordinates数组嵌套过深如四层数组超出 ECharts 解析能力。解决用 geojson.io 打开你的 JSON 文件点击右上角 “Validate” —— 若提示Invalid geometry则用geojson-rewind工具修复环方向npx geojson-rewind1.0.0 input.geojson fixed.geojson5.2 现象点击某省后市级地图显示但严重偏移如江苏移到渤海湾原因省级 JSON 与市级 JSON 的crs坐标系声明不一致或市级 JSON 未声明crs导致 ECharts 误判为平面坐标。解决用文本编辑器打开市级 JSON确认首行含crs: {type: name, properties: {name: urn:ogc:def:crs:OGC:1.3:CRS84}}。若缺失手动添加若为GCJ02必须用proj4库先转换为 WGS84。5.3 现象tooltip 显示undefined或点击后params.name为空字符串原因geoJSON 的features[i].properties中缺少name字段ECharts 默认读取此字段或字段名为CITYNAME但未在registerMap时指定nameProperty。解决注册时显式声明字段映射echarts.registerMap(jiangsu, json, { nameProperty: CITYNAME // 告诉 ECharts 用 CITYNAME 字段作为 name });5.4 现象返回上一级后地图缩放级别异常如全国图显示为放大 10 倍的局部原因ECharts 的geo组件会记忆上一次zoom和center切换地图时未重置。解决每次setOption前手动重置 geo 配置myChart.setOption({ geo: { // 强制重置 zoom: 1, center: [105, 35] // 中国中心点 }, series: [{ map: nextMap }] });5.5 现象在 Vue/React 中动态切换地图首次渲染正常二次切换后地图消失原因组件卸载时未调用myChart.dispose()导致 canvas 实例残留新实例与旧实例冲突。解决在组件beforeUnmountVue或useEffect cleanupReact中// Vue 3 setup onBeforeUnmount(() { if (myChart) { myChart.dispose(); } });6. 进阶技巧用 dataset 实现“同屏对比”与“热力图叠加”让地图真正服务业务做到省→市→区县下钻只是完成了“能用”。要让地图成为业务决策入口还需两招一是支持同一视图对比多维度数据如“江苏省各市 GDP vs 人口密度”二是叠加热力图突出关键指标。ECharts 5 的dataset机制让这事变得极简且无需改写 series 配置。6.1 用 dataset 绑定多源数据避免反复 setOption传统做法是每次切换城市就setOption({ series: [...] })重绘整个图表性能差且动画生硬。dataset允许将数据与地图解耦仅更新数据源即可驱动渲染// 初始化时定义 dataset const option { dataset: [{ id: gdpData, source: [ { city: 南京市, value: 16907 }, // 亿元 { city: 无锡市, value: 14851 }, { city: 徐州市, value: 8457 } ] }, { id: popData, source: [ { city: 南京市, value: 942.3 }, // 万人 { city: 无锡市, value: 749.5 }, { city: 徐州市, value: 902.6 } ] }], series: [{ type: map, map: jiangsu, encode: { tooltip: city, value: value }, datasetIndex: 0 // 绑定 GDP 数据集 }] }; myChart.setOption(option);关键参数encode.tooltip指定 tooltip 显示字段cityencode.value指定颜色映射字段value。切换数据时只需myChart.setOption({ dataset: [{ id: gdpData, source: updatedGdpSource // 替换整个 source 数组 }] });ECharts 自动 diff 并重绘无闪烁性能提升 3 倍以上。6.2 热力图叠加用 scatter 系列模拟“人口热力”效果ECharts 无原生热力图地图但可用scattersymbol模拟且支持coordinateSystem: geo// 在 series 数组中追加 { type: scatter, coordinateSystem: geo, symbol: pin, // 地图标记图标 symbolSize: function(val) { return val[2] / 100; // val[2] 是人口值缩放为图标大小 }, itemStyle: { color: #FF6B6B }, data: [ [118.7674, 32.0415, 942.3], // [经度, 纬度, 人口] [120.2961, 31.5689, 749.5], [117.1848, 34.2618, 902.6] ] }注意经纬度必须为 WGS84 标准且顺序为[lng, lat]非[lat, lng]。数据点需提前用geocoding服务转为坐标或从county.shp的centroid字段提取。6.3 我的实战习惯用 Webpack alias 管理地图资源路径项目中地图文件达 34 个省 300 个市硬编码路径极易出错。我在vue.config.js中配置configureWebpack: { resolve: { alias: { geo: path.resolve(__dirname, src/assets/geo) } } }然后在代码中import jiangsuJson from geo/jiangsu-city.topo.json; echarts.registerMap(jiangsu, jiangsuJson);这样既避免路径错误又让地图资源与业务代码物理隔离上线时可单独 CDN 托管geo目录。最后想说ECharts 地图不是炫技工具而是业务语言的翻译器。我见过太多团队花两周调通地图却因没想清楚“用户到底想对比哪两个指标”而返工。所以每次启动新项目我都会先手绘一张纸左边写用户问题如“哪个市的订单增长最快”右边写地图要呈现的元素如“市级边界 订单增长率色阶 TOP3 市名标注”。这张纸比任何代码都重要。希望帮到你。本文还有配套的精品资源点击获取