不用专业GIS软件,这个开源项目让你用Web做实时地理数据平台
如果你需要做飞机追踪、船舶监控或卫星轨道预测,通常的做法是用 ArcGIS 或其他专业 GIS 软件。但最近看到一个开源项目,有人用 Web 技术做出了一个实时地理空间情报平台,名叫 WorldWideView。
这个项目基于 CesiumJS(一个 Web 3D 地球库),但关键的不是"又是一个地球",而是它的核心设计思想——模块化的数据源 + 高性能的实时渲染。它能同时追踪飞机、船舶、卫星这些完全不同的数据源,在一个 3D 地球上流畅地呈现,而且支持实时更新。
200+ 个 GitHub Star,说明很多人觉得这个思路很有价值。
为什么值得关注
1. 10万+对象也能实时渲染
在 Web 上用 3D 呈现地理数据,性能一直是个瓶颈。GIS 数据往往是海量的——几千条航线、几万个基站、几十万个地形点。怎么在浏览器里流畅地显示?
WorldWideView 用了一个关键优化:Cesium Primitives。与其把每个飞机、每艘船都当成一个独立的 3D 对象(这样 GPU 压力很大),不如把它们合并成一个"原始几何体",然后用数据驱动批量渲染。这样做的结果是,即使有 10 万+ 个对象同时显示,帧率仍然很稳定。
这个思想和"大场景优化"是一个道理,但在地理可视化领域的应用并不多见。
2. 开放的插件系统,不用改核心代码
WorldWideView 的设计把核心和数据源分离了。核心只负责"如何高效地渲染这些数据",而具体"什么数据"则通过插件来扩展。
这意味着什么?
- 想接入飞机数据?写个飞机插件,处理 ADS-B 数据流
- 想接入海事数据?写个 AIS 插件,处理船舶位置信息
- 想接入卫星轨道?写个轨道插件,计算实时位置
每个数据源都是独立的模块,互不影响。这样做的好处是,你可以轻松地混搭任意组合——同时显示飞机、船舶、卫星,或者只显示其中某些,完全由你决定。而且新增一个数据源时,不需要改一行核心代码。
3. 实时更新和平滑动画
地理数据平台最重要的就是"实时"。飞机不能显示旧位置,卫星轨道要每秒更新。
WorldWideView 内置了实时数据流处理和平滑动画。系统会自动在数据点之间插值计算,让移动看起来流畅,而不是"一跳一跳"。这是看起来专业和业余的重要差别。
同时,系统支持"Oriented Icons"——飞机、船舶等图标会自动转向,指向它们的运动方向。这些细节让整个可视化看起来很专业。
核心架构:为什么这样设计
如果你看代码,会发现这个项目的设计非常清晰:
1. 数据源无关的核心
WorldWideView 的核心不关心你的数据是什么。它只知道:"给我一个数据流,我来帮你渲染成 3D 地球上的元素"。这意味着核心逻辑非常稳定,不会因为新增一个数据源而变得复杂。
2. 插件即数据源
每个数据源(飞机、船舶、卫星)实现相同的接口:
订阅数据流→ 源源不断地获取位置数据转换数据格式→ 统一成系统理解的格式渲染到地球→ 由核心引擎负责高效渲染
这种设计让系统非常灵活。你可以用一个插件来管理 100 架飞机,也可以用同一个插件同时管理飞机、无人机、直升机——只要它们的数据格式兼容。
3. 分离渲染和数据处理
高性能的秘诀在于不让数据处理成为瓶颈。WorldWideView 用 TypeScript + Next.js 来做数据处理和业务逻辑,然后把"怎么渲染"这个任务交给 CesiumJS。数据处理可以在后端做,也可以在浏览器做,CesiumJS 只负责把这些数据高效地显示出来。
核心技术实现
如果你想深入理解为什么这个项目能在浏览器里流畅地处理 10 万+ 对象,这一节讲几个关键的技术决策:
1. Cesium Primitives:批量渲染的核心
CesiumJS 有两种方式来渲染地球上的对象:
- Entity API - 每个飞机、船舶是一个独立的 Entity 对象,功能丰富但性能一般
- Primitive API - 把多个对象打包成一个 Primitive,由 GPU 批量渲染
WorldWideView 选择了 Primitive API,理由很简单:Entity API 适合显示几十个对象,Primitive API 适合几万甚至几十万个。
具体怎么做的?假设你有 1 万架飞机要显示:
- 不是创建 1 万个 Entity 对象(这会让浏览器卡死)
- 而是创建一个大的 Primitive,内部包含 1 万个"飞机"
- 这个 Primitive 只需要一次 GPU 绘制调用,而不是 1 万次
- 当飞机位置更新时,只需要更新 Primitive 内部的数据,不需要重新创建对象
这样做的效果是,性能开销从"随对象数量线性增长"变成"基本固定"。
2. 实时数据流处理:WebSocket + 数据变换管道
飞机、船舶、卫星的数据不是一次性加载的,而是源源不断的流数据。WorldWideView 的做法是:
- 用 WebSocket 或 HTTP 长连接接收实时数据
- 数据到达后立即进入一个"转换管道"
- 每个插件定义自己的转换逻辑(如何把原始数据转成坐标 + 属性)
- 转换后的数据交给渲染引擎
这个设计的妙处在于,数据处理和渲染完全解耦。数据可以在浏览器处理,也可以在服务器端预处理,甚至可以在 WebWorker 中处理(避免阻塞主线程)。
3. 插件系统的接口约定
WorldWideView 的插件必须实现一个统一的接口。简化来说大概是这样:
interface DataSource {
// 订阅数据流
subscribe(callback: (data) => void): void;
// 把原始数据转成{经度, 纬度, 高度, 方向, 属性}
transform(rawData: any): GeoPosition;
// 告诉渲染引擎这是什么类型的对象(飞机/船舶/卫星)
getObjectType(): string;
}只要插件实现了这个接口,核心引擎就知道怎么处理它。这是一个非常聪明的设计——核心不需要知道飞机数据长什么样,不需要知道卫星轨道怎么计算,它只需要"拿到数据 → 渲染"。
4. 地理坐标系统和性能优化
地理数据涉及两个坐标系统的转换:
- 经纬度坐标 - 地球表面位置(如 GPS 坐标)
- 笛卡尔坐标 - 3D 图形学坐标(屏幕渲染需要)
这个转换在 WebGL 中是很贵的操作。WorldWideView 的做法是:
- 大部分计算在 CPU 端完成(JavaScript)
- 只把最终的 3D 坐标送到 GPU
- 或者把转换逻辑写在 GPU Shader 中,由 GPU 并行计算
这样能显著降低 CPU 压力,腾出性能给数据处理。
5. 内存管理和动态加载
10 万个对象的数据量是很大的。WorldWideView 用了几个策略来管理内存:
- 视锥剔除 - 只加载相机能看到的地理区域的数据
- LOD(细节级别) - 远处的飞机用简单的图标,近处用复杂的模型
- 数据流预缓冲 - 新数据到达时不是立即全部加载,而是按需缓冲,旧数据逐步释放
这些优化保证了即使数据源源不断涌入,内存占用也能保持在合理范围内。
适合哪些场景
适合的场景:
- 航空公司的航班实时监控系统
- 海事部门的船舶追踪平台
- 卫星地面站的轨道监控
- 物流企业的车队管理
- 无人机集群控制系统
- 紧急救援的实时指挥中心
这些场景的共同点是:数据源多样(不只是一种数据),更新频繁(实时性要求高),对象数量大(性能要求高)。
不太适合的场景:
- 静态地图应用(不需要实时更新)
- 复杂的地理分析(需要更多的 GIS 工具)
- 超大规模数据集(100+ 万个对象可能需要额外优化)
数据源从哪里来
WorldWideView 的核心价值就在于它能把多个不同的数据源整合到一个地球上。根据项目的代码,它内置了 7 种数据源插件,每种插件连接到不同的数据提供方。
项目内置的 7 种数据源
| 数据源类型 | 使用的 API/服务 | 覆盖范围 | 成本 |
|---|---|---|---|
| 航空数据 | OpenSky Network / adsb.fi | 全球飞行中的商业航班 | 免费(adsb.fi)/ 免费+付费(OpenSky) |
| 海事数据 | 内置 AIS 接收器支持 | 全球海域船舶实时位置 | 取决于 AIS 数据源 |
| 摄像头监控 | Insecam API | 全球开放网络摄像头 | 免费 |
| 地理数据 | GeoJSON 标准格式 | 自定义地理边界和特征 | 免费 |
| 地缘政治边界 | 内置数据库 | 国家、省份、地区边界 | 免费 |
| 军事设施 | military_bases.geojson | 全球军事基地位置 | 公开数据 |
| 野火监控 | 实时野火追踪数据源 | 全球野火分布 | 免费/付费 |
关键数据源详解
1. 航空数据 - OpenSky Network + adsb.fi
项目优先使用这两个数据源:
-
OpenSky Network(https://opensky-network.org)- (opens in a new tab) 全球最大的开放 ADS-B 数据库
- 免费层:支持基础 API 访问
- 付费层:无限制 API 额度
- 特色:项目配置支持"多账户轮换"(comma-separated clientId:clientSecret pairs),可以绕过单账户 4000 积分/天的限制
-
adsb.fi(https://adsb.fi)- (opens in a new tab) 军用和民用航空数据
- 完全开放,不需要 API 密钥
- 速率限制:1 请求/秒
- 更新频率:实时
2. 摄像头数据 - Insecam
项目集成了 insecam-api,可以获取全球开放的网络摄像头实时画面。这是一个独特的功能——很多地方的网络摄像头因为没有正确配置安全认证,导致直播流公开可访问。
3. 地形和影像 - Cesium Ion + Bing Maps
用于渲染高保真的地球背景:
- Cesium Ion Token - 提供官方 3D 地形和默认影像
- Bing Maps API(可选)- 提供更高分辨率的卫星影像
4. 数据存储 - Supabase
所有实时数据都可以持久化到 Supabase(基于 PostgreSQL 的 BaaS 平台):
- 保存历史追踪轨迹
- 支持用户账户和认证
- 支持实时数据库订阅
怎么创建自定义数据源插件
如果想添加自己的数据源,项目的架构非常开放。在 src/plugins/ 目录中,每个插件遵循统一的接口。大致步骤是:
-
在
src/plugins/下创建新文件夹,比如src/plugins/mydata/ -
实现标准接口(TypeScript):
// plugin interface
export interface DataSourcePlugin {
name: string; // 数据源名称
description: string; // 描述
subscribe(callback: (data) => void): void; // 订阅数据流
transform(rawData: any): GeoPosition; // 转换为地理坐标
getObjectType(): string; // 对象类型
}- 数据格式转换 - 把原始数据转成:
{
latitude: number,
longitude: number,
altitude?: number,
heading?: number, // 方向角度
properties?: object // 其他属性
}-
配置环境变量(
.env.local)- 如果数据源需要 API 密钥或端点 -
在主应用中注册插件 - 告诉系统这个新插件存在
得益于模块化设计,添加一个新数据源只需要 50-100 行代码。项目文档提供了完整的示例。
项目还支持的高级特性
- WebSocket 实时推流 - 用
ws库接收实时数据流 - HLS 视频流 - 用
hls.js在地图上播放实时视频 - 多账户 API 轮换 - 绕过 API 速率限制,支持水平扩展
怎么体验
如果你想看看效果,拉下代码很简单:
git clone https://github.com/silvertakana/worldwideview.git
cd worldwideview
npm install
npm run dev打开 http://localhost:3000,你就能看到一个 3D 地球。项目预置了一些演示数据源(飞机、卫星等),直接就能看到各种数据在地球上实时运动的效果。
如果你想深入研究代码或自己添加数据源,项目提供了完整的文档:
- 架构设计文档 - 理解为什么这样设计
- 插件开发指南 - 如何写一个自定义数据源
- API 文档 - 核心系统的接口说明
写在最后
WorldWideView 这个项目的价值,不只是"又一个地理可视化工具",而是展示了如何用 Web 技术架构一个专业级别的实时数据平台。
很多人以为做飞机监控、船舶追踪这种系统必须用专业 GIS 软件或者特殊的行业方案。但这个项目证明了,用开源的 Web 技术,只要设计得当,也能达到专业级的效果——而且代码完全透明,可以自由定制。
如果你的项目涉及实时地理数据展示、多源数据融合、或者需要在 Web 上做地理信息系统,这个项目的设计思想值得深入学习。特别是它的"模块化数据源"和"高性能渲染"这两个核心思想,可以应用到很多其他场景。
GitHub 项目地址:https://github.com/silvertakana/worldwideview (opens in a new tab)