做前端可视化的朋友,只要牵扯到地理数据,基本都绕不开 echarts地图。后台监控大屏、城市人流分析、门店选址评估、疫情热力图——凡是带着空间属性的数据,第一反应就是用地图来呈现。但说实话,很多人第一次接触 echarts 地图时都挺懵的:官方示例打开是一个完整的中国地图,代码拷下来却只看到空白;想画一个市级地图,又不知道数据去哪找;好不容易画出来了,标点不显示、tooltip 换行失效、区域点击没反应……一堆问题轮着来。
这篇实战笔记就是来解决这些事的。我会带你从零开始,把 echarts 地图的完整链路打通:底图数据从哪来、GeoJSON 怎么处理、series-map 和 geo 组件怎么选、业务散点怎么叠加、markPoint 标注怎么落地、tooltip 怎么换行、以及最常踩的几个坑怎么排查。内容不搞概念堆砌,全部基于我实际做过的项目经验,示例代码直接拷贝就能跑。适合刚接触 echarts 地图的初学者,也适合想系统梳理一遍地图可视化逻辑的开发者。
1. 地图方案选型:series-map 与 geo 组件怎么选
先说结论:echarts 画地图有两种主流姿势,一种是用series-map系列直接渲染地图,另一种是用geo组件作为地理坐标系底层,再叠加scatter、effectScatter、lines等系列。两者看着都能出图,但底层逻辑和适用场景差别挺大。
1.1 series-map 的适用场景
series-map是最直观的方案,把地图数据直接作为系列配置传入,每个区域对应一份数据,通过itemStyle控制区域样式、label显示区域名、visualMap做颜色映射。这种方案非常适合"区域着色"类需求,比如全国各省的 GDP 分布、各城市的销量对比、各区县的人口密度。
它的核心优势是配置简单,心智负担小。你只需要准备一份国家或地区的 GeoJSON,配置一个map: 'china',告诉 echarts 我要画的是哪个已经注册过的地图,剩下的区域填充、边框、高亮都交给内部处理。对于纯静态展示或只做区域对比的页面,用 series-map 可以很快出效果。
但它也有明显的短板:series-map 在交互层面比较"重",每一个区域都携带了注册时的区域数据,想在上面额外叠加散点、飞线、涟漪特效时,通常还得单独再配置一个 geo 组件或另一套 series,反而绕了远路。
1.2 geo 组件与散点叠加
如果你要做的不是"区域涂色",而是"以地图为底层,展示点位分布、路径流动、热力扩散",那我建议直接用geo组件。geo 组件负责把地图底图画出来,然后你可以自由地在同一个 option 里挂多个系列,通过coordinateSystem: 'geo'把数据点的经纬度映射到地图上。
这套玩法的好处是,底图和业务数据完全解耦。底图只管好看——区域颜色、边框、缩放、旋转这些都在 geo 里配置;散点、标点、连线是业务层,可以随时增删,不会互相干扰。我做过一个门店巡店系统,底图用 geo 固定,员工位置、门店状态、巡检轨迹各用一套 series 叠加,后期迭代极其舒服。
1.3 混合使用的实战建议
实际项目中,我经常是二者搭配的。区域热力分布用 series-map 或 geo 内部控制,点数据用 scatter 系列控制。判断标准就一条:如果你的数据主体是"面",优先 map;如果你的数据主体是"点"或"线",优先 geo。面面结合的场景(比如既想给省份上色,又要在重点城市打点),我会把 geo 作为唯一底图,再同时配置 map 系列和 scatter 系列,让它们共享 geo 坐标系。这种方式配置量稍大,但数据关系最清晰,出图效果也最好。
1.4 ECharts 5.x 的注册机制
这里的"注册"是个高频关键词。无论用哪种方案,你都要先告诉 echarts:我要用一份名字为某标签的地理数据。在 ECharts 5.x 里,注册 API 是echarts.registerMap('china', geoJson),第一个参数是地图名称,和后续配置里的map: 'china'遥相呼应。很多新手把 GeoJSON 加载进来却忘了注册,或者注册名和配置名不一致,导致地图区域一片空白——这个坑排在所有地图问题的第一位,后面我还会展开。
提示:GeoJSON 是一份体积不小的地理边界数据,建议在页面初始化时统一加载注册,不要每次渲染 option 都去请求数据,避免重复网络开销和注册覆盖。
2. 地图数据的获取与处理:GeoJSON 才是灵魂
echarts 本身只负责"画",它并不内置任何地理信息数据。你需要把地图的边界数据喂给它。这份边界数据其实就是 GeoJSON,一种用 JSON 格式描述地理空间信息的标准结构。说人话就是:它用一堆经纬度坐标点,围出了每个省、市、区的轮廓,echarts 拿到这份轮廓就能画出来。
2.1 省级国家级 GeoJSON 获取
对国内开发者来说,最常用的免费数据源是 DataV.GeoAtlas,它提供了全国各省、市、区县级别的 GeoJSON 数据,支持在线预览和直接下载。进入对应页面后,可以按需选择省级、市级、区县级,生成需要的 JSON 文件。这个数据源我用了好几年,稳定性不错,数据结构也规范,是初学者的首选。
另外,阿里云 DataV 还提供了一个在线 GeoJSON 读取接口,基本格式如下:
https://geo.datav.aliyun.com/areas_v3/bound/{adcode}_full.json其中{adcode}是行政区划代码,比如北京市是110000,广东省是440000。用这个接口可以直接请求某个省市的最新边界数据,不用手动下载文件。不过实际项目里,我是建议把 GeoJSON 下载到本地静态资源目录,避免运行环境请求外网导致延迟或不可用。
2.2 市级区块与自定义区域裁剪
有些场景下,你想画的范围不是标准的省界或市界,比如某个产业园、某个商圈、某条河道沿岸。这种自定义区域怎么处理?两种思路:
- 如果你有 GIS 背景,可以用 QGIS 或 ArcGIS 把行政边界裁剪成自定义区域,导出为 GeoJSON,再交给 echarts 使用。
- 如果你不会 GIS 工具,也可以基于已有 GeoJSON 做几何编辑。比如取某个市的数据,然后手动精简 coordinates 数组,只保留你关心的子区域轮廓。这个方法改动量大,只适合轮廓比较简单的小区域。
还要注意一个细节:GeoJSON 里的坐标系统通常是 WGS84 或 GCJ02 等地理坐标,以经纬度表示。echarts 默认直接按经纬度绘制,一般情况下不需要做投影转换。但如果你拿到的数据是平面坐标(比如一些 CAD 导出的数据),就需要先转换成经纬度,否则画出来会严重变形。
2.3 数据结构剖析与最小示例
一个基础的 GeoJSON 结构长这样:
{ "type": "FeatureCollection", "features": [ { "type": "Feature", "properties": { "name": "广东省", "adcode": 440000 }, "geometry": { "type": "MultiPolygon", "coordinates": [ [ [ [113.475, 22.173], [113.477, 22.183] ] ] ] } } ] }注意看properties里的name字段,这个字段是 echarts 渲染 label 时默认展示的区域名称。如果你的业务数据里城市名和这个 name 对不上(比如数据里写的是"广东",GeoJSON 里叫"广东省"),后续做区域数据映射时就会出现匹配不上的问题。我在项目中踩过这个坑,后文会细讲。
2.4 坐标系一定要确认
这是很多从零开始画 echarts 地图的人最容易忽略的点。GeoJSON 数据的坐标系决定了画出来的地图是否"正"。国内项目常用的坐标体系有 WGS84(GPS 原始坐标)、GCJ02(国测局加密坐标)等。如果你用了基于 GCJ02 的底图数据,同时业务点坐标是 WGS84 的 GPS 原始坐标,直接叠加就会出现整个地图向某个方向偏移的诡异现象。
最稳妥的做法是,底图数据和业务点数据来源统一。如果拿到的数据已经是高德或腾讯系坐标,就保持统一;如果一批点位是 GPS 设备采集的原始坐标,就需要先在服务端做坐标转换,再传到前端绘制。这属于测绘层面的基础问题,但直接影响显示效果,提前确认能省去一大把排查时间。
3. 样式定制与交互联动:让地图有业务感
数据到位、坐标系确认干净之后,接下来就是让地图看起来像"产品",而不是一份干巴巴的行政轮廓图。样式的定制和交互的联动是地图可视化项目里最磨人的部分,也是真正拉开新手和熟练工差距的地方。
3.1 区域颜色与高亮状态的配置详解
区域配色的核心是itemStyle和emphasis。itemStyle控制默认状态下的区域填充色、边框色、边框宽度;emphasis控制鼠标悬停或点击选中时的状态。
itemStyle: { areaColor: '#1b2b4a', borderColor: '#79b6ff', borderWidth: 1.5 }, emphasis: { itemStyle: { areaColor: '#2d5a9e', shadowBlur: 10, shadowColor: 'rgba(0, 0, 0, 0.5)' }, label: { show: true, color: '#fff' } }这个配置看着简单,但有两个小技巧值得注意。第一,areaColor不一定是纯色,你可以使用 echarts 的渐变对象——new echarts.graphic.LinearGradient(0, 0, 0, 1, [...]),用渐变填充会让地图在深色大屏上更有层次感。第二,shadowBlur配合阴影色可以在高亮时做出"凸起"的立体感,指定省份像被提起来一样,视觉效果非常讨喜。
3.2 visualMap 实现数据驱动的颜色映射
如果你有数值型业务数据要展示,比如各省销量、各区分单量,这时候别手动为每个区域写死了,直接用visualMap组件。它会把数据区间自动映射到颜色梯度上,数值大的区域颜色深,数值小的颜色浅(也可以反过来),用户一眼就能看出差异。
visualMap: { min: 0, max: 1000, left: 20, bottom: 20, text: ['高', '低'], inRange: { color: ['#e0f3f8', '#74add1', '#4575b4'] } }配置完成后,每个区域的颜色就会根据data里的数值自动变化。这里有个关键点:series-map 的 data 项中的name必须和 GeoJSON 里properties.name完全一致。比如数据项写成{ name: '广东', value: 834 },而 GeoJSON 里叫"广东省",这个省份就会变成透明的灰色,因为它匹配不到任何一个区域。
3.3 label 区域名的显示技巧
区域名的显示默认是label: { show: true },但实际项目里常常需要控制它的显示位置、字体大小和颜色。在地图很大或区域很小的情况下,把每个省的名称都显示出来会产生严重的文字重叠,观感很差。我常用的处理方式是:
- 只在 zoom 到一定级别时显示 label,通过
geo组件的regions配合label.show做条件控制。 - 或者干脆把 label 关掉,用 tooltip 的提示来补充区域名信息,视觉上更干净。
如果有特殊的视觉需求,比如只展示部分重点省份的名称,可以配合data数据项里的label: { show: true }属性做逐区域覆盖。这个细节在官方示例里提得不多,但在真实的大屏设计里几乎是刚需。
3.4 区域点击事件驱动的业务联动
地图不只是用来看的,还得能用。最典型的交互场景是:点击某个省份,下方柱状图自动切换为对应省份的数据,实现地图和其他图表的联动。echarts 通过myChart.on('click', function(params) {...})返回被点击区域的信息。
myChart.on('click', function (params) { if (params.componentType === 'series' && params.seriesType === 'map') { const provinceName = params.name; updateBarChart(provinceName); } });这里有一个容易踩的坑:如果你在一个图表实例里同时挂了 map 系列和 geo 组件,点击事件可能会触发两次(一次是 geo 的点击,一次是 map 系列本身的点击)。解决方式是在回调里判断params.componentType,见上面的代码。这是 echarts 地图联动的经典细节,很多教程都没交代清楚。
4. 完整实战:从零搭建门店分布地图
光讲配置不说实例等于白讲。下面我以一个"门店分布与覆盖范围"页面为例,手把手带你把 echarts 地图从零画出来。目标很明确:页面加载时先渲染一张中国地图,各省份按门店数量着色,重点城市用散点突出,重要门店用 markPoint 打标,鼠标悬停时 tooltip 显示门店详情且自动换行,点击省份能联动展示该省门店列表。这张图覆盖了 echarts 地图 90% 的常见需求,你可以直接把这套结构套到自己的项目里。
4.1 页面骨架与依赖引入
首先准备一个基础的 HTML 页面。如果你用的是 Vue 或 React,核心思路不变,只是把实例挂载放到生命周期函数里。
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>全国门店分布大屏</title> <style> html, body, #map-container { width: 100%; height: 100%; margin: 0; background: #0e1a2a; font-family: 'Microsoft YaHei', sans-serif; } </style> </head> <body> <div id="map-container"></div> <script src="https://cdn.jsdelivr.net/npm/echarts@5.5.0/dist/echarts.min.js"></script> <script src="./geo/china.json"></script> <script src="./map-app.js"></script> </body> </html>我习惯把 GeoJSON 保存为本地 JS 文件,文件里用全局变量暴露数据,比如window.CHINA_GEO = {...}。这样避免异步加载时序问题,脚本一加载完,数据就绪,反手就可以注册地图。
4.2 注册地图与基础 map 系列配置
接下来是核心逻辑。在map-app.js中完成三件事:获取容器、初始化实例、注册地图。
const dom = document.getElementById('map-container'); const myChart = echarts.init(dom); // 假设 geo/china.json 已暴露为 window.CHINA_GEO echarts.registerMap('china', CHINA_GEO); const storeData = [ { name: '北京', value: 156, stores: ['北京朝阳店', '北京海淀店', '北京大兴店'] }, { name: '上海的完整名字', value: 128, stores: ['上海静安店'] }, { name: '广东省', value: 96, stores: ['深圳南山店', '广州天河店'] } ];这里我故意留了一个错误示范:数据里写的是"上海的完整名字",而 GeoJSON 里正常应该叫"上海"。这种不匹配的情况就是我前面警告过的经典问题。真跑起来你会发现"上海"区域没有颜色,数值没有映射上去。修复方式很简单——保持数据名称和 GeoJSON 里properties.name一致。如果你数据源里的名称和标准行政区划名有差异,可以在数据预处理时做一个nameMapping,也可以用 GeoJSON 里的adcode来匹配,按 code 值关联数据比按中文名更稳。
4.3 series-map 与 scatter 叠加的完整配置
接下来同时配置 map 系列(区域着色)和 scatter 系列(重点城市打点),共享同一个 geo 坐标系。
const option = { tooltip: { trigger: 'item', backgroundColor: 'rgba(10, 20, 40, 0.85)', borderColor: '#3d6fb4', textStyle: { color: '#fff', fontSize: 13, lineHeight: 22 }, formatter: function (params) { if (params.seriesType === 'map') { let detailList = ''; if (params.data && params.data.stores && params.data.stores.length) { detailList = params.data.stores.map(function (item) { return '<div>' + item + '</div>'; }).join(''); } else { detailList = '<div>暂无门店数据</div>'; } return params.name + '<br/>门店数:' + (params.value ? params.value : 0) + '<br/>门店明细:' + detailList; } if (params.seriesType === 'scatter') { return '<b>' + params.name + '</b><br/>门店数:' + params.value[2] + '<br/>地址:' + (params.data.address || ''); } return ''; } }, geo: { map: 'china', roam: true, zoom: 1.2, top: 80, bottom: 40, itemStyle: { areaColor: '#1b2b4a', borderColor: '#79b6ff', borderWidth: 1.5 }, emphasis: { itemStyle: { areaColor: '#2d5a9e' }, label: { show: true, color: '#fff' } } }, series: [ { name: '省份门店数', type: 'map', map: 'china', geoIndex: 0, data: storeData.map(function (item) { return { name: item.name, value: item.value, stores: item.stores }; }) }, { name: '重点城市', type: 'scatter', coordinateSystem: 'geo', symbolSize: function (val) { return Math.max(6, Math.min(24, val[2] / 10)); }, label: { show: true, formatter: '{b}', position: 'right', color: '#ffd666' }, itemStyle: { color: '#ffd666', shadowBlur: 6, shadowColor: '#ffd666' }, data: [ { name: '深圳', value: [114.0579, 22.5431, 80], address: '南山区科技园' }, { name: '杭州', value: [120.1551, 30.2741, 65], address: '余杭区未来科技城' }, { name: '成都', value: [104.0665, 30.5723, 42], address: '高新区天府大道' } ] } ] }; myChart.setOption(option);这套配置跑起来,你就能看到一张深蓝底色的中国地图,各省份根据门店数呈现不同深浅的颜色,三个重点城市上带有金色圆点和城市名,悬停能看详细信息,还能拖拽缩放。整个页面已经是"半成品大屏"的水平了。
4.4 tooltip 自动换行与富文本排版
很多人问 echarts tooltip 怎么换行,其实很简单:formatter函数里返回值拼接<br/>就能换行,或者返回一个数组,echarts 会自动把数组每一项渲染为独立一行。
formatter: function (params) { return [ '<b>' + params.name + '</b>', '门店数:' + params.value, '区域负责人:张伟' ].join(''); }如果你希望 tooltip 内容更丰富,比如加小标题、分割线、图片链接,字符串拼接 HTML 是大杀器。但要注意,默认的 tooltip 宽度是自适应文本的,如果内容有很多行,建议配置extraCssText增加内边距,或者设置confine: true防止 tooltip 超出画布被截断。这两个参数在官方文档里属于冷门项,但在大屏项目里几乎天天用。
4.5 markPoint 标注核心门店
还有一个高频词是 "echarts map 里的 markPoint"。如果只是单纯想在某个经纬度位置打个标,用 scatter 就够了;但如果你要展示的是"这个位置有一个非常重要的事件/门店/设备",markPoint 更合适。markPoint 可以挂在 map 系列上,也可以挂在 geo 坐标系下的散点系列上,我用后者更顺手。
series: [ { name: '核心门店标注', type: 'effectScatter', coordinateSystem: 'geo', symbol: 'pin', symbolSize: 28, label: { show: true, formatter: '{b}', position: 'top', color: '#fff' }, itemStyle: { color: '#ff4d4f' }, data: [ { name: '总部旗舰店', value: [116.3974, 39.9093, 320], address: '北京市东城区' } ] } ]用effectScatter加symbol: 'pin',配合波纹特效,视觉效果就和"标注点"完全不同——它像是在地图上插了一根图钉,并且有脉冲扩散动画,非常适合突出核心位置。注意 value 数组里前两位是经纬度,第三个可以塞任意业务数值,整个数组会在 tooltip 里通过params.value[2]取出来。这是 echarts 地图里最常被忽略的"传数"技巧。
4.6 窗口自适应的细节
最后补一个被问了很多次的点:浏览器窗口大小变化时,地图如何自适应。一行代码搞定。
window.addEventListener('resize', function () { myChart.resize(); });但要注意,如果地图容器在页面初始渲染时是隐藏状态(比如在 Tab 里),直接 init 会出现宽度为 0 的异常,图表画不出来。这种场景要等容器显示后再调用myChart.resize(),或者用setTimeout、nextTick延迟初始化。这是我做了多个管理系统后总结出的血泪经验。
5. 高频问题与排查技巧实录
地图可视化项目做多了,你会发现踩坑的内容高度相似。我把这几年在 echarts 地图上遇到的高频问题整理成了一张速查表,顺手附上排查思路,希望帮你少走弯路。
| 问题现象 | 主要原因 | 解决方案 |
|---|---|---|
| 地图区域空白或只有边框 | GeoJSON 未注册,或注册名与配置名不一致 | 确认registerMap已调用,且map名完全一致 |
| 区域不显示数值颜色 | data 的 name 与 GeoJSON 的 properties.name 不匹配 | 统一名称,或用 adcode 等唯一标识做映射 |
| 散点/标点不显示 | 系列未设置coordinateSystem: 'geo' | 在 scattter / effectScatter 系列配置中加上该字段 |
| 标点位置偏了 | 经纬度坐标系不一致 | 确保底图与业务点坐标统一,提前做好坐标转换 |
| tooltip 不换行 | formatter 未返回 HTML 字符串 | 拼接<br/>,或返回数组 |
| tooltip 被画布截断 | tooltip 超出图表容器边界 | 设置confine: true或调整extraCssText |
| 饼图 labelLine 末尾小圆点偏移 | 饼图配置中labelLine属性细节问题 | 使用labelLayout调整端点和标签间距 |
| pxtorem 对 echarts 没起到效果 | echarts 使用 canvas 绘制,不响应 css 字体转换 | 直接在 echarts 配置中控制字体大小,不依赖全局 rem |
5.1 地图空白和名称匹配的排查顺序
遇到地图空白,我的排查顺序是:打开浏览器控制台,看有没有报Map china not exists之类的错误。如果没有报错但地图依然空白,再在调试面板手动打印一下echarts.getMap('china'),看返回是否为空对象。这一步基本能定位 90% 的问题:要么没注册,要么注册时传入的 GeoJSON 是空数据,要么注册名写错了。这三个问题在实际中出现的频率排序大约是 5:3:2,前两个最多。
名称匹配问题则要细心一点。我建议在数据接入前先写一段预处理脚本,把业务数据里的行政区划名统一成 GeoJSON properties 里的行政区划标准名称。如果数据量很大,可以只保留有数据的省份名称,用一个映射表做转换。总之不要让"广东"和"广东省"这种差异进入运行时,等渲染出来再发现就晚了。
5.2 pxtorem 与 ECharts 的怪异拉扯
热词里有一条是"pxtorem 对 echarts 没起到效果 vue3"。这个现象很典型:某些项目里全局配置了 postcss-pxtorem,页面上的字体、间距都自动转 rem,但 echarts 里的字号、图表尺寸纹丝不动。原因很简单,echarts 的绘制是在 canvas 上进行的,字体大小和图形尺寸是在setOption时被写进 canvas 内部的,和 CSS 的 rem 转换完全不沾边。echarts 图表本身只是一个 el 节点,它的宽高由外层容器决定,容器如果设置了 rem,宽度是会跟着变的,但图表内部所有文本、图形参数都来自配置对象。
解决方案分两种:一是如果你需要 echarts 的字体跟随视口缩放,就得自己监听 resize,按比例动态调整textStyle.fontSize之类的配置,再重新 setOption;二是干脆把 echarts 当作局部模块,保持固定像素值,不参与全局 rem 转换。对大多数大屏项目来说,第二种更省心,因为大屏的缩放通常由整体页面 transform 控制,不需要 echarts 内部逐项自适应。
5.3 折线图 x 轴刻度与地图联动的共性问题
"echarts 折线图 x 轴刻度"这个词也经常和地图一起出现,因为大屏页面基本是地图配折线的搭配。折线图 x 轴刻度异常最常见的原因是数据里的 x 轴值是字符串而非数值,或者时间字符串格式不统一,导致 echarts 把它当成类目轴处理而表现异常。排查方法也很直接:把 x 轴数据的JSON.stringify打印出来,检查是否有多余空格、日期格式不统一、null 值混入。
另外一个和地图相关的点是,折线图和地图共用一个 resize 事件时,如果有多个图表实例,一定要逐个resize(),不要只处理最后一个实例。我在做数据大屏时就踩过这种低级错误:窗口缩放后地图正常、折线图不动,检查发现循环里写错了实例变量,把同一个myChart覆盖了多次。图表实例当页面里超过一个时,建议用数组或对象统一管理。
5.4 数据更新后地图不刷新的处理
项目做到后期,地图数据通常是动态请求的。很多人会把新请求到的数据直接赋给 data,以为 echarts 会自动更新,结果发现地图纹丝不动。原因在于setOption默认是合并模式,对于 map 系列的名称和值,如果新旧数据结构不同,合并策略可能不触发完整更新。最稳妥的方式是使用myChart.setOption(option, true),第二个参数传true表示完全覆盖旧配置,强制重新计算渲染。也可以用myChart.clear()后再 setOption,但要记得重新注册地图(clear 不会清掉注册数据,不用担心)。
我个人的习惯是:地图数据变化时,尽量只更新变化层,比如只改scatter系列的 data,通过myChart.setOption({ series: [{ data: newData }] })局部更新,这样性能更好,也不会影响底图样式。这个技巧在数据实时刷新的大屏里非常有用。
5.5 关于地图数据时效性的提醒
最后补充一个比较隐蔽的问题:GeoJSON 数据是有"时效性"和"版本"的。行政区划发生过调整的区域,比如县级市改区、新区划成立,旧版本 GeoJSON 里的边界和名称可能和新数据对不上,导致某些区域画不出来或名称漂移。所以每次上线前,我建议重新确认一下地图数据的版本,最好能标注获取日期。尤其是有民政区划调整的年份,别等到业务方反馈"某市的位置怎么是空的"才回头查数据。
6. 做地图可视化的几点个人心得
从零开始把 echarts 地图跑通并不难,真正难的是把地图做得"像产品"。配色要克制、层级要清晰、交互要给反馈、数据要有效。我第一次做全国热力图时,把每个省都涂得花花绿绿,结果业务方看了一脸嫌弃,后来才明白,地图的首要任务是让读者一眼看到"差异",而不是把每个区域都打扮得花枝招展。颜色深浅要与业务数值强度对应,能不用渐变就不用,除非视觉稿要求。
还有一点是数据的预处理前置化。现在我做任何带地理信息的项目,都会先写一道清洗脚本,统一行政区划名称、清洗异常经纬度、剔除超出地图范围的数据点。这个过程虽然繁琐,但能把 80% 的线上问题提前消灭在数据层。等你经历过一次"地图上某座城市凭空消失了"的线上事故,就明白我说这话的含金量了。
另外,如果你打算长期做 echarts 可视化,建议把常用的地图数据、配色主题、基础配置沉淀成自己的工具库。不同项目之间直接复用,能省下大量重复工作。我自己的电脑里就存了一份全国省市县的 GeoJSON 备份、一套深色大屏地图主题、以及封装好的 Vue 和 ECharts 地图组件,每次新项目打开就能开工,这才是从零开始画 echarts 地图之后真正应该沉淀下来的东西。