WorldWideView:用 CesiumJS 搭一个实时地理情报平台

WorldWideView 是一个基于 CesiumJS 的开源实时地理空间可视化平台,技术栈为 Next.js + TypeScript,数据存储用 Supabase。它能同时接入飞机追踪、海事 AIS、交通摄像头、野火监控等多个异构数据源,在浏览器内渲染 10 万+ 个实时对象,帧率稳定在 60fps。

项目地址:https://github.com/silvertakana/worldwideview(200+ (opens in a new tab) Stars)

核心设计:数据源与渲染解耦

WorldWideView 的架构核心是插件化数据源 + 高性能批量渲染的分离设计。

渲染层只做一件事:高效地把数据画到 3D 地球上。它不关心数据来自哪里,格式是什么,更新频率是多少。这些都由各自的插件处理,插件将原始数据标准化为统一的地理坐标对象后交给渲染引擎。

这个设计的直接好处是:添加新数据源不需要改渲染逻辑,某个数据源出现延迟也不会阻塞其他数据源的渲染。

渲染性能:为什么能流畅处理 10 万+ 对象

CesiumJS 提供了两套渲染 API,选择哪套对性能影响巨大:

  • Entity API:每个对象独立管理,适合对象少、交互丰富的场景(几十到几百个对象)
  • Primitive API:将多个对象合并为一个批次提交 GPU,适合大规模静态场景

WorldWideView 选择了 Primitive API。1 万架飞机只需要一次 GPU Draw Call,而不是 1 万次。对象位置更新时直接修改 Primitive 内部的 buffer 数据,不重新创建对象。性能开销从 O(n) 降为接近 O(1)。

其他配套优化:

  • 视锥剔除(Frustum Culling):只渲染当前相机视野内的对象,视野外直接跳过
  • LOD:远处对象使用低面数模型,减少 GPU 顶点计算量
  • 坐标预计算:经纬度到笛卡尔坐标的转换在 CPU 侧完成,只将最终坐标提交 GPU

数据源:每个插件对接了什么

项目内置 5 类数据源插件,每个插件背后都有明确的外部 API。

航空数据

主数据源为 OpenSky Network,通过 REST 轮询获取全球航班实时位置,刷新间隔 5 秒:

GET https://opensky-network.org/api/states/all

认证走 OAuth2(client_credentials),免费账户每天 4000 积分,约支持 4 小时的连续拉取。项目在 .env 中支持配置多组凭据,按轮换顺序使用,单个账户额度耗尽后自动切换:

# .env.local
OPENSKY_CREDENTIALS=clientId1:clientSecret1,clientId2:clientSecret2

军事航班走 adsb.fi,无需密钥,速率限制 1 req/s:

GET https://opendata.adsb.fi/api/v2/mil

海事数据

对接 aisstream.io 的 WebSocket 流,订阅全球船舶位置报告(PositionReport),刷新间隔 60 秒:

WSS wss://stream.aisstream.io/v0/stream

连接后发送订阅消息:

{
  "APIKey": "<MARITIME_API_KEY>",
  "BoundingBoxes": [[[-90, -180], [90, 180]]],
  "FilterMessageTypes": ["PositionReport"]
}

需要注册 aisstream.io 账户获取免费 API Key。支持货船、油轮、客船、军舰等 8 种船型分类。

交通摄像头

聚合三个官方交通数据源,全部公开免费无需密钥:

数据源API 地址摄像头数量覆盖地区
GDOTArcGIS REST API~2,000美国乔治亚州
TfL JamCamhttps://api.tfl.gov.uk/Place/Type/JamCam~900英国伦敦
Caltranshttps://cwwp2.dot.ca.gov/data/d{N}/cctv/~3,400美国加州(12个地区)

摄像头数据本地缓存 TTL 为 24 小时。

野火监控

对接 NASA FIRMS(Fire Information and Management System),使用 VIIRS SNPP 卫星热点数据,每 5 分钟刷新:

GET https://firms.modaps.eosdis.nasa.gov/api/area/csv/{API_KEY}/VIIRS_SNPP_NRT/world/1

API Key 可选,无 Key 时降级到公开 CSV 源。返回的热点数据按火点辐射功率(FRP)分为四级:

等级FRP 范围显示颜色
< 10 MW黄色
10–50 MW橙色
50–100 MW红色
极端> 100 MW深红

数据通过动态三层聚类(Macro ~220km / Meso ~55km / Micro ~5.5km)在不同缩放级别下合并显示,避免热点密集区域的图标重叠。

地理与边界数据

军事基地位置以 military_bases.geojson 内置在项目中,无需额外配置。其他地理边界支持标准 GeoJSON 格式。

底层基础设施

组件技术用途
3D 地球CesiumJS + Cesium Ion Token地形、影像、3D Tiles
高清影像Bing Maps API(可选)替换默认影像
数据持久化Supabase(PostgreSQL)历史轨迹存储、用户认证
历史回放/api/aviation/history?time={ts}回放任意时间点的航班位置

本地运行

git clone https://github.com/silvertakana/worldwideview.git
cd worldwideview
npm install
cp .env.example .env.local  # 填入 Cesium Ion Token 和 Supabase 配置
npm run dev

访问 http://localhost:3000。只配置 Cesium Ion Token 即可启动,其余数据源按需开启。

如果需要添加自定义数据源,在 src/plugins/ 下新建一个目录,实现统一的插件接口(数据订阅、格式转换、对象类型定义),50–100 行代码即可完成一个基础插件。

总结

WorldWideView 是一个完整的实时地理可视化参考实现,不只是 Demo,而是有完整的数据接入、性能优化、历史存储方案。

它的适用场景是:多异构数据源、高更新频率、大规模对象数量的实时可视化需求。如果你的需求是静态地图或复杂地理分析,这个项目不是最佳选择。

架构上值得借鉴的两个核心思路:

  1. Primitive API 的批量渲染:把渲染代价从 O(n) 降到接近 O(1),是在 Web 端做大规模地理可视化的关键
  2. 插件化数据解耦:数据源与渲染层分离,使得不同频率、不同协议(REST / WebSocket)的数据源可以独立运行,互不干扰

GitHub 项目地址:https://github.com/silvertakana/worldwideview (opens in a new tab)