1. 前言
本文中将先调整下相机视角,经纬度可以在谷歌地图中先找到对应的位置,然后右击,就能看到对应的经纬度的值,点击进行复制。复制的值是纬度和经度,注意下面需要赋值的顺序是经度和纬度,需要调换下顺序。在修改或者添加属性前,申请ion必不可少。在已经具备ion token的基础上,了解下切换底图的流程。然后再看看加载来自arcGisOnline的栅格影像是如何实现的。
2. 相机视角
先将地图调整到合适的视角。viewer.camera.setView(options)
将视图跳转到options定义的位置信息中,options是一个对象,可以包含以下属性:
-
destination
: (必需)相机的新位置,可以是一个Cartesian3
坐标,表示经度、纬度和高度。例如:Cesium.Cartesian3.fromDegrees(longitude, latitude, height)
。 -
orientation
: (可选)相机的朝向设置,包括:heading
: 相机的航向(以弧度为单位)。pitch
: 相机的俯仰(以弧度为单位)。roll
: 相机的滚转(以弧度为单位)。
viewer.camera.setView({
// 目的地
destination: Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883, 2000),
// 飞行结束时的视角方向
orientation: {
// 水平方向的角度,以弧度表示
heading: Cesium.Math.toRadians(0.0),
// 垂直方向的角度,以弧度表示
pitch: Cesium.Math.toRadians(-90.0),
// 围绕垂直轴的旋转角度,以弧度表示
roll: 0.0,
},
});
如果需要从一个视角跟踪到另一个视角,可使用viewer.camera.flyTo(options)
,除了可以使用上述options选项之外,增加的可选项属性:
duration
: (可选)相机移动到新位置所需的时间(以秒为单位),如果未指定,则相机立即跳转到新位置。complete
: (可选)一个回调函数,在相机移动完成后调用。cancelable
: (可选)布尔值,指示飞行是否可以被取消。默认为true
。
viewer.camera.flyTo({
// 目的地
destination: Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883, 2000),
// 视角方向
orientation: {
// 水平方向的角度,以弧度表示
heading: Cesium.Math.toRadians(0.0),
// 垂直方向的角度,以弧度表示
pitch: Cesium.Math.toRadians(-40.0),
// 围绕垂直轴的旋转角度,以弧度表示
roll: 0.0,
},
duration: 4.0, // 飞行时间
complete: () => {
// 飞行完成后的回调函数
console.log("相机📷已经到达目的地✈️");
},
});
viewer.camera.flyTo(options)
通过设置目标位置、朝向、持续时间和回调函数,您可以灵活地控制相机的飞行行为,从而增强应用的交互性和用户体验。
3. 申请ion
在我们使用Cesium的过程中,如果没有申请ion,同时没有自己的数据源用的cesium提供的数据源,viewer的底部常常会提示一行小的英文字母。大意就是需要申请access token。 注册获取cesium-tocken入口
在创建Cesium Viewer的时候,将access token填为自己的access token即可。
Cesium.Ion.defaultAccessToken = '<YOUR ACCESS TOKEN HERE>';
4. 切换图层
Cesium应用程序中一个关键元素是Imagery(图层)。瓦片图集合根据不同的投影方式映射到虚拟的三维数字地球表面。依赖于相机指向地表的方向和距离,Cesium会去请求和渲染不同层级的图层详细信息。Cesium默认展示的底图是Bing Maps Aerial,这个图层被打包进Viewer中用于演示。如果要切换其他图层,需要完成ion的申请,并添加该图层的权限。
例如点开视图中地图切换控件按钮,选择Sentinel-2。
提示报错信息:RequestErrorEvent {statusCode: 404, response: '{"code":"ResourceNotFound","message":"Resource Not…UjcyWX_Jd63Vx877udZE&assetRegion=ap-northeast-1"}', responseHeaders: {…}}
这是因为没有设置权限。需要到Cesium ion页面允许Sentinel-2图层的权限,找到该图层并点击添加。如下图所示:
添加成功后,在上述页面的My Assets中,可以看到权限添加成功的内容。查看对应的assetId,添加到展示的图层中。
const layer = viewer.imageryLayers.addImageryProvider(
await Cesium.IonImageryProvider.fromAssetId(3954)
);
视图打开后将展示Sentinel-2图层。
5. ArcGIS 服务器上的地图影像集成
5.1 常用的 ArcGIS Online 图层链接
这里我们使用ArcGIS Online平台上的地图服务。以下是一些常用的 ArcGIS Online 图层链接和服务类型。
- 世界影像图
https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer
2. 世界街道图
https://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer
3. 世界地形图
https://services.arcgisonline.com/ArcGIS/rest/services/World_Terrain_Base/MapServer
4. 世界灰度影像图
https://services.arcgisonline.com/ArcGIS/rest/services/Canvas/World_Gray/MapServer
5.2 ArcGisOnline影像加载
Cesium提供ArcGisMapServerImageryProvider类用于从ArcGIS Server获取影像数据,将服务器上的地图影像集成到cesium中,以便进行3D可视化和分析。cesium.com-ArcGisMapServerImageryProvider
官网上提供了示例代码如下:
// Create an imagery provider from the url directly
const esri = await Cesium.ArcGisMapServerImageryProvider.fromUrl(
"https://ibasemaps-api.arcgis.com/arcgis/rest/services/World_Imagery/MapServer", {
token: "<ArcGIS Access Token>"
});
使用 ArcGIS Online 服务时,是否需要 Access Token 取决于您访问的服务类型,以上提供的是公共的 ArcGIS Online 服务,不需要Access Token。
我们从其中挑选一个World_Street_Map作为案例来使用:
const esri = await Cesium.ArcGisMapServerImageryProvider.fromUrl( "https://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer"
);
这里注意下,有些教程踩坑了,八青妹踩坑的demo案例如下:
var viewer = new Cesium.Viewer('cesiumContainer', {
imageryProvider : new Cesium.ArcGisMapServerImageryProvider({
url : '//services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer'
}),
baseLayerPicker : false
});
如果使用这种老旧的方法,是显示不了地图影像的。显示的是一个水灵灵的蓝色球体。
在上述切换图层中的案例代码中是使用viewer.imageryLayers.addImageryProvider()
来进行切换的,那我们打印下该imagerLayers看看,里面究竟是啥
const viewer = new Cesium.Viewer("cesiumContainer", {
infoBox: false,
});
const imageLayers = viewer.imageryLayers;
console.log(imageLayers);
所以我们这里将这个默认展示的图层清空,然后添加arcgisOnline图层。代码如下:
import { onMounted } from "vue";
import * as Cesium from "cesium";
onMounted(async () => {
Cesium.Ion.defaultAccessToken =
"bulabulabulabula";//替换自己的ion token
const esri = await Cesium.ArcGisMapServerImageryProvider.fromUrl(
"https://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer"
);
const viewer = new Cesium.Viewer("cesiumContainer", {
infoBox: false,
});
const imageLayers = viewer.imageryLayers;
imageLayers.remove(imageLayers.get(0));
imageLayers.addImageryProvider(esri);
});
成功的效果图如下所示:
ps:如果不清空默认的图层,这个贴图覆盖不完整的。效果可以自行试试。
6. 总结
最后,我们将相机视角和arcGisOnline底图结合下看看。