前言

Cesium入门开发系列知识点了解

Cesium api 文档介绍 详细介绍cesium每个类的函数以及属性等等 Cesium 在线例子

内容概览

  1. cesium结合leaflet实现鹰眼图
  2. cesium结合自身api 实现鹰眼图
  3. 源代码

Cesium结合leaflet实现鹰眼图

image.png

核心代码:通过监听cesium视图变化事件联动leaflet视图同步,同时也监听leaflet视图变化事件联动cesium视图同步

在Cesium窗口中添加小地图组件

  1. <template>
  2. <div style="width: 100%; height: 100%">
  3. <div style="position: relative; width: 100%; height: 100%" ref="coreViewer">
  4. <div ref="viewer" style="width: 100%;height:100%" id="viewer"></div>
  5. <leafletMini :center="minimapCenter" :marker="minimapCursor" :zoom="minimapZoom" :viewRect="minimapViewRect"/>
  6. </div>
  7. </div>
  8. </template>
  9. <script>
  10. import bindMinimap from '../scripts/eagleEye'
  11. import leafletMini from '../components/leafletMini.vue'
  12. import {
  13. LMap,
  14. LTileLayer,
  15. LMarker,
  16. LPopup
  17. } from 'vue2-leaflet'
  18. export default {
  19. name: "cesiumView",
  20. components: {
  21. 'leafletMini': leafletMini
  22. },
  23. mounted() {
  24. this.$nextTick(() => {
  25. const viewer = initViewer(this.$refs.viewer)
  26. this.freezedViewer = Object.freeze({viewer})
  27. var that = this
  28. document.addEventListener(Cesium.Fullscreen.changeEventName, () => {
  29. that.isFullscreen = Cesium.Fullscreen.fullscreen
  30. })
  31. })
  32. },
  33. data() {
  34. return {
  35. freezedViewer: undefined,
  36. minimapCenter: undefined,
  37. mizimapZoom: 2,
  38. minimapCrusor: L.latlng(0.0, 0.0),
  39. minimapViewRect: []
  40. }
  41. },
  42. methods: {
  43. bindEagleEyeOnMinimap() {
  44. let h = parseInt(window.getComputedStyle(this.$refs.coreViewer).height)
  45. let w = parseInt(window.getComputedStyle(this.$refs.coreViewer).width)
  46. bindMinimap(this.freezedViewer && this.freezedViewer.viewer,(x,y,zoom,viewRectCoords)=>{
  47. this.minimapCenter=L.latLng(y, x);
  48. this.minimapZoom=zoom;
  49. this.minimapCrusor=L.latLng(y, x);
  50. this.minimapViewRect=viewRectCoords;
  51. },w,h);
  52. }
  53. }
  54. }
  55. </script>

实现联动的代码:eagleEyle.js

import * as Cesium from 'cesium'
//启动鹰眼功能
function bindMinimap(cesiumViewer, funcWithCursorPos,windowWidth,windowHeight) {
    var handler = new Cesium.ScreenSpaceEventHandler(cesiumViewer.scene.canvas);
    handler.setInputAction(function(movement) {
        let dynamicPosition = undefined;
        let ray = cesiumViewer.camera.getPickRay(movement.endPosition);
        dynamicPosition = cesiumViewer.scene.globe.pick(ray, cesiumViewer.scene);
        let corners=getViewRect(cesiumViewer,cesiumViewer.scene.camera,windowWidth,windowHeight);
        if (Cesium.defined(dynamicPosition)) {
            funcWithCursorPos(Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(dynamicPosition).longitude),
                Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(dynamicPosition).latitude),
                getZoomLevel(cesiumViewer.scene.camera),
                corners
            );
        }
    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
}
//计算相机视域
function getViewRect(cesiumViewer,camera,windowWidth,windowHeight){
    let cornerPos = undefined;
    let ray=undefined;
    let positions=[];

    ray = cesiumViewer.camera.getPickRay(new Cesium.Cartesian2(0,0));
    cornerPos = cesiumViewer.scene.globe.pick(ray, cesiumViewer.scene);
    if (!Cesium.defined(cornerPos)){
        return [];
    }
    positions.push([Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(cornerPos).latitude),
    Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(cornerPos).longitude)]);

    ray = cesiumViewer.camera.getPickRay(new Cesium.Cartesian2(0,windowHeight));
    cornerPos = cesiumViewer.scene.globe.pick(ray, cesiumViewer.scene);
    if (!Cesium.defined(cornerPos)){
        return [];
    }
    positions.push([Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(cornerPos).latitude),
    Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(cornerPos).longitude)]);

    ray = cesiumViewer.camera.getPickRay(new Cesium.Cartesian2(windowWidth,windowHeight));
    cornerPos = cesiumViewer.scene.globe.pick(ray, cesiumViewer.scene);
    if (!Cesium.defined(cornerPos)){
        return [];
    }
    positions.push([Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(cornerPos).latitude),
    Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(cornerPos).longitude)]);

    ray = cesiumViewer.camera.getPickRay(new Cesium.Cartesian2(windowWidth,0));
    cornerPos = cesiumViewer.scene.globe.pick(ray, cesiumViewer.scene);
    if (!Cesium.defined(cornerPos)){
        return [];
    }
    positions.push([Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(cornerPos).latitude),
    Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(cornerPos).longitude)]);

    return positions
}
//计算地图缩放等级
function getZoomLevel(camera) {
    let h = camera.positionCartographic.height;
    if (h <= 100) { //0.01
        return 19;
    } else if (h <= 300) { //0.02
        return 18;
    } else if (h <= 660) { //0.05
        return 17;
    } else if (h <= 1300) { //0.1
        return 16;
    } else if (h <= 2600) { //0.2
        return 15;
    } else if (h <= 6400) { //0.5
        return 14;
    } else if (h <= 13200) { //1
        return 13;
    } else if (h <= 26000) { //2
        return 12;
    } else if (h <= 67985) { //5
        return 11;
    } else if (h <= 139780) { //10
        return 10;
    } else if (h <= 250600) { //20
        return 9;
    } else if (h <= 380000) { //30
        return 8;
    } else if (h <= 640000) { //50
        return 7;
    } else if (h <= 1280000) { //100
        return 6;
    } else if (h <= 2600000) { //200
        return 5;
    } else if (h <= 6100000) { //500
        return 4;
    } else if (h <= 11900000) { //1000
        return 3;
    } else {
        return 2;
    }
}
export default bindMinimap;

