Skip to content

组件重写

组件重写就是在不改变 Cesium 源码的基础上,能不能用 Cesium 提供的组件完成自定义的需求。

HomeButton组件

HomeButton组件的功能是返回到系统初始化时的位置,默认是整个球的位置。

但在实际的业务场景中,一般初始化范围都是某一个城市或园区的位置,如何使用 HomeButton组件完成定位呢?

方式一:修改相机的默认矩形范围

Rectangle.fromDegrees() 方法的参数

js
Cesium.Rectangle.fromDegrees(west, south, east, north)
js
// 设置默认视图矩形
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 中添加监听事件

js
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 地图服务。

js
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
    }
  }
}
js
const viewer = new Cesium.Viewer("cesiumContainer", {
  infoBox: false,
  baseLayerPicker: false,
  geocoder: new OpenStreetMapNominatimGeocoder()
})

BaseLayerPicker组件

Cesium 提供了默认的底图、地形图的选择面板,通过修改 baseLayerPicker 的属性 true 或 false 来控制显隐,通过选择面板中的地图或地形图来实现对应图层的切换和显示。

但是这些图层都是在线的资源,如果是离线环境,或者只是显示客户提供的几个图层数据,该如何实现呢?

要实现这个功能,首先了解 BaseLayerPicker 的主要逻辑关系图,如下:

BaseLayerPicker

从上图我们可以看出,要实现不同的ImageryProvider,只需要提供不同的ProviderViewModel,比如BingMap、OSM、ArcGIS、GoogleMaps的,这样在BaseLayerPicker的UI中,就会有多个Provider供用户选择,而交互则由BaseLayerPickerViewModel类负责,用户并不需要关心内部的实现,BaseLayerPickerViewModel类已经帮我们都实现了。

下面我们利用 BaseLayerPicker 的逻辑关系,实现自定义的 ImageryProvider(高德矢量图)和 TerrainPovider(ArcGIS地形),并将其显示在选择器面板中。

js
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
js
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]
}

自定义地图切换

Released under the MIT License.