2026-07-05 / 7 min

浙江空气质量大屏里的 Three.js 3D 地图

浙江空气质量大屏的 3D 地图由 GeoJSON 投影、城市拉伸、Raycaster 交互、AQI 映射与降水粒子组成。

Three.js3D 可视化空气质量

定位

这张 3D 地图是浙江空气质量系统的首层交互入口。11 个地市被渲染为空间对象,用户可以旋转、缩放、悬浮查看数据,并点击城市进入详情页。

空气质量数据通常以数字和图表出现。地图先呈现“哪些地区更严重、哪些地区更平稳”的空间分布,再把用户带到城市详情。

地图生成

地图数据来自浙江 GeoJSON。前端先使用 D3 的 geoMercator 将经纬度投影为平面坐标,再把每个地市边界转换为 Three.js Shape

核心步骤是:

  1. 遍历 GeoJSON features,拿到每个地市的 polygon。
  2. 将经纬度投影成局部平面坐标。
  3. THREE.Shape 描出城市轮廓。
  4. THREE.ExtrudeGeometry 给轮廓增加厚度。
  5. 把所有城市 mesh 放进统一的 mapGroup

项目将 mapGroup.rotation.x 设为 -Math.PI / 2,使局部坐标与屏幕中的 3D 视角对齐。入场时的城市生长和 hover 隆起都修改 scale.z

入场与交互

地图按城市纬度顺序播放入场动画。每个城市的初始高度接近 0,再用缓动函数恢复到正常高度。

交互主要由 Raycaster 完成:

  • 鼠标移动时检测当前指向的城市 mesh。
  • 命中城市后显示悬浮数据卡片。
  • hover 城市通过 scale.z 增高,形成地块隆起。
  • 点击城市后跳转到 detail.html?city=城市名
  • 鼠标拖动控制相机角度,滚轮控制相机距离。

因此地图同时承担导航、全省概览和城市数据查看。

AQI 数据映射

实时数据由 Flask API 的 /api/now 提供。前端收到城市 AQI 后,同时更新以下视觉层:

  • 城市 mesh 的主色和自发光颜色。
  • 城市标签里的 AQI 数字。
  • 悬浮卡片里的 PM2.5、温度、湿度、风速和可信度。
  • 顶部平均 AQI、最高值、最低值、优良率和预警数。

AQI 色彩通过 HSL 连续映射生成,不使用固定的离散色块。空气质量变化时,城市颜色过渡更平滑,并与底部图例保持一致。

标签纹理

城市标签使用 CanvasTexture 生成。代码先在 canvas 上绘制颜色圆点、城市名和 AQI 文本,再把 canvas 转成 Three.js sprite 的贴图。

这种做法让标签跟随 3D 场景定位,同时保持 2D 文本的可读性。AQI 更新时,旧 texture 会先释放,再替换为新的 texture,避免显存对象持续累积。

降水粒子

项目里还有一个降水粒子系统。它用 BufferGeometry 创建最多 8000 个粒子,并根据城市降水量分配粒子数量。

大致逻辑是:

  1. 为每个粒子保存位置和下落速度。
  2. 将城市经纬度投影到地图局部坐标。
  3. 按降水量决定每个城市上方生成多少粒子。
  4. 粒子不断沿局部 Z 轴下落,落到地图附近后重新回到高处。
  5. 入场动画结束后再淡入雨滴,避免画面一开始过载。

降水字段由此成为地图中的动态状态,而不只停留在表格里。

可复用经验

这类 3D 数据地图也适用于环境监测、物流分布、城市能耗、人口流动和设备告警等地区型项目。

实现时先明确数据和空间对象的对应关系:

  1. GeoJSON 决定空间边界。
  2. API 数据决定状态。
  3. Three.js 负责空间表达和交互。
  4. ECharts 负责解释细节和趋势。

这四层职责明确后,3D 视图可以作为数据系统的入口,并与趋势和详情分析保持一致。