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

资讯详情

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

ECharts地图3D效果实战:map3D与geo3D配置详解与踩坑指南

ECharts地图3D效果实战:map3D与geo3D配置详解与踩坑指南 做数据可视化大屏这几年平面地图用得久了总感觉少点味道。尤其当领导站在大屏前指着一片平平整整的蓝色色块说“能不能让它立体一点有点科技感”的时候你就知道单纯靠调色和阴影已经糊弄不过去了。Echarts 的地图模块本身只能画二维平面但通过 ECharts GL 扩展我们完全可以把地图“抬”起来做出带光照、带海拔、能旋转的 3D 效果。这篇文章就围绕“如何让地图显示出3d感”这个最朴素的需求把我从选型、配置到踩坑的完整过程写出来给正在做地图可视化、大屏项目、数据展示系统的朋友一条可以直接抄作业的路线。1. 先搞清楚Echarts 的“3D感”到底有几种实现路线地图要显示 3D 感第一步不是写代码而是先想明白你要的是“真 3D”还是“伪 3D”。这两者难度不一样效果差别也很大。我最早做地图美化时直接用shadow、gradient和view.rotate做视觉欺骗后来需求升级才切到 ECharts GL 的 map3D 组件。1.1 路线一直接用 ECharts GL 的 map3D 组件map3D是 ECharts GL 提供的三维地图组件本质上是一个把地图矢量数据映射到三维球面或平面上的渲染器。它支持光照、海拔、视角旋转、拖拽、缩放效果最接近真实的 3D 地图。你只需要引入echarts-gl扩展库然后在series里配置一个type: map3D的系列即可。option { series: [{ type: map3D, map: china, shading: lambert, itemStyle: { color: #2a6bbf, opacity: 0.9, borderWidth: 1, borderColor: #fff }, label: { show: true, textStyle: { color: #fff, fontSize: 10 } }, emphasis: { label: { show: true }, itemStyle: { color: #ffd700 } }, viewControl: { autoRotate: true, distance: 120, alpha: 40, beta: 20 } }] }这种方案的优点是代码量少效果直观光照和材质由引擎自动计算适合快速出效果。缺点是需要额外安装echarts-gl体积增加约 1MB 左右gzip 后约 300KB而且对低端设备渲染压力较大。1.2 路线二用 geo3D 自定义曲面实现“假海拔”geo3D本身是三维地理坐标系组件它可以承载多个系列类型比如散点图、柱状图、飞线图。你可以把geo3D当成一个“三维画布”而map3D只是这个画布上一种特殊的地图载体。如果你想在地图上叠加柱子、飞线、标签通常的做法就是先配置一个geo3D再添加对应的 3D 系列。option { geo3D: { map: china, shading: realistic, environment: #111, light: { main: { intensity: 1.2, shadow: true }, ambient: { intensity: 0.3 } }, viewControl: { autoRotate: false, alpha: 50, beta: 0 } }, series: [{ type: bar3D, coordinateSystem: geo3D, data: [...] // 坐标数据需要转换成 [lng, lat, value] }] }这种方案适合需要叠加业务数据的场景比如全国各省销量柱子、物流飞线、城市点位等。但要注意geo3D的坐标系统跟平面地图的经纬度坐标系不一样数据要经过转换否则位置对不上。后面我会专门讲这个坑。1.3 路线三纯平面地图“伪 3D”美化零依赖也能做如果你不想引入额外的库又想有一点立体感可以在平面地图上动手脚。比如把地图整体旋转一定角度rotate加多层shadow用渐变模拟光照或者在地图底部画一个“底座”色块再配合地图区域的itemStyle.shadowBlur制造悬浮效果。series: [{ type: map, map: china, roam: true, label: { show: true }, itemStyle: { areaColor: #1a5bb5, shadowColor: rgba(0, 0, 0, 0.5), shadowBlur: 20, shadowOffsetY: 15 }, emphasis: { itemStyle: { areaColor: #ffd700 } } }]这种方案在视觉上能骗过部分人但本质上是“假 3D”无法旋转视角也没有光照变化。适合那种只需要在地图上突出层次感、不太需要交互旋转的大屏场景。三种路线怎么选我个人的判断标准是如果只是静态展示选路线三如果要有真实的立体旋转和光照选路线一如果要在 3D 地图上叠加业务数据比如柱子、飞线、散点选路线二。下面我以map3D为主线把完整配置和踩坑经验详细展开。2. 实操用 map3D 让中国地图立体起来的完整配置先说环境。ECharts 地图 3D 效果的底层是 WebGL所以需要浏览器支持 WebGL。我用的是 ECharts 5 echarts-gl2.0 的组合Vue/React 项目里一样能用。安装过程很简单npm install echarts echarts-gl然后在项目入口引入import * as echarts from echarts; import echarts-gl;如果你用的是 CDN 方式记得先引echarts.min.js再引echarts-gl.min.js顺序不能反。2.1 注册地图数据与基础环境准备map3D和普通的map一样需要先注册地图 JSON 数据。这个 JSON 可以是 China、World也可以是某个省份、城市。注意map3D不认 geoJSON 的FeatureCollection直接传参需要先通过echarts.registerMap(china, chinaJson)注册。import chinaJson from ./china.json; echarts.registerMap(china, chinaJson);如果你拿到的地图 JSON 不是标准格式比如用高德或百度导出的最好先用工具转换成标准 GeoJSON。map3D对地图边界的精度要求比较高坐标如果出现小数点丢失边界会闪烁或者缺块。重点说一个很多人忽略的点地图 JSON 里的crs属性。map3D默认用的是EPSG:4326经纬度坐标如果你的地图数据是EPSG:3857Web Mercator或者投影坐标渲染出来会严重变形。我在项目里遇到过一次地图拉伸成冬瓜形排查了半天才发现是数据源问题。所以注册前务必检查crs如果不是默认的需要先转换。2.2 map3D 的核心配置项逐行拆解下面给出一个我实际项目里用过的完整配置配合注释说明每个字段的作用。option { tooltip: { formatter: function(params) { return params.name ? params.name (params.value || 0) : ; } }, visualMap: { min: 0, max: 1000, seriesIndex: 0, inRange: { color: [#1a4a82, #2a6bbf, #4fa3e0] }, textStyle: { color: #fff } }, series: [{ type: map3D, map: china, shading: lambert, // 材质类型lambert / realistic boxHeight: 10, // 地图拔高高度数值越大海拔越高 instancing: true, // 开启实例化渲染优化性能 pickInterval: 100, // 拾取精度值越大渲染越快但点击检测越粗糙 label: { show: true, distance: 3, // 标签距离地面高度 textStyle: { color: #fff, fontSize: 12, fontFamily: Arial, fontWeight: bold } }, itemStyle: { color: #2a6bbf, opacity: 1, borderWidth: 1, borderColor: #8ed3ff }, emphasis: { label: { show: true, color: #ffd700 }, itemStyle: { color: #ffd700 } }, light: { main: { intensity: 1.2, // 主光源强度 shadow: true, // 是否产生阴影 alpha: 35, // 光源垂直角度 beta: 30 // 光源水平角度 }, ambient: { intensity: 0.4 // 环境光强度 } }, viewControl: { autoRotate: true, // 自动旋转 autoRotateSpeed: 5, // 旋转速度 distance: 100, // 视角距离控制地图大小 alpha: 50, // 俯仰角垂直视角 beta: 20, // 方位角水平视角 minAlpha: 20, maxAlpha: 90, panSensitivity: 1, // 平移灵敏度 zoomSensitivity: 1 // 缩放灵敏度 }, data: [] // 各省份数据格式 [{name:北京, value: 92}, ...] }] };shading字段值得多说两句。它只有两个可选值lambert和realistic。lambert是朗伯材质计算简单性能好颜色比较柔和realistic是物理材质会考虑反射、折射、环境映射效果更逼真但需要配合environment环境贴图使用否则看起来会死黑。我一般用lambert加高光就能满足 95% 的展示需求realistic主要用来做那种镜面质感极强的大屏需要配一张深色环境贴图。2.3 光照、海拔、视角的联动调参技巧很多人调 3D 地图习惯一个个参数瞎试效率很低。我总结了一套联调顺序先调海拔再调光照最后调视角。调海拔boxHeight决定地图拔高的高度不是越大越好。如果数值太大地图会像一块块高墙边界交叉处会出现遮挡立体感反而变差。我一般先用 5 或 10 做底再根据实际视觉效果微调。如果地图区域很多建议用小数值比如 3~8让各个区域之间还能看到高低差。调光照lambert材质需要至少一个主光源否则地图是平的。alpha控制光线从哪个角度从上往下照beta控制水平旋转。默认的alpha: 35, beta: 30是安全值。想让地图有明显的明暗对比可以把alpha调小到 20 左右让光源更贴近地平线暗面会更多。想整体亮一些把ambient提高到 0.6。调视角alpha是俯仰角我一般控制在 40~60 之间太低会看到地图背面太高就变成俯视平面图失去立体感。distance控制相机距离它会和alpha联动——当你缩小alpha时地图在视觉上会变扁需要适当调整距离保持画面饱满。一个比较实用的口诀海拔决定层次光照决定立体视角决定冲击。三者协调好地图自然就有了“3D 感”。3. 进阶给 3D 地图叠加散点、飞线、柱状图让大屏活起来地图只有色块和标签是不够的。真正撑起大屏内容的是那些在地图上飞来飞去的数据线条、拔地而起的柱子、闪亮亮的城市点位。要在 3D 地图上叠加这些元素需要用到geo3D坐标系和bar3D、scatter3D、lines3D等系列类型。3.1 散点与柱状图在 3D 地图上的坐标换算geo3D的坐标系默认是经纬度。但echarts-gl在渲染时会把经纬度转换成三维坐标转换比例是固定值。当你在series里写数据时坐标格式是[lng, lat, value]其中 value 会映射到柱子的高度bar3D或者散点的大小scatter3D。一个常见的错误是直接拿普通 map 的散点数据丢进 bar3D导致柱子飘在地图外。正确的数据格式如下data: [ [北京市, 116.4, 39.9, 1200], [上海市, 121.5, 31.2, 1800], [广东省, 113.3, 23.1, 2300] ]注意bar3D支持[name, lng, lat, value]四元组也支持[lng, lat, value]三元组。如果 value 很大柱子会穿透地图出现“通天柱”效果需要配合barSize和bevelSize控制粗细。3.2 飞线动画的 series 配置飞线是 3D 地图大屏最常用的元素。它通过lines3D系列绘制配合effect控制光点动画。下面是一个从多个城市飞向北京的配置片段series: [{ type: lines3D, coordinateSystem: geo3D, effect: { show: true, period: 4, trailWidth: 2, trailLength: 0.4, trailOpacity: 0.8, trailColor: #4fd2ff }, lineStyle: { width: 1, color: #4fd2ff, opacity: 0.8, curveness: 0.3 }, data: [ { coords: [[121.5, 31.2], [116.4, 39.9]] }, { coords: [[113.3, 23.1], [116.4, 39.9]] }, { coords: [[114.1, 22.5], [116.4, 39.9]] } ] }]curveness控制飞线的弯曲程度。数值越大线拱得越高。在 3D 地图上飞线默认在同一个海拔高度如果想让线从地面向上弧线飞行需要配合altitude或height字段。我常用的做法是设置lines3D的height为 1再配合curveness: 0.3这样飞线会在地图上方一点点不会贴地。3.3 一个完整的大屏示例把上面几个部分组合起来一个简单的 3D 地图大屏配置大概是这样的一个geo3D作为底图一个bar3D放各省数据一个lines3D放飞线一个scatter3D放重点城市点位。三者在同一个option里coordinateSystem都指向同一个geo3D组件的 id。注意geo3D组件和series的 index 关系必须一一对应否则坐标会乱套。option { geo3D: { map: china, boxHeight: 8, shading: lambert, viewControl: { autoRotate: true, distance: 100, alpha: 45, beta: 15 } }, series: [ { type: bar3D, coordinateSystem: geo3D, data: barData, barSize: 1.5, shading: lambert, itemStyle: { color: #4fa3e0 } }, { type: lines3D, coordinateSystem: geo3D, effect: { show: true }, data: linesData }, { type: scatter3D, coordinateSystem: geo3D, data: scatterData, symbolSize: 8, itemStyle: { color: #ffd700 } } ] };这种组合在大屏上效果非常抢眼。但越炫酷越考验电脑性能尤其是instancing没有开启的时候大量柱子和飞线会掉帧。建议在geo3D里开启instancing: true它能把多个几何体合并绘制大幅减少绘制开销。4. 避坑我踩过的 5 个 3D 地图相关的坑我前后在十几个项目里用过 ECharts 3D 地图下面这些坑基本都踩过一遍写出来给大家省点时间。4.1 坑一geo 注册不一致导致地图不显示第一次用 map3D 时我注册地图使用了echarts.registerMap(china, chinaJson)但在 series 里写成了map: China大小写不一致结果整个地图空白连报错都没有。这个坑很低级但真的很容易犯。ECharts 地图名称是严格区分大小写的注册用china引用就必须写china。另外china.json文件里可能会有一些非 ASCII 编码的字符如果文件被转码成 UTF-8-BOM注册时也会出错建议用 UTF-8 无 BOM 格式保存。4.2 坑二map3D 和 series 的坐标系对不上map3D本质上是基于经纬度坐标系绘制地图的而bar3D、scatter3D等系列如果指定了coordinateSystem: geo3D它们也会参考这个坐标系。但如果你在同一个页面里既有map3D又有其他 3D 系列而series里没有指定coordinateSystem默认会使用笛卡尔坐标系x 轴、y 轴数据就乱套了。解决办法很简单所有需要叠加的 3D 系列都必须加上coordinateSystem: geo3D并且确保geo3D组件和系列在同一个图表实例里。4.3 坑三性能优化与区域钻取3D 地图在数据量大的时候比如全国 300 多个市级行政区渲染起来会卡顿。我经历过一次大屏项目地图一动就掉帧最后定位到几个问题一是地图 JSON 文件太大有 10 多 MB建议对 GeoJSON 做简化二是label的show开了但每个区域都显示标签数量太多浏览器吃不消。解决办法是把需要高亮的区域标签打开其他区域关闭或者用label.formatter只显示前几个字符。关于区域钻取map3D本身不支持像 2D map 那样的roam联动钻取。如果要从全国下钻到省份通常的做法是切换地图 JSON 并重新注册或者用两个map3D叠加做动画过渡。这个逻辑比较复杂我的建议是不要用map3D做钻取老老实实回到 2D map 做下钻交互要 3D 感就用全局立体旋转撑撑场面。4.4 坑四地图边界模糊或出现锯齿这个问题一般出现在地图缩放之后。根因是 3D 场景的渲染分辨率固定缩放时边界没有重新抗锯齿。解决办法有三种一是把renderer参数里的antialias设置为true二是通过devicePixelRatio提高渲染分辨率比如devicePixelRatio: 2三是给地图区域加细边框用borderColor和borderWidth掩盖锯齿。第三种最有效我项目里常用的边框颜色是rgba(255,255,255,0.3)宽度 1既不会太抢眼又能遮住边缘毛刺。4.5 坑五3D 地图在部分浏览器不兼容WebGL 不是所有浏览器都能跑。IE 11 以前的老版本浏览器对 WebGL 支持很差echarts-gl直接渲染不出来。我们的处理方法是在初始化图表前先检测 WebGL 是否可用不可用就回退到 2D 地图方案。检测代码很简单function webglAvailable() { try { var canvas document.createElement(canvas); return !!(window.WebGLRenderingContext (canvas.getContext(webgl) || canvas.getContext(experimental-webgl))); } catch (e) { return false; } }如果不支持 WebGL就加载普通map系列的配置保证功能可用。这个降级逻辑在大屏项目里非常重要因为总有某个领导的电脑是旧设备。5. 从“3D感”到“高级感”视觉细节的打磨经验地图有了立体感不代表好看。很多项目把 3D 地图做出来以后颜色艳俗、光照浮夸、标签乱飞。我习惯在地图基础效果出来之后再花一倍时间打磨视觉细节让“3D感”变成“高级感”。5.1 颜色渐变与光照方向地图区域颜色不要用纯色最好用visualMap做数值渐变。渐变颜色建议选择同一色系的深色到亮色比如深蓝到亮蓝、深紫到青绿避免彩虹色。光照方向要和渐变方向配合如果地图右侧有数据高亮光源就从右侧打如果中央区域是高值主光源可以垂直往下打让中间亮、四周暗形成聚光灯效果。这个可以通过light.main.alpha和beta精确控制。5.2 标签与高亮交互标签默认是直接贴在地图表面的3D 视角下容易被遮挡。我建议把label.distance设为 3~6把文字抬高到地图上方并且开启emphasis下的标签放大和颜色变化。还有一个小技巧给标签加一层textShadowBlur让文字边缘发晕在深色背景下会更清晰。高亮交互方面不要只改颜色。可以配置emphasis.itemStyle的同时给对应区域加一个height变化让被点击的省份“弹起来”。map3D的emphasis支持itemStyle.height或itemStyle.offset这类属性不同版本支持程度不同实测下来boxHeight不能动态修改但可以用itemStyle.extrude配合3D效果做视觉突起。5.3 让地图旋转起来自动旋转是 3D 地图最直观的“炫技”方式但旋转速度和方向不对反而会让人头晕。我常用的配置是autoRotate: trueautoRotateSpeed: 3数值越小越慢beta初始角度设置在 20~30 之间。如果项目里还有别的图表旋转会让用户很难点击地图区块此时可以把autoRotate关掉改成鼠标拖拽旋转或者在这张地图没有 hover 时自动缓慢旋转hover 后暂停。还有一个小技巧地图旋转时背景不要纯黑可以加一层极淡的网格或星空底。echarts-gl支持backgroundColor和environment我用得最多的是environment: rgba(0,0,0,0)配合 CSS 背景做渐变地图立体感会更强还不干扰周围的图表。6. 最后的经验总结3D地图不是炫技是为业务服务写了这么多再回到最初的问题ECharts 地图如何显示出 3D 感本质上你要在“真实”和“表现力”之间找一个平衡点。map3D可以让你快速拥有一个旋转的立体地图geo3D可以让你在立体空间里叠加各种业务数据而伪 3D 美化则适合那些不想引入额外依赖的场景。工具都是现成的关键是搞清楚自己需要什么。我个人在实际项目里的体会是3D 地图更适合总览和展示细节查看和联动钻取还是 2D 地图更务实。如果你想做一张 3D 地图大屏建议先按这篇文章的路线把基础效果跑通再用visualMap和geo3D叠加真实业务数据最后把自动旋转和 hover 弹起打磨到位这样出来的东西既有科技感又能真正传递数据价值。别盲目追求花哨效果最终用户记住的永远是那张图告诉了他什么。
返回列表