组件重写
组件重写就是在不改变 Cesium 源码的基础上,能不能用 Cesium 提供的组件完成自定义的需求。
HomeButton组件
HomeButton组件的功能是返回到系统初始化时的位置,默认是整个球的位置。
但在实际的业务场景中,一般初始化范围都是某一个城市或园区的位置,如何使用 HomeButton组件完成定位呢?
方式一:修改相机的默认矩形范围
Rectangle.fromDegrees() 方法的参数
Cesium.Rectangle.fromDegrees(west, south, east, north)
// 设置默认视图矩形
Cesium.Camera.DEFAULT_VIEW_RECTANGLE = Cesium.Rectangle.fromDegrees(
105.64986713382211,
28.412226440280833,
115.86644822910478,
34.28236721949601
)
// 设置相机高度,值越小越贴近地面
Cesium.Camera.DEFAULT_VIEW_FACTOR = 0.001
方式二:在 HomeButton 的 viewModel 中添加监听事件
if (viewer.homeButton) {
const command = viewer.homeButton.viewModel.command
command.beforeExecute.addEventListener((e: any) => {
e.cancel = true
viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(
110.75074131172585,
32.069462704278976,
1500000
),
duration: 3,
maximumHeight: 2000000,
easingFunction: Cesium.EasingFunction.QUADRATIC_IN_OUT //缓动效果
})
})
}
Geocoder组件
Geocoder 是地理编码的意思,Cesium 默认采用的是 Bing 地图服务来实现地理编码的功能。
下面通过重写 geocode 方法,将 Cesium 默认的 Bing 地图服务改为 OSM 地图服务。
class OpenStreetMapNominatimGeocoder {
async geocode(input: string) {
const resource = new Cesium.Resource({
url: "https://nominatim.openstreetmap.org/search",
queryParameters: {
format: "json",
q: input
}
})
try {
const results = await resource.fetchJson()
if (!Array.isArray(results)) {
throw new Error(
"Unexpected response format from the geocoding service."
)
}
return results.map(result => {
const boundingBox = result.boundingbox
return {
displayName: result.display_name,
destination: Cesium.Rectangle.fromDegrees(
parseFloat(boundingBox[2]),
parseFloat(boundingBox[0]),
parseFloat(boundingBox[3]),
parseFloat(boundingBox[1])
)
}
})
} catch (error) {
console.error("Error during geocoding:", error)
throw error
}
}
}
const viewer = new Cesium.Viewer("cesiumContainer", {
infoBox: false,
baseLayerPicker: false,
geocoder: new OpenStreetMapNominatimGeocoder()
})
BaseLayerPicker组件
Cesium 提供了默认的底图、地形图的选择面板,通过修改 baseLayerPicker 的属性 true 或 false 来控制显隐,通过选择面板中的地图或地形图来实现对应图层的切换和显示。
但是这些图层都是在线的资源,如果是离线环境,或者只是显示客户提供的几个图层数据,该如何实现呢?
要实现这个功能,首先了解 BaseLayerPicker 的主要逻辑关系图,如下:
从上图我们可以看出,要实现不同的ImageryProvider,只需要提供不同的ProviderViewModel,比如BingMap、OSM、ArcGIS、GoogleMaps的,这样在BaseLayerPicker的UI中,就会有多个Provider供用户选择,而交互则由BaseLayerPickerViewModel类负责,用户并不需要关心内部的实现,BaseLayerPickerViewModel类已经帮我们都实现了。
下面我们利用 BaseLayerPicker 的逻辑关系,实现自定义的 ImageryProvider(高德矢量图)和 TerrainPovider(ArcGIS地形),并将其显示在选择器面板中。
const viewer = new Cesium.Viewer("cesiumContainer", {
infoBox: false,
baseLayerPicker: true
})
const [imageryViewModels, terrainViewModels] = await createImageryProviderViewModels()
viewer.baseLayerPicker.viewModel.imageryProviderViewModels = imageryViewModels
viewer.baseLayerPicker.viewModel.terrainProviderViewModels = terrainViewModels
async function createImageryProviderViewModels() {
const imageryViewModels: any[] = []
const terrainViewModels: any[] = []
/** 创建影像相关地图 */
async function createImageryVM() {
imageryViewModels.push(
new Cesium.ProviderViewModel({
name: "高德矢量",
iconUrl: Cesium.buildModuleUrl(
"Widgets/Images/ImageryProviders/openStreetMap.png"
),
tooltip: "高德矢量地图服务",
creationFunction: function () {
return new Cesium.UrlTemplateImageryProvider({
url: "http://webrd0{s}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}",
subdomains: ["1", "2", "3", "4"]
})
}
})
)
imageryViewModels.push(
new Cesium.ProviderViewModel({
name: "Natural Earth\u00a0II",
iconUrl: Cesium.buildModuleUrl(
"Widgets/Images/ImageryProviders/naturalEarthII.png"
),
tooltip:
"Natural Earth II, darkened for contrast.\nhttp://www.naturalearthdata.com/",
creationFunction: function () {
return Cesium.TileMapServiceImageryProvider.fromUrl(
Cesium.buildModuleUrl("Assets/Textures/NaturalEarthII")
)
}
})
)
}
/** 创建地形相关地图 */
async function createTerrainVM() {
terrainViewModels.push(
new Cesium.ProviderViewModel({
name: "ArcGIS地形",
iconUrl: Cesium.buildModuleUrl(
"Widgets/Images/TerrainProviders/Ellipsoid.png"
),
tooltip: "ArcGIS地形服务",
creationFunction: async function () {
return await Cesium.ArcGISTiledElevationTerrainProvider.fromUrl(
"https://elevation3d.arcgis.com/arcgis/rest/services/WorldElevation3D/Terrain3D/ImageServer",
{
token:
"KED1aF_I4UzXOHy3BnhwyBHU4l5oY6rO6walkmHoYqGp4XyIWUd5YZUC1ZrLAzvV40pR6gBXQayh0eFA8m6vPg.."
}
)
}
})
)
}
await createImageryVM()
await createTerrainVM()
return [imageryViewModels, terrainViewModels]
}