开源库入门教程 Cesium:3D地球和地图库
文章目录
- Cesium是什么?
- 为什么选择Cesium?
- 快速上手Cesium
- 安装和配置
- 方法1:使用npm安装(适合现代前端工程)
- 方法2:使用CDN(最简单的方式)
- 创建你的第一个Cesium应用
- Cesium的核心概念
- 1. Viewer(查看器)
- 2. Entity(实体)
- 3. DataSource(数据源)
- 4. Primitive(图元)
- 5. Camera(相机)
- 实用技巧和示例
- 加载不同类型的影像图层
- 添加3D建筑和城市模型
- 绘制路径和轨迹
- 交互事件处理
- 性能优化建议
- 常见问题和解决方案
- 1. "terrain provider is not ready"错误
- 2. 坐标转换问题
- 3. 如何测量距离和面积
- 4. 在线和离线部署的区别
- 后续学习资源
- 结语
最近在做项目时需要展示地理数据,我尝试了好几个库后才发现了Cesium这个宝藏!它让我能够在浏览器中创建惊艳的3D地球和地图应用。今天就和大家分享一下我使用Cesium的心得和入门步骤,希望对你有所帮助!
Cesium是什么?
Cesium是一个开源的JavaScript库,专门用于创建高性能的3D地球和地图应用。它最初由AGI(Analytical Graphics, Inc.)公司在2012年开发,现在由Cesium GS公司维护。
Cesium最厉害的地方在于它能在网页浏览器中渲染完整的3D地球,而且不需要任何插件(这点真的太棒了)!它直接使用WebGL技术,所以在现代浏览器中都能流畅运行。
为什么选择Cesium?
在众多地图库中,Cesium有几个突出优势:
-
真正的3D地球 - 不同于很多2D地图库,Cesium提供了一个完整的3D地球模型,支持从太空到街道级别的无缝缩放。
-
时间动态数据 - Cesium有一个内置的时间轴控件,可以展示随时间变化的数据(比如卫星轨道、天气变化等)。
-
精确的地理参考 - 支持各种坐标系统和地理投影,保证数据在地球上的准确位置。
-
海量数据处理能力 - 能够高效处理大量的地理数据,包括地形、影像和矢量数据。
-
活跃的社区支持 - 有完善的文档和活跃的社区,遇到问题很容易找到解决方案。
快速上手Cesium
接下来,我会带你从零开始搭建一个简单的Cesium应用。相信我,比你想象的要简单!
安装和配置
有几种方式可以在项目中使用Cesium:
方法1:使用npm安装(适合现代前端工程)
npm install cesium
安装后,还需要配置一下webpack或其他打包工具,因为Cesium包含了一些静态资源需要特殊处理。
方法2:使用CDN(最简单的方式)
如果你只是想快速尝试,直接在HTML中引入CDN链接就可以了:
<script src="https://cesium.com/downloads/cesiumjs/releases/1.104/Build/Cesium/Cesium.js"></script>
<link href="https://cesium.com/downloads/cesiumjs/releases/1.104/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
注意版本号可能会更新,建议去官网查看最新版本。
创建你的第一个Cesium应用
下面是一个最基础的Cesium应用示例:
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><title>我的第一个Cesium应用</title><script src="https://cesium.com/downloads/cesiumjs/releases/1.104/Build/Cesium/Cesium.js"></script><link href="https://cesium.com/downloads/cesiumjs/releases/1.104/Build/Cesium/Widgets/widgets.css" rel="stylesheet"><style>html, body, #cesiumContainer {width: 100%;height: 100%;margin: 0;padding: 0;overflow: hidden;}</style>
</head>
<body><div id="cesiumContainer"></div><script>// 你需要一个Cesium ion账号获取tokenCesium.Ion.defaultAccessToken = '你的Cesium ion token';// 创建Cesium查看器const viewer = new Cesium.Viewer('cesiumContainer', {terrain: Cesium.Terrain.fromWorldTerrain(),// 开启大气效果skyAtmosphere: true,// 显示底图选择器baseLayerPicker: true});// 设置初始视图为北京viewer.camera.flyTo({destination: Cesium.Cartesian3.fromDegrees(116.4074, 39.9042, 15000),orientation: {heading: Cesium.Math.toRadians(0),pitch: Cesium.Math.toRadians(-90),roll: 0.0}});</script>
</body>
</html>
这段代码会创建一个基本的3D地球,并将视角定位到北京上空。你需要注册一个Cesium ion账号来获取免费的token,这样才能访问Cesium提供的地形和影像服务。
Cesium的核心概念
在开始创建复杂应用前,有必要了解Cesium的几个核心概念:
1. Viewer(查看器)
Viewer是Cesium应用的核心组件,它包含了3D地球和一系列控件。创建一个Viewer非常简单:
const viewer = new Cesium.Viewer('cesiumContainer');
Viewer提供了很多配置选项,例如:
const viewer = new Cesium.Viewer('cesiumContainer', {terrain: Cesium.Terrain.fromWorldTerrain(), // 加载全球地形timeline: true, // 显示时间轴animation: true, // 显示动画控件baseLayerPicker: true, // 显示底图选择器sceneModePicker: true, // 显示场景模式选择器navigationHelpButton: true, // 显示帮助按钮infoBox: true, // 显示信息框fullscreenButton: true // 显示全屏按钮
});
2. Entity(实体)
Entity是Cesium中表示地理对象的基本方式,可以是点、线、面、模型等。例如,添加一个点标记:
viewer.entities.add({position: Cesium.Cartesian3.fromDegrees(116.4074, 39.9042),point: {pixelSize: 10,color: Cesium.Color.RED},label: {text: '北京',font: '14pt sans-serif',pixelOffset: new Cesium.Cartesian2(0, -20)}
});
3. DataSource(数据源)
DataSource用于加载和管理大量实体数据,支持多种格式如GeoJSON、KML、CZML等:
// 加载GeoJSON数据
const dataSource = Cesium.GeoJsonDataSource.load('data/china.geojson', {stroke: Cesium.Color.BLUE,fill: Cesium.Color.BLUE.withAlpha(0.5),strokeWidth: 3
});
viewer.dataSources.add(dataSource);
4. Primitive(图元)
Primitive是更底层的渲染对象,比Entity性能更高,适合渲染大量图形:
// 创建一个蓝色矩形
const instance = new Cesium.GeometryInstance({geometry: new Cesium.RectangleGeometry({rectangle: Cesium.Rectangle.fromDegrees(115, 39, 117, 41),vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT}),attributes: {color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.BLUE.withAlpha(0.5))}
});viewer.scene.primitives.add(new Cesium.Primitive({geometryInstances: instance,appearance: new Cesium.PerInstanceColorAppearance()
}));
5. Camera(相机)
Camera控制视角,可以通过编程方式控制飞行和视角:
// 飞行到特定位置
viewer.camera.flyTo({destination: Cesium.Cartesian3.fromDegrees(121.5, 31.2, 10000), // 上海orientation: {heading: Cesium.Math.toRadians(30), // 朝向pitch: Cesium.Math.toRadians(-45), // 俯仰角roll: 0 // 翻滚角},duration: 3 // 飞行时间(秒)
});
实用技巧和示例
下面分享几个实用的Cesium功能和示例,这些在实际项目中超级有用!
加载不同类型的影像图层
Cesium支持多种影像服务:
// 添加Bing地图影像
viewer.imageryLayers.addImageryProvider(new Cesium.BingMapsImageryProvider({url: 'https://dev.virtualearth.net',key: '你的Bing Maps API密钥',mapStyle: Cesium.BingMapsStyle.AERIAL_WITH_LABELS})
);// 添加WMS服务
viewer.imageryLayers.addImageryProvider(new Cesium.WebMapServiceImageryProvider({url: 'https://某WMS服务地址',layers: '图层名',parameters: {format: 'image/png',transparent: true}})
);
添加3D建筑和城市模型
3D Tiles是Cesium的一项重要技术,用于流式加载大规模3D模型:
// 加载3D建筑模型
const tileset = viewer.scene.primitives.add(new Cesium.Cesium3DTileset({url: Cesium.IonResource.fromAssetId(96188) // 这是纽约的3D建筑模型ID})
);// 设置样式,例如根据建筑高度着色
tileset.style = new Cesium.Cesium3DTileStyle({color: {conditions: [['${height} >= 300', 'color("red")'],['${height} >= 200', 'color("orange")'],['${height} >= 100', 'color("yellow")'],['true', 'color("white")']]}
});
绘制路径和轨迹
可以使用Entity创建动态路径:
// 定义路径点
const positions = [];
for (let i = 0; i < 100; i++) {const longitude = 116.4 + Math.random() * 0.1;const latitude = 39.9 + Math.random() * 0.1;positions.push(Cesium.Cartesian3.fromDegrees(longitude, latitude, 0));
}// 创建路径实体
const path = viewer.entities.add({polyline: {positions: positions,width: 5,material: new Cesium.PolylineGlowMaterialProperty({glowPower: 0.2,color: Cesium.Color.BLUE})}
});// 创建沿路径移动的点
const point = viewer.entities.add({position: new Cesium.CallbackProperty(function(time) {// 计算当前时间在路径上的位置const seconds = Cesium.JulianDate.secondsDifference(time, viewer.clock.startTime);const index = Math.floor(seconds * 5) % positions.length;return positions[index];}, false),point: {pixelSize: 15,color: Cesium.Color.RED}
});// 设置时钟开始运行
viewer.clock.shouldAnimate = true;
交互事件处理
Cesium提供了丰富的事件系统,例如鼠标点击:
// 添加鼠标点击事件处理
const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
handler.setInputAction(function(click) {// 将屏幕坐标转换为地球表面坐标const pickedObject = viewer.scene.pick(click.position);if (Cesium.defined(pickedObject) && pickedObject.id) {// 点击了某个实体console.log('点击了实体:', pickedObject.id);} else {// 将屏幕坐标转换为地球表面坐标const cartesian = viewer.scene.pickPosition(click.position);if (Cesium.defined(cartesian)) {const cartographic = Cesium.Cartographic.fromCartesian(cartesian);const longitude = Cesium.Math.toDegrees(cartographic.longitude);const latitude = Cesium.Math.toDegrees(cartographic.latitude);const height = cartographic.height;console.log(`点击位置:经度=${longitude}, 纬度=${latitude}, 高度=${height}米`);}}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
性能优化建议
使用Cesium开发大型应用时,需要注意性能问题,这里有几个实用的优化技巧:
-
使用Entity还是Primitive?
- 少量对象(<1000):使用Entity,开发更简单
- 大量对象(>1000):使用Primitive,性能更好
-
限制可见性
- 使用
tileset.maximumScreenSpaceError
控制3D Tiles的细节级别 - 设置
entity.show
或primitive.show
根据距离显示或隐藏对象
- 使用
-
使用地形和影像的分层细节(LOD)
- 设置适当的
viewer.scene.screenSpaceCameraController.maximumZoomDistance
- 根据距离切换不同分辨率的影像
- 设置适当的
-
避免频繁更新位置
- 使用
viewer.scene.requestRender()
而不是每帧更新 - 对于动画,使用Cesium的时钟系统和CallbackProperty
- 使用
-
使用BatchTable和GPU批处理
- 对于大量相似的对象,使用BatchTable进行批处理
- 考虑使用Cesium的BatchedInstancedFeatures
常见问题和解决方案
在使用Cesium过程中,我遇到过这些常见问题,分享给大家:
1. "terrain provider is not ready"错误
这通常是因为地形提供者还没有完全加载。解决方法是在使用地形之前先检查其就绪状态:
Cesium.Terrain.fromWorldTerrain().readyPromise.then(function(terrain) {viewer.terrainProvider = terrain;// 现在可以安全地使用地形了});
2. 坐标转换问题
Cesium中有多种坐标系统,常见的有:
- 经纬度坐标(度)
- Cartesian3(笛卡尔坐标)
- Cartographic(弧度表示的经纬度)
它们之间的转换方式:
// 经纬度转Cartesian3
const position = Cesium.Cartesian3.fromDegrees(longitude, latitude, height);// Cartesian3转经纬度
const cartographic = Cesium.Cartographic.fromCartesian(position);
const longitude = Cesium.Math.toDegrees(cartographic.longitude);
const latitude = Cesium.Math.toDegrees(cartographic.latitude);
const height = cartographic.height;
3. 如何测量距离和面积
使用Cesium的空间计算功能:
// 计算两点距离
const point1 = Cesium.Cartesian3.fromDegrees(116.4, 39.9);
const point2 = Cesium.Cartesian3.fromDegrees(121.5, 31.2);
const distance = Cesium.Cartesian3.distance(point1, point2); // 米// 计算多边形面积
const positions = [Cesium.Cartesian3.fromDegrees(116.0, 40.0),Cesium.Cartesian3.fromDegrees(117.0, 40.0),Cesium.Cartesian3.fromDegrees(117.0, 39.0),Cesium.Cartesian3.fromDegrees(116.0, 39.0)
];// 需要手动计算面积,Cesium没有直接的API
// 可以使用turf.js等库辅助计算
4. 在线和离线部署的区别
在线模式需要Cesium ion账号和互联网连接,而离线部署需要:
- 下载并本地托管Cesium静态资源
- 准备本地地形和影像数据
- 配置适当的本地数据提供者
// 使用本地地形
viewer.terrainProvider = new Cesium.CesiumTerrainProvider({url: './terrain'
});// 使用本地影像
viewer.imageryLayers.addImageryProvider(new Cesium.TileMapServiceImageryProvider({url: './imagery'})
);
后续学习资源
如果你想深入学习Cesium,这些资源非常有用:
- Cesium官方文档
- Cesium Sandcastle示例
- Cesium社区论坛
- Cesium GitHub仓库
结语
Cesium是一个功能强大的3D地球和地图库,它让我们能够创建令人惊叹的地理可视化应用。从简单的地图展示到复杂的时空数据分析,Cesium都能胜任。
虽然刚开始学习时有一定的门槛,但一旦掌握了基本概念,你就能快速开发出专业级的地理应用。希望这篇入门教程能够帮助你迈出第一步!
最后的建议是——多看官方示例,多动手实践,遇到问题就去查官方文档和社区。Cesium的世界很大,探索起来非常有趣!
记得,地图和地理数据可视化不仅仅是技术,更是一门艺术。用Cesium,让你的数据在3D世界中活起来吧!