尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

省市县三级地图JS文件获取与ECharts地图下钻实战指南

省市县三级地图JS文件获取与ECharts地图下钻实战指南 简介一套覆盖全国省、地市、区县三级的ECharts地图JS文件适合前端开发者和数据分析师在Web端展示中国区域数据。由于官方已不直接提供地图文件这份资源能弥补数据获取空缺配合ECharts的map配置即可实现区域着色、视觉映射、点击联动等交互。压缩包共343个js文件、25.79MB文件按行政区划代码命名便于查找使用。可快速搭建不同粒度的地图图表并绑定业务数据形成分级统计、热力对比等效果适用于政务数据可视化、电商区域分析等场景。已有2177人学习下载可省去手工整理地理坐标数据的麻烦。做省级下钻被地图JS卡了两天我整理了一份省市县三级地图文件的完整用法先说自己踩的坑。去年接了一个可视化大屏项目省级数据都正常渲染了结果拿给业务方一看人家说光看省份没用我要点进地市看区县数据。我当时第一反应是这不就是echarts地图点击下钻嘛结果一做才发现真正麻烦的不是下钻逻辑而是地市、区县的地图JS文件到底去哪找。我在网上翻了很久的答案搜echarts 地市 地图js出来的资源五花八门有的失效有的只有几个省份还有的要付费下载。后来花了好几天把获取、注册、下钻、性能这些链路都趟通了。这篇文章就把这次的完整经验整理出来涉及到全国、地市、区县三级地图JS文件的获取渠道、引入方式、下钻实现、visualMap分段配色的坑以及大屏场景的性能优化都有对应的代码和思路供有同样需求的朋友参考。1. 为什么echarts官方JS文件里没有地市区县数据echarts官方包里的地图数据相当有限。npm安装echarts/echarts之后echarts/map/json/china.json提供的是全国34个省级行政区的边界数据再往下走地市级、区县级的地图数据完全是没有的。这不是echarts偷懒而是定位决定的。echarts本质上是图表组件库地图只是它众多图形类型中的一种官方不可能像专业GIS平台那样去维护全国所有省、市、区县边界的GeoJSON数据更别说行政区划还经常调整撤县设区、新区设立、合并拆分维护成本非常高。所以要拿到省市县三级地图数据本质上需要自己找GeoJSON数据源。而所谓地图JS文件其实大部分情况下就是把GeoJSON封装成了JS模块或者干脆直接用JSON格式动态加载。明白了这个前提你就知道为什么网上搜到的资源总是残缺不全了。因为大家都是从不同渠道抓下来的有的只更新到了某个年份有的只覆盖了部分省市。后面的所有操作都建立在先把数据源搞定这个基础上。2. 三个靠谱的地图数据源服务质量差距很大搜了一圈之后我把能用、好用的数据源梳理成了三类各有各的优缺点。数据源覆盖层级更新频率获取方式适合场景DataV.GeoAtlas阿里云省、市、区县全部覆盖频繁更新基本跟着行政区划走在线访问单个GeoJSON也支持打包下载大部分业务项目首选高德开放平台行政区划API省、市、区县含边界经纬度高德地图数据更新调API拿数据编码为GeoJSON已经在用高德地图的项目GitHub开源项目如echarts-mapjson省市为主区县覆盖情况参差取决于维护者仓库下载或npm安装临时用、离线环境2.1 DataV.GeoAtlas效率最高的选择DataV.GeoAtlas的数据组织方式是访问链接直接返回单个区域的GeoJSON。比如你要获取某个省份的完整边界访问一个带行政区划编码的接口就能拿到JSON数据包含了省级边界和子级城市的边界数组。你只需要在前端通过fetch或axios请求下来按需注册。这个数据源的另一个优势是区县级数据质量比较稳定。我在项目里用到了浙江省的区县级数据边界基本和实际吻合用在业务场景里足够了。唯一需要注意的是不同年份的数据可能存在细微差异建议在项目里固定数据版本不要每次发布都去拉最新的。2.2 高德开放平台的行政区划API如果你的项目已经集成了高德地图相关能力可以直接调它的行政区划API通过subdistrict参数可以递归获取下级行政区划信息。它返回的数据里带polyline边界坐标你可以在前端拼成GeoJSON格式供echarts使用。不过这个方案有个小坑高德返回的边界坐标精度和DataV的数据存在差异某些邻近区域会有轻微重叠echarts渲染时可能看到细微的边界毛刺。如果你对边界精度要求不高可以接受如果要做正式的商用大屏还是优先用DataV。2.3 GitHub开源项目的注意点GitHub上确实有很多echarts 地图json类的仓库有的把全国省市县都整理成了单个文件用起来很直接。但我体验下来的经验是这类仓库的data时效性差异很大有的区县数据还是2018年前的很明显是半弃坑状态。建议是可以用但使用前务必抽查几个区县边界和你实际掌握的地图对比一下确认没问题再上线。提示无论你选哪个数据源项目里一定要保留一份下载好的静态JSON/JS文件而不是每次都去请求外部接口。外部接口到线上环境经常有跨域、限流问题放在自己服务器上最稳妥。3. 把地图JS文件在项目里正确加载起来关于加载这一步很多教程还在教用script标签引用一个全局的china.js然后echarts.registerMap(china, window.china)。这种做法在老的jQuery时代还行放在现在的前端工程化项目里并不合适。我的建议是把地图GeoJSON当作普通的模块依赖处理用固定文件名放在src/assets/map/目录里然后在页面组件里import或者用接口动态获取。下面以Vue3 ECharts 5为例写一个省市地图页面的最小示例。3.1 静态引入单省地图// provinceMap.vue import * as echarts from echarts; import zhejiangJson from /assets/map/zhejiang.json; const chart echarts.init(document.getElementById(mapChart)); echarts.registerMap(zhejiang, zhejiangJson); const option { tooltip: { trigger: item, formatter: (params) ${params.name}br/数值${params.value || 0} }, visualMap: { min: 0, max: 1000, left: left, top: bottom, text: [高, 低], inRange: { color: [#e0f3f8, #abd9e9, #74add1, #4575b4, #313695] } }, series: [{ type: map, map: zhejiang, roam: true, label: { show: true, fontSize: 10 }, data: [ { name: 杭州市, value: 800 }, { name: 宁波市, value: 600 } ] }] }; chart.setOption(option);注意registerMap接收的第二个参数是GeoJSON对象不是字符串。如果你通过接口拉取的是JSON文本记得先JSON.parse。3.2 动态加载全国区县数据的方案如果项目的诉求是全国地图上展示到区县级一次性把全国三千多个区县的GeoJSON全注册进echarts页面会明显卡顿而且文件体积也不小。这种情况下我建议换一种思路初始化的时候只注册全国的省级边界数据等用户点进去某个省份再按需加载这个省份的市级/区县级数据。// 按需加载某个省份的区县级GeoJSON async function loadProvinceDetail(provinceCode) { const res await fetch(/map-data/${provinceCode}.json); const geoJson await res.json(); echarts.registerMap(provinceCode, geoJson); // 更新图表option注意切换地图类型 chart.setOption({ series: [{ type: map, map: provinceCode }] }); }这个按需加载的思路既节省了首屏加载资源也避免了初始化时注册大量无用地图数据导致的卡顿。如果你确实需要全国区县一次性展示可以研究一下GeoJSON的简化抽稀算法减少边界坐标点数量。区县级的GeoJSON文件通常有几百KB甚至上MB抽稀之后能压到几十KB对大屏渲染影响非常明显。4. 省级到市、市到区县的下钻交互与名称映射地图数据能够正常渲染之后下钻的核心逻辑其实很简单监听click事件根据点击区域的名称切换到对应的下级地图。真正容易出问题的是两个地方名称映射和地图的重复注册。4.1 click事件实现下钻chart.on(click, (params) { const name params.name; // 省级切换到市级 if (currentLevel province) { const provinceCode provinceCodeMap[name]; if (provinceCode) { loadProvinceDetail(provinceCode); currentLevel city; } } });这里的关键是provinceCodeMap这个映射表。GeoJSON里的name属性不一定是标准的北京市浙江省格式它可能叫北京浙江也可能叫北京市浙江省不同数据源格式不一样。我的经验是在注册地图之前先做一次数据清洗把所有的name统一成带省/市/区后缀的格式或者统一去掉后缀保证和业务数据里的名称一致。4.2 名称不一致的坑业务数据的名称往往和地图的name对不上。比如业务数据里写的是杭州地图里是杭州市这个时候匹配不上图例上的数值就是空的。处理方法有两种第一种是改数据用地图里的标准名称做映射转换。第二种是改GeoJSON遍历所有区域把properties.name统一替换成业务侧的名称。我倾向于用第二种因为手工维护映射表某些时候会漏项等上线了才发现某个区县是空白就尴尬了。function normalizeGeoName(geoJson, nameMap) { geoJson.features.forEach((feature) { const oldName feature.properties.name; if (nameMap[oldName]) { feature.properties.name nameMap[oldName]; } }); return geoJson; }4.3 返回上一级大屏下钻一般都需要返回全国按钮。在echarts里返回上一级不需要销毁整个实例只需要重新注册全国地图数据然后用setOption切换回全国的地图类型。如果你用同一个chart实例来回切换建议在切换之前chart.clear()避免残留上一次的系列配置。function backToParent() { if (currentLevel city) { echarts.registerMap(china, chinaJson); chart.setOption({ series: [{ type: map, map: china }] }); currentLevel province; } }5. visualMap分段配色的坑从9段变成10段热搜词里频繁出现echarts地图9段图变10段图echarts visualmap pieces这个点确实是大屏地图的高频问题。原因在于echarts的visualMap有两种模式continuous连续型和piecewise分段型。大屏地图场景下由于数值分布经常不均匀连续型配色往往把大部分区域渲染成一个颜色分段型才能合理区分。分段型配色的核心是pieces数组但很多人对边界值理解有偏差导致我明明设置了9段实际渲染出来10段的情况。visualMap: { type: piecewise, pieces: [ { min: 0, max: 100 }, { min: 100, max: 200 }, { min: 200, max: 500 }, { min: 500, max: 1000 } ] }这里的问题在于max: 100和下一段的min: 100边界重叠数值正好等于100的数据会被算进两段里。echarts的实际处理是优先匹配第一个符合条件的piece所以不会报错但你在图例上会看到段数比预期多或者某段人数特别少。正确的做法是把每段设置成左闭右开或者直接用lt、lte、gt、gte这些更明确的比较符号visualMap: { type: piecewise, pieces: [ { gte: 0, lt: 100, label: 0-100 }, { gte: 100, lt: 200, label: 100-200 }, { gte: 200, lt: 500, label: 200-500 }, { gte: 500, label: 500以上 } ] }如果你要动态生成分段比如根据所有数据里的最大值平均切成9段生成算法里也注意最后一段要包含最大值同时避免前面的段把最大值提前吃掉。这类边界问题排查起来最费时间因为视觉上很难发现只有点开tooltip才能看到数值落入的区间不对。6. 给某些市标记数量散点图叠加地图的玩法热搜词里还有一个高频需求echarts地图上怎么给某些市标记数量。这不是在地图系列上直接改数据能实现的而是要用地图 散点图scatter组合的方式。series: [ { type: map, map: zhejiang, data: provinceData, roam: true }, { type: effectScatter, coordinateSystem: geo, data: cityPoints, symbolSize: (val) Math.max(val[2] / 1000, 5), label: { show: true, formatter: (params) ${params.value[2]} } } ]cityPoints数组里的每一项要包含[longitude, latitude, value]这种结构。经纬度数据可以在地图数据里提取也可以用高德/腾讯地图的坐标拾取器手动维护。这套组合玩法还可以继续扩展比如结合热搜词里提到的echarts-gl在geo3D或map3D上叠加scatter3D做立体的3D地图散点效果。3D地图视觉效果确实强但性能开销也大普通大屏机器跑起来会掉帧。我的建议是如果确认目标设备显卡还行、项目展示需求确实要求3D效果再去研究echarts-gl的geo3D map3D scatter3D组合方案如果只是要展示数据分布2D地图 effectScatter的性价比高得多。7. 大屏场景的加载性能优化经验地图文件在可视化大屏里是绝对的体积大头。全国省级GeoJSON压缩后大约200-400KB一个省份的市级数据几十到几百KB不等区县级数据更夸张一个大省有好几MB。如果首屏全部加载页面白屏时间会很难看。我的做法是分三层处理第一层首屏只加载全国省级数据。大屏一般一打开就是全国总览这时候只需要省级边界。第二层只预取当前可见省份的下级数据。用户大概率会点几个业务重点省份其他不常用的省份不用提前加载。第三层对于区县级数据上线前做一轮抽稀。GeoJSON里的coordinates数组往往是精度很高的坐标点对于展示型大屏来说完全可以简化。用简单的Douglas-Peucker抽稀算法把坐标精度从6位小数降到3-4位肉眼完全看不出差异文件体积却能减少一半以上。// 简化坐标精度降低体积 function simplifyPrecision(geoJson, digits 3) { const factor Math.pow(10, digits); geoJson.features.forEach((feature) { const coordinates feature.geometry.coordinates; // 需要深度遍历所有坐标层级这里省略具体遍历逻辑 // 核心操作coord Math.round(coord * factor) / factor }); return geoJson; }另外地图JS/CDN资源的加载尽量放到首屏之后再执行不要在index.html里用同步script阻塞页面启动。8. 一个反复被踩的坑别在地图数据上做丘丘式冒险最后聊一个我观察到的现象。网上很多人分享自己的全国地图数据包时喜欢把JSON和JS混着放弄一个冷不丁的加密压缩版出来看起来好像功能很全实际上数据内部互相打架导致排查问题的时间比解决问题的时间还长。我现在的习惯很简单所有地图数据一律统一为.json格式的GeoJSON放在固定目录里通过registerMap统一加载不做任何形式的动态拼接。如果你有多个页面要用到同一份地图数据用一个单例模块统一管理而不是每个页面都自己fetch一遍。数据源建议固定一家不要今天用DataV明天用高德的API不同源的数据边界、名称、坐标精度完全不一样混用必然出问题。万一真遇到了这个区域边界很奇怪的情况优先检查是不是混用了不同时期的数据版本。如果你需要在一个页面里展示多个地图实例比如全国地图和省份地图同时显示注意每个echarts实例的id要区分开并且各自的registerMap名称不能冲突否则第二个实例会覆盖掉第一个实例的地图定义这也是一个很容易被忽略的隐性bug。这次的项目做完之后我自己也把常用的地图JSON文件归档了一份到内部公共资源里以后新项目直接引用不用再去翻各种来源了。做地图可视化这行的其实很多时间都花在了数据清洗和资源整合上把这些基础工作做扎实了后续的图表演示才能真正跑得快、看得清。本文还有配套的精品资源点击获取
返回列表