文章目录
-
- Cesium是什么?
- 为什么选择Cesium?
- 快速上手Cesium
- Cesium的核心概念
-
- [1. Viewer(查看器)](#1. Viewer(查看器))
- [2. Entity(实体)](#2. Entity(实体))
- [3. DataSource(数据源)](#3. DataSource(数据源))
- [4. Primitive(图元)](#4. Primitive(图元))
- [5. Camera(相机)](#5. Camera(相机))
- 实用技巧和示例
- 性能优化建议
- 常见问题和解决方案
-
- [1. "terrain provider is not ready"错误](#1. "terrain provider is not ready"错误)
- [2. 坐标转换问题](#2. 坐标转换问题)
- [3. 如何测量距离和面积](#3. 如何测量距离和面积)
- [4. 在线和离线部署的区别](#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安装(适合现代前端工程)
bash
npm install cesium
安装后,还需要配置一下webpack或其他打包工具,因为Cesium包含了一些静态资源需要特殊处理。
方法2:使用CDN(最简单的方式)
如果你只是想快速尝试,直接在HTML中引入CDN链接就可以了:
html
<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应用示例:
html
<!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账号获取token
Cesium.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非常简单:
javascript
const viewer = new Cesium.Viewer('cesiumContainer');
Viewer提供了很多配置选项,例如:
javascript
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中表示地理对象的基本方式,可以是点、线、面、模型等。例如,添加一个点标记:
javascript
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等:
javascript
// 加载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性能更高,适合渲染大量图形:
javascript
// 创建一个蓝色矩形
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控制视角,可以通过编程方式控制飞行和视角:
javascript
// 飞行到特定位置
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支持多种影像服务:
javascript
// 添加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模型:
javascript
// 加载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创建动态路径:
javascript
// 定义路径点
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提供了丰富的事件系统,例如鼠标点击:
javascript
// 添加鼠标点击事件处理
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"错误
这通常是因为地形提供者还没有完全加载。解决方法是在使用地形之前先检查其就绪状态:
javascript
Cesium.Terrain.fromWorldTerrain().readyPromise
.then(function(terrain) {
viewer.terrainProvider = terrain;
// 现在可以安全地使用地形了
});
2. 坐标转换问题
Cesium中有多种坐标系统,常见的有:
- 经纬度坐标(度)
- Cartesian3(笛卡尔坐标)
- Cartographic(弧度表示的经纬度)
它们之间的转换方式:
javascript
// 经纬度转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的空间计算功能:
javascript
// 计算两点距离
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静态资源
- 准备本地地形和影像数据
- 配置适当的本地数据提供者
javascript
// 使用本地地形
viewer.terrainProvider = new Cesium.CesiumTerrainProvider({
url: './terrain'
});
// 使用本地影像
viewer.imageryLayers.addImageryProvider(
new Cesium.TileMapServiceImageryProvider({
url: './imagery'
})
);
后续学习资源
如果你想深入学习Cesium,这些资源非常有用:
结语
Cesium是一个功能强大的3D地球和地图库,它让我们能够创建令人惊叹的地理可视化应用。从简单的地图展示到复杂的时空数据分析,Cesium都能胜任。
虽然刚开始学习时有一定的门槛,但一旦掌握了基本概念,你就能快速开发出专业级的地理应用。希望这篇入门教程能够帮助你迈出第一步!
最后的建议是------多看官方示例,多动手实践,遇到问题就去查官方文档和社区。Cesium的世界很大,探索起来非常有趣!
记得,地图和地理数据可视化不仅仅是技术,更是一门艺术。用Cesium,让你的数据在3D世界中活起来吧!