总结

Vue绑定数据很方便,通过Props就能把Cesium主窗口的数据绑定给miniMap子窗口,不需要写多余的代码。包括小地图的中心位置、鼠标坐标、视域范围都是这样同步过来的,且感受不到任何延迟。

Cesium 结合Cesium实现鹰眼图

import { DomUtil, Util } from '../utils'
import State from '../state/State'
import Widget from './Widget'

const { Cesium } = DC.Namespace

const DEF_OPTS = {
  animation: false,
  baseLayerPicker: false,
  fullscreenButton: false,
  geocoder: false,
  homeButton: false,
  infoBox: false,
  sceneModePicker: false,
  selectionIndicator: false,
  timeline: false,
  navigationHelpButton: false,
  navigationInstructionsInitiallyVisible: false,
  creditContainer: undefined
}

class HawkeyeMap extends Widget {
  constructor() {
    super()
    this._wrapper = DomUtil.create('div', 'dc-hawkeye-map', null)
    this._wrapper.setAttribute('id', Util.uuid())
    this._baseLayer = undefined
    this._delegate = undefined
    this.type = Widget.getWidgetType('hawkeye_map')
    this._state = State.INITIALIZED
  }

  _prepareDelegate() {
    this._delegate = new Cesium.Viewer(this._wrapper, {
      ...DEF_OPTS,
      sceneMode: Cesium.SceneMode.SCENE2D
    })
    this._delegate.scene.screenSpaceCameraController.enableRotate = false
    this._delegate.scene.screenSpaceCameraController.enableTranslate = false
    this._delegate.scene.screenSpaceCameraController.enableZoom = false
    this._delegate.scene.screenSpaceCameraController.enableTilt = false
    this._delegate.scene.screenSpaceCameraController.enableLook = false
    this._delegate.cesiumWidget._creditContainer.style.display = 'none'
    this._delegate.cesiumWidget.screenSpaceEventHandler.removeInputAction(
      Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK
    )
    this._delegate.scene.screenSpaceCameraController.maximumZoomDistance = 40489014.0
    this._delegate.scene.backgroundColor = Cesium.Color.TRANSPARENT
    this._delegate.scene.postProcessStages.fxaa.enabled = true
    this._delegate.imageryLayers.removeAll()
  }

  _bindEvent() {
    this._viewer.camera.changed.addEventListener(this._sync2DView, this)
  }

  _unbindEvent() {
    this._viewer.camera.changed.removeEventListener(this._sync2DView, this)
  }

  _installHook() {
    this._prepareDelegate()
    this._viewer.camera.percentageChanged = 0.01
  }

  _sync2DView() {
    let viewCenter = new Cesium.Cartesian2(
      Math.floor(this._viewer.canvas.clientWidth / 2),
      Math.floor(this._viewer.canvas.clientHeight / 2)
    )
    let worldPosition = this._viewer.scene.camera.pickEllipsoid(viewCenter)
    if (!worldPosition) {
      return false
    }
    let distance = Cesium.Cartesian3.distance(
      worldPosition,
      this._viewer.scene.camera.positionWC
    )
    this._delegate.scene.camera.lookAt(
      worldPosition,
      new Cesium.Cartesian3(0.0, 0.0, distance)
    )
  }

  addBaseLayer(baseLayer) {
    if (!this._delegate || !this._enable) {
      return this
    }
    if (baseLayer) {
      if (this._baseLayer) {
        this._delegate.imageryLayers.remove(this._baseLayer)
      }
      this._baseLayer = this._delegate.imageryLayers.addImageryProvider(
        baseLayer
      )
    }
    return this
  }
}

Widget.registerType('hawkeye_map')

export default HawkeyeMap