真实公交数据丢进 Cesium,武汉 405 路变成了可以跟着跑的 3D 场景
大部分公交可视化项目停在一个层面:在地图上画一条线,标几个点,完事。Trajectory-Roaming 走得更远——一辆 3D 公交车沿真实路线行驶,到站停车,摄像机可以跟着车走,还可以切进车厢看第一人称视角。
项目用 Cesium.js + Vue 3 构建,代码开源。技术栈本身不稀奇,但把这几个功能拼通需要绕过一些不那么显而易见的坑,这篇文章就聊聊它是怎么做的。

Cesium 的动画模型和你想的不一样
做 Cesium 轨迹动画,第一个容易踩的坑是对它的动画模型产生误解。
很多人的第一反应是:给车一个起点、一个终点、一个速度,让它跑。但 Cesium 不是这样工作的。它的实体动画是时间驱动的——你需要预先声明"这个实体在 T1 时刻在哪、T2 时刻在哪、T3 时刻在哪",然后 Cesium 的时钟系统负责播放这张位置表。
这意味着,如果你的轨迹数据只有坐标、没有时间戳,你得先把时间戳造出来,Cesium 才能工作。
Trajectory-Roaming 的数据来自真实的武汉公交 API,格式大概是这样的:

xs 和 ys 字段是轨迹点的经纬度序列,一共 332 个点,记录了 405 路公交从起点到终点的完整行程。有坐标,没有时间。
时间从哪来
这是整个项目里最值得看的一块。
项目用了一个很朴素的方法:既然没有时间,就用物理公式反推。相邻两个轨迹点之间的距离可以算出来,再给定一个速度常量(项目设的是 20),时间 = 距离 / 速度,逐段累加,就得到了每个轨迹点的相对时间戳。
332 个点算完,结果是这样一个累计时间数组:

有了这张时间表,就可以把每个坐标和时间戳一起塞进 Cesium 的 SampledPositionProperty。这个对象内部存的就是一组 (JulianDate, Cartesian3) 的键值对,Cesium 时钟每推进一帧,它就从这张表里插值出当前位置,驱动车辆移动。

这个方法的代价是明显的:真实公交不会匀速行驶,它要停红灯、进站等候、路况变速。用常量速度推出来的时间表,只能还原路线形状,还原不了真实的运行节奏。但作为可视化 Demo,这个精度够用,而且实现成本很低。
如果要做得更真实,需要在数据里带上每个轨迹点的真实时间戳,或者接入实时 GPS 数据。
朝向问题怎么解决
车辆沿路线行驶时,转弯处车头朝向要跟着变。手动处理的话,需要在每个轨迹点计算一次方向角,工作量不小,而且插值处理不好容易抖动。
Cesium 提供了一个现成的工具:VelocityOrientationProperty。把它赋给实体的 orientation 属性,它会自动根据相邻帧的位移方向计算朝向——不需要存角度,不需要手动插值,车头始终指向行进方向。
这个 API 在文档里不算显眼,但对轨迹动画来说是个很实用的东西,项目里直接用上了。
三种摄像机视角
控制面板提供了三种摄像机模式,这是整个项目观感差异最大的一块。
跟随视角是最常见的做法,摄像机挂在车辆后上方跟着走;自由视角解除绑定,可以自由操控地图。
比较有意思的是车内视角——摄像机移进车厢内部,从车窗往外看,沿途的楼宇、路牌从两侧掠过。这个视角的实现需要把摄像机偏移到实体的本地坐标系内部,随实体一起旋转平移,而不只是简单地跟随。
控制面板整体长这样:左侧是站点列表,底部是播放控制,速度和进度一目了然。

点击车辆还会弹出一张信息卡片,展示路线的运营信息,这部分数据也直接来自原始 JSON:

一个值得注意的细节
项目接入了浏览器的 Page Visibility API。切走标签页时,动画会自动暂停;切回来,继续从上次的位置播放。
这个细节很多类似项目都没有处理。如果不加这个,Cesium 的时钟会在你切走标签页期间继续推进,回来的时候车早就开到终点了——或者循环回起点,你完全不知道发生了什么。加了这个处理,行为才是用户预期的。
适合拿来参考什么
如果你在用 Cesium 做轨迹类项目,这个仓库里几个点可以直接参考:
- 无时间戳的轨迹数据怎么驱动 Cesium 动画:s=vt 反推的思路,简单粗暴但够用
SampledPositionProperty的实际用法:文档里说的比较抽象,看代码更直接VelocityOrientationProperty:处理移动实体朝向的标准方式,很多人不知道有这个- 实体跟随摄像机和车内视角的实现方式:两种不同的摄像机绑定思路
项目的数据是静态 JSON,没有接实时接口;速度是常量,没有真实的时变速度;也只有单条路线、单辆车。这些都是扩展空间,但也是这个项目目前没有覆盖的范围。
安装比较简单,标准的 pnpm + Vite 流程:
git clone https://github.com/Harvey-Andrew/Trajectory-Roaming.git
cd Trajectory-Roaming
pnpm install
pnpm devCesium.js 需要配置 Ion Access Token,免费注册即可获取。项目底图用的是高德瓦片,基础功能不依赖付费资源。
GitHub:https://github.com/Harvey-Andrew/Trajectory-Roaming (opens in a new tab)
文中截图来自项目 README。