在构建内网三维 GIS 系统或工业级可视化平台时,很多开发者都会遇到 CesiumJS 依赖网络地图服务的问题,比如默认使用 Bing、Ion 提供的在线地形与影像服务。但在无网络、私有化部署或内网安全环境下,我们就必须提供离线的地图和地形服务。
本文将基于 NestJS + CesiumJS ,手把手实现一个离线地图瓦片服务 + 离线地形服务的完整方案。
🧰 技术选型
技术 | 用途 |
---|---|
NestJS | 后端服务框架,提供地图/地形文件 |
CesiumJS | 前端三维可视化引擎 |
地图瓦片(TMS) | 提供离线影像,如天地图、谷歌等 |
地形数据(QuantizedMesh) | 提供离线地形数据支持 |
@nestjs/serve-static | 提供静态文件服务 |
目录结构预览
bash
cesium-offline-server/
├── src/
├── public/
│ ├── tiles/ # 离线影像瓦片(z/x/y.png)
│ └── terrain/ # 地形数据(layer.json + .terrain)
├── package.json
└── ...
一、准备地图和地形数据
1.1 离线地图瓦片(TMS)
你可以使用:
- Global Mapper、QGIS 等工具裁剪下载地图
- 参考天地图、谷歌影像瓦片命名规则(z/x/y.png)
最终结构:
arduino
public/tiles/
├── 0/0/0.png
├── 1/0/0.png
├── 1/0/1.png
└── ...
1.2 离线地形数据(QuantizedMesh)
推荐使用以下工具生成:
地形目录结构如下:
arduino
public/terrain/
├── layer.json
├── 0/0/0.terrain
├── 1/0/0.terrain
├── 1/0/1.terrain
└── ...
二、NestJS 项目搭建
2.1 创建 Nest 项目
bash
nest new cesium-offline-server
2.2 安装静态资源模块
bash
npm install @nestjs/serve-static
2.3 配置静态资源服务
编辑 app.module.ts
:
ts
import { Module } from '@nestjs/common';
import { ServeStaticModule } from '@nestjs/serve-static';
import { join } from 'path';
@Module({
imports: [
// 映射 tiles 到 /tiles 路由
ServeStaticModule.forRoot({
rootPath: join(__dirname, '..', 'public/tiles'),
serveRoot: '/tiles',
}),
// 映射 terrain 到 /terrain 路由
ServeStaticModule.forRoot({
rootPath: join(__dirname, '..', 'public/terrain'),
serveRoot: '/terrain',
}),
],
})
export class AppModule {}
2.4 开启跨域
修改 main.ts
:
ts
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.enableCors(); // 必须开启
await app.listen(3000);
}
三、前端 Cesium 接入离线地图和地形
3.1 离线地图瓦片加载
js
const viewer = new Cesium.Viewer("cesiumContainer", {
imageryProvider: new Cesium.UrlTemplateImageryProvider({
url: "http://localhost:3000/tiles/{z}/{x}/{y}.png",
tilingScheme: new Cesium.GeographicTilingScheme(), // WGS84
maximumLevel: 18,
}),
baseLayerPicker: false,
terrainProvider: new Cesium.EllipsoidTerrainProvider(), // 暂不加载地形
});
3.2 离线地形加载
js
viewer.terrainProvider = new Cesium.CesiumTerrainProvider({
url: "http://localhost:3000/terrain",
requestVertexNormals: true,
requestWaterMask: true,
});
四、测试验证与排查建议
✅ 检查资源访问
确保能访问:
http://localhost:3000/tiles/0/0/0.png
http://localhost:3000/terrain/layer.json
http://localhost:3000/terrain/1/0/0.terrain
✅ layer.json 示例:
json
{
"tilejson": "2.1.0",
"format": "quantized-mesh-1.0",
"version": "1.0.0",
"scheme": "tms",
"tiles": ["{z}/{x}/{y}.terrain"],
"attribution": "Offline Terrain",
"bounds": [-180, -90, 180, 90],
"minzoom": 0,
"maxzoom": 14
}
✅ 浏览器调试工具 Network 查看请求是否 200
五、总结
通过本文我们完成了:
- 使用 NestJS 快速部署离线地图和地形服务
- 结构清晰地管理 tiles 和 terrain 资源
- 在 Cesium 前端正确加载离线资源
✅ 优势
- 📡 完全离线:适用于内网、矿井、无人区等环境
- 🛡️ 私有数据保护:不暴露给外部 API
- ⚡ 性能更优:局域网传输,加载快无延迟
🔗 后续拓展
- 支持多地图图层(如天地图、谷歌、OpenStreetMap 切换)
- 加入图层控制 API,动态切换瓦片
- 加入 NestJS 文件上传接口,实现地图服务在线发布管理