简介china.json是面向前端可视化开发者的ECharts 3D地图核心数据文件采用GeoJSON格式存储中国省级行政区域边界坐标可直接配合ECharts的geo3D组件使用。压缩包内含1个JSON文件体积仅13KB便于快速集成到项目中。使用该文件时可省去手工整理地理数据的步骤只需调用echarts.registerMap并配置对应地图名称即可渲染出可交互的3D中国地图并在此基础上按省份着色、标注或绑定业务数据。文件中每个行政区对应一条边界坐标数组结构清晰适合用于数据可视化教学、大屏展示或业务系统地理模块开发。目前已有245人浏览或学习对于需要快速搭建3D地图效果的前端开发者来说是一份轻量且精准的实用资源。 做可视化大屏凡是碰到需要“全国地图 3D 效果”的需求绝大多数项目最后都会落到 echarts echarts-gl china.json 这个组合上。光用 echarts 自带的 map 类型只能做 2D 平面填色要做立体的、能拖拽旋转、带光效的地图块必须借助 echarts-gl 里的 geo3D、map3D、scatter3D 这几个组件。这篇文章就围绕“echarts 3D 地图数据 china.json”这条主线把从取数、注册、配 3D 参数到叠加城市标记的完整链路拆开说一遍顺便把我实际踩过的坑都标出来。我尽量不把官网文档搬过来重复而是讲“文档里没说但项目里一定会遇到”的细节。适合刚开始碰 echarts 可视化、想快速做 3D 中国地图的新手也适合已经做过 2D 地图、想提升大屏效果的开发者照着走一遍基本能跑通。1. 整体设计与思路拆解1.1 为什么选 echarts echarts-gl而不是自己用 WebGL 画如果你只是需要一张能看、能旋转、能联动的中国 3D 地图自己拿 Three.js 从 GeoJSON 开始建模属于典型的“杀鸡用牛刀”而且后期维护成本很高。echarts 本身是 2D 生态但通过 echarts-gl 这个 WebGL 扩展可以直接把 geo 系列和地图数据放到 3D 场景里渲染。它最大的优势是配置声明式地图块的高度、光照、棱线、颜色映射全部是 option 里的 JSON 字段不用写顶点、法线、着色器这些底层逻辑。从选型角度讲这个组合比较适合数据可视化大屏、数据驾驶舱这类场景因为后续还要接 visualMap 分段、tooltip 联动、异步刷新数据用 echarts 声明式配置比手写渲染循环好维护太多。1.2 geo3D、map3D、scatter3D 到底啥关系很多初学者容易在这三个名字上绕晕。简单类比geo3D 是舞台map3D 是舞台上隆起的立体地形模型scatter3D 则是模型上插的指示标。也就是说组件类型主要用途geo3D组件定义 3D 坐标系和底图其他 3D 系列挂载到它上面map3D系列渲染地图块面支持 visualMap 分段填色scatter3D系列在 geo3D 上撒点标记城市位置、数量等实际项目中两种写法最常见。如果只是区域填色直接写一个 map3D 系列就行内部会自动挂到默认的 geo3D 坐标系上。如果既要立体地图打底又要撒城市数量的点就得显式声明 geo3D 组件让 map3D 和 scatter3D 的 coordinateSystem 都指向它。后面实操部分我会把这两种场景都过一遍。2. 数据准备china.json 到底从哪来2.1 GeoJSON 结构快速上手china.json 并不是 echarts 专有格式它本质是一份 GeoJSON描述的是中国省级行政边界的空间信息。你要先认识它的核心结构后面排查问题才不慌{ type: FeatureCollection, features: [ { type: Feature, properties: { adcode: 110000, name: 北京市, center: [116.4, 39.9] }, geometry: { type: Polygon, coordinates: [ [ [116.3, 39.8], [116.4, 39.95] ] ] } } ] }features 数组中每个元素就是一个行政区。properties 里通常有 name、adcode、center这三个字段对图表配置很关键name 用于地图数据匹配center 是省级几何中心坐标做散点标记或者计算数值标注时可以直接用。geometry.coordinates 是边界坐标点注意它一般是经纬度数组多级嵌套不能想当然地直接取下标。2.2 china.json 获取的三种常见姿势先说最省事的阿里云 DataV 提供的 GeoAtlas 数据。全国范围数据直接请求这个地址https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json返回的就是标准 GeoJSON结构干净name、adcode、center 都有日常开发完全够用。唯一要注意的是跨域本地 file:// 打开大概率会被拦截建议起个本地服务或者走代理转发。第二种是 GitHub 上早期 echarts 老项目遗留的 china.json用的人很多但因为维护时间较早部分数据边界精度和最新行政区划有出入域名也可能变动。我一般不建议生产项目直接引第三方 CDN 地址最好下载到本地 assets 目录。第三种是自定义裁剪。如果你只需要部分省份或者觉得原始 GeoJSON 文件太大影响首屏加载可以用 mapshaper 这类工具做简化处理。命令行里跑一句mapshaper china.json -simplify 10% -o china_simplify.json可以把文件体积降到原来的十分之一视觉上边界几乎没差别。2.3 坐标、文件体积这些隐藏坑GeoJSON 里的坐标务必保持经纬度不要提前转成 Web Mercator 平面坐标。echarts-gl 在 3D 渲染时会自己处理投影你一旦手动转了地图很可能直接不显示或者位置歪到天上去。另外一个隐藏坑是文件体积完整的全国边界 GeoJSON 带较高精度时可能有 2-4MB放在大屏里首次加载会明显卡顿所以上生产前建议简化一下并把请求结果缓存成全局变量而不是每次进页面都重新 fetch。3. 实操过程从零搭一个能用的 3D 中国地图3.1 依赖安装与页面骨架用 npm 项目就直接装两个包npm install echarts echarts-gl注意 echarts-gl 的版本要和 echarts 匹配echarts 5 对应 echarts-gl 2.x旧项目如果还在用 echarts 4就装 echarts-gl 1.x。版本不匹配最常见的现象是控制台报“component geo3D not exists”或者 3D 系列直接不渲染。页面里先准备一个有宽高的容器这一点太容易被忽视div idmap3d stylewidth: 100%; height: 600px;/div如果容器宽高为 0什么图都出不来。3.2 注册地图并渲染基础 3D 地图加载数据后通过 registerMap 注册然后配置 map3D 系列const chart echarts.init(document.getElementById(map3d)); fetch(https://geo.datav.aliyun.com/areas_v3/bound/100000_full.json) .then(res res.json()) .then(geoJson { echarts.registerMap(china, geoJson); chart.setOption({ series: [{ type: map3D, map: china, regionHeight: 3, shading: lambert, itemStyle: { color: #1a5c9e, borderWidth: 1, borderColor: #a0d4ff }, label: { show: true, textStyle: { color: #ffffff, fontSize: 12 } }, viewControl: { distance: 100, alpha: 40, beta: 0, autoRotate: false }, light: { main: { intensity: 1.2 }, ambient: { intensity: 0.5 } } }] }); });这里逐个说下核心参数。regionHeight 是地块隆起的高度单位近似于“地图缩放后视觉上的高度”数值越大立体感越强但太大相邻省份会挤在一起建议 1-5 之间按视觉效果调。shading 是着色模式常用 lambert 和 color前者会计算光照明暗有层次后者就是纯色填充适合极简风格。viewControl 负责视角distance 是相机离地图的距离alpha 是俯仰角beta 是水平旋转角autoRotate 开启后地图会自动慢速旋转大屏演示时很出效果但偏后台的看板建议关掉干扰阅读。light.main 可以理解成“太阳”intensity 是强度加 shadow 后地图块会产生侧面阴影立体感立刻上一个档次。3.3 区域填色visualMap 配 pieces地图数据通常是一组省名对应的数值比如各省销售额const mapData [ { name: 北京市, value: 320 }, { name: 广东省, value: 1250 }, { name: 四川省, value: 860 } ];然后在 option 里加 visualMapvisualMap: { type: piecewise, pieces: [ { gte: 0, lt: 500, label: 0-500, color: #d9f0ff }, { gte: 500, lt: 1000, label: 500-1000, color: #7cc3ff }, { gte: 1000, lt: 1500, label: 1000-1500, color: #2b7fd1 }, { gte: 1500, label: 1500以上, color: #0f3c73 } ] }这里有个小技巧如果有人问“echarts 地图 9 段图怎么变 10 段图”本质就是 pieces 数组里加一项。但要注意 gte 和 lt 的边界覆盖比如第一段到 500第二段从 500 开始中间不能留空隙否则 visualMap 会把未覆盖部分自动按连续型处理产生想不到的颜色段。3.4 给城市撒点标数量scatter3D 叠加区域颜色只代表聚合值很多需求还要求“给某些市标记数量”比如标出头部城市的销售额。这时候用 scatter3D 最方便const cityData [ { name: 北京, value: 320, coord: [116.4, 39.9] }, { name: 上海, value: 420, coord: [121.47, 31.23] }, { name: 广州, value: 380, coord: [113.26, 23.13] } ]; option { geo3D: { map: china, itemStyle: { color: #1a5c9e }, viewControl: { distance: 100, alpha: 40 } }, series: [{ type: map3D, coordinateSystem: geo3D, map: china, regionHeight: 3 }, { type: scatter3D, coordinateSystem: geo3D, data: cityData.map(item ({ name: item.name, value: [item.coord[0], item.coord[1], item.value], itemStyle: { color: #ffd700 } })), symbolSize: function(val) { return Math.max(6, val[2] / 20); }, label: { show: true, formatter: function(params) { return params.name \n params.value[2]; }, textStyle: { color: #fff, fontSize: 12 } } }] };scatter3D 的 value 数组前两位是经纬度第三位才是真正的数值。symbolSize 用函数写法可以让点的大小随数值变化视觉上更直观。label.formatter 里通过 params.value[2] 取第三位展示这样地图上每个城市上方就能看到数量和名称。如果你不想自己维护城市的经纬度GeoJSON 的 properties.center 里有现成的省级中心坐标省份数据直接用它就行。地级市数据就需要单独准备一份带经纬度的城市表了。3.5 纹理贴图和光照微调让地图不发闷纯色 3D 地图看久会显得“塑料感”很强。echarts-gl 的 map3D 支持给地块表面贴纹理常见做法是准备一张尺寸 512x512 左右的纹理图低频噪点或者科技感网格图都行material: { texture: https://example.com/texture.jpg, textureRepeat: true, roughness: 0.6, metalness: 0.1 }textureRepeat 为 true 时纹理会在整个地图表面重复平铺适合做网格或噪点。roughness 控制粗糙度值越大高光越弱metalness 控制金属感值太大会让地图块像钢板一样反光反而看不清颜色映射建议不超过 0.2。光照方面除了 main 和 ambient还可以加一个 postEffect 泛光效果让高亮区域边缘发光特别适合大屏postEffect: { enable: true, bloom: { enable: true, bloomIntensity: 0.15 } }bloomIntensity 不要调太大0.1-0.2 之间比较克制超过 0.5 整个画面会白花花一片。4. 常见问题与排查技巧实录4.1 地图不显示或者只有一个黑色大方块优先级最高的是检查 echarts-gl 是否成功引入。很多人只引了 echarts忘了引 echarts-gl结果 option 里 type: map3D 被当成未知系列地图不出或者报 “series.map3D not exists”。其次检查容器宽高哪怕父容器是 display:none 状态下初始化的也会导致渲染区域为 0。最后确认 registerMap 是否在 setOption 之前调用因为 fetch 是异步的如果不等数据回来就 setOptionseries 里 map: china 找不到对应地图名自然白屏。4.2 地图显示成一段长方形 / 位置偏移这类问题大概率是数据问题。如果 geoJSON 用的是经典 china.json而 echarts 是 5.x部分老数据的 adcode 和 name 跟新版图表组件匹配不上会出现某些省份不显示或整体位置偏移。换数据源是最省事的方法优先用 DataV 的 GeoAtlas。另一种情况是容器本身是超宽扁的形状3D 地图在宽高比很大的容器里会被压得看起来像“长方形展示”这时候优先调整视口或者用 viewControl.distance 增大相机距离让地图在画面中占比较小视觉上就不会那么变形。4.3 3D 地图上给某些市标记数量自己写 label 不生效如果你用的是 map3D 系列label 默认显示的是省名。想显示数值可以在 data 里加 value然后 formatter 这样写label: { show: true, formatter: function(params) { return params.name \n (params.value || ); } }如果是 scatter3D 的标记不显示 label多半是忘了在 series 里开 label.show因为在 3D 场景里默认是不显示标签的。还有一个小坑scatter3D 的 label 会跟随视角旋转文字容易倒过来体验不好时可以关闭 label改用 tooltip 展示数量或者另加一个系列用固定朝向的文字标注。4.4 visualMap 9 段变 10 段颜色却合在一起分段边界没有全覆盖是最常见原因。比如 pieces 里你写了 { gte: 0, lt: 500 } 和 { gte: 501, lt: 1000 }500 到 501 之间就出现了一个空洞visualMap 会把空洞附近的区间重新计算感觉像是两段颜色合并了。正确写法是相邻段用同一个边界值{ gte: 0, lt: 500, color: #d9f0ff }, { gte: 500, lt: 1000, color: #7cc3ff }另外如果 series.data 里的值全部落在同一个分段内视觉上也会觉得“怎么只有一段颜色”这不是配置问题是数据本身分布太集中。可以考虑把极值单独处理或者结合业务重新设定分段阈值。4.5 在 vue / uniapp 里集成时遇到的幺蛾子vue 项目里最常见的是模块引入报错。正确姿势是完整引入 echarts 后再引入 echarts-glimport * as echarts from echarts; import echarts-gl;不要用按需引入的方式去引 echarts-gl 的某个系列它没有按需导出。另一个高频问题是组件销毁后不释放实例导致页面切换时 WebGL 上下文越积越多最后黑屏。在 onUnmounted 里调用 chart.dispose() 是必须的。至于 uniappH5 端用起来问题不大小程序端因为 canvas 类型不同echarts-gl 的支持有限建议小程序里退回 2D 地图方案或者用 web-view 内嵌 H5 页面。5. 我的一些实操体会最后分享几个我在实际项目里沉淀下来的小习惯。第一优先把 2D 效果调通再切 3D。2D 地图的 visualMap、tooltip、series.data 结构和 3D 基本是共享的先在 2D 下把数据联调明白切 3D 时只动渲染层排查范围会小很多。第二3D 地图的性能瓶颈通常不在地图本身而在 scatter3D 的点数。撒几百个点没问题一次性撒几千个点建议开 large: true 并用 symbolSize 控制点大小否则帧率会很惨。第三大屏截图或演示前记得给 viewControl 设置 autoRotate: true再配合 postEffect 泛光这种动态效果才是 3D 地图区别于 2D 的核心卖点。另外也想提醒一句地图 GeoJSON 涉及行政边界数据实际项目上线前尽量选择官方发布的合规数据文件开发阶段用公开数据源验证页面效果没问题但不能默认所有来源都适合直接上生产。这个细节看着不起眼真出问题就是大事提前规避比事后解释强得多。这套 echarts echarts-gl china.json 的方案我已经在多个大屏项目里跑过稳定性还是很让人放心的照着上面的顺序逐步落地基本不会走弯路。本文还有配套的精品资源点击获取