【Cesium】六、实现鹰眼地图(三维)与主图联动效果

一、前言

上一篇文章:【Cesium】五、地图实现鹰眼效果(三维),虽然实现了3D 的鸟瞰图效果,但是只有鸟瞰图跟着 主地图在动,如果 在鸟瞰图上操作 主地图却不会跟着同步。本文则是实现主地图与鸟瞰图的联动效果。

本文参考文章:cesium实现鹰眼地图(三维)与主图联动效果

二、效果

在这里插入图片描述

三、实现方法

2.1 思路

鹰眼地图与主图联动,需要判断是主图在动,还是鹰眼地图在动,即需要判断触发事件,否者会造成循环联动,无法实现效果。

2.2 方法

utils 下新建HawkEye3DMap.js 文件,代码如下:

import * as Cesium from "cesium";
/**
 * @description: 三维鹰眼地图及与主图联动
 * @param {*}
 * @return {*}
 */
export class HawkEye3DMap {
    constructor(viewer) {
        // 主图
        this._viewer = viewer;
        // 鹰眼图
        this._hawkEyeMap = null;
        // 判断事件是主图触发还是鹰眼地图触发
        this._isMainMapTrigger = false;
        this._isEyeMapTrigger = false;
    }

    // 初始化函数
    _init() {
        this._divInit();
        this._mapInit();
    }

    // 创建div,并设置样式
    _divInit() {
        let hawkEyeDiv = document.createElement("div");
        hawkEyeDiv.setAttribute('id', "hawkEye3dMap");
        hawkEyeDiv.style.cssText = "position: absolute;left: 70% ;top: 2% ;border-radius: 50% ;height: 160px;width: 160px;overflow: hidden;border: 2px solid #002FA7;"
        document.getElementsByTagName("body").item(0).appendChild(hawkEyeDiv);
    };

    _mapInit() {
        // div创建完成后才能初始化地图,否则会找不到div保错
        // 初始化地图
        this._hawkEyeMap = new Cesium.Viewer('hawkEye3dMap', {
            infoBox: false,
            geocoder: false,
            homeButton: false,
            sceneModePicker: false,
            baseLayerPicker: false,
            navigationHelpButton: false,
            animation: false,
            timeline: false,
            fullscreenButton: false,
        });
        this._hawkEyeMap.cesiumWidget.creditContainer.style.display = 'none';
        this._hawkEyeMap.scene.backgroundColor = Cesium.Color.TRANSPARENT;
        this._hawkEyeMap.imageryLayers.removeAll();

        // 鹰眼图中添加高德路网中文注记图(鹰眼图中坐标偏移一点不影响)
        this._hawkEyeMap.imageryLayers.addImageryProvider(
            new Cesium.UrlTemplateImageryProvider({
                url: "http://webrd02.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}",
                minimumLevel: 3,
                maximumLevel: 18
            })
        );

        // 引起事件监听的相机变化幅度
        this._viewer.camera.percentageChanged = 0.02;
        this._hawkEyeMap.camera.percentageChanged = 0.5;

        this._bindEvent();
    }

    // 绑定事件
    _bindEvent() {
        // 鹰眼与主图同步
        this._viewer.camera.changed.addEventListener(this._syncEyeMap, this);
        // 第一次刷新渲染时联动
        this._viewer.scene.preRender.addEventListener(this._syncEyeMap, this);

        // 主图与鹰眼图同步
        this._hawkEyeMap.camera.changed.addEventListener(this._syncMap, this);
        this._hawkEyeMap.scene.preRender.addEventListener(this._syncMap, this);
    }

    // 同步主图与鹰眼地图
    _syncEyeMap() {
        // 监听主图
        new Cesium.ScreenSpaceEventHandler(this._viewer.canvas).setInputAction(() => {
            this._isMainMapTrigger = true;
            this._isEyeMapTrigger = false;
        }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

        // 判断是否为主图移动
        if (!this._isMainMapTrigger) {
            return false;
        }

        this._hawkEyeMap.camera.flyTo({
            destination: this._viewer.camera.position,
            orientation: {
                heading: this._viewer.camera.heading,
                pitch: this._viewer.camera.pitch,
                roll: this._viewer.camera.roll,
            },
            duration: 0.0,
        })
    }

    // 鹰眼地图与主图联动效果
    _syncMap() {
        // 监听鹰眼地图
        new Cesium.ScreenSpaceEventHandler(this._hawkEyeMap.canvas).setInputAction(() => {
            this._isMainMapTrigger = false;
            this._isEyeMapTrigger = true;
        }, Cesium.ScreenSpaceEventType.LEFT_DOWN)

        // 判断是否为鹰眼地图移动
        if (!this._isEyeMapTrigger) {
            return false;
        }
        this._viewer.camera.flyTo({
            destination: this._hawkEyeMap.camera.position,
            orientation: {
                heading: this._hawkEyeMap.camera.heading,
                pitch: this._hawkEyeMap.camera.pitch,
                roll: this._hawkEyeMap.camera.roll,
            },
            duration: 0.0,
        })
    }
}

2.3 使用

首先在vue文件中引入刚刚的js文件

import { HawkEye3DMap } from "@/utils/HawkEye3DMap.js"

随后在script 中调用方法

// 鹰眼地图初始化 联动效果
let hawkEyeMap = new HawkEye3DMap(viewer);
hawkEyeMap._init();

App.vue

上面是部分代码,下面附上App.vue的全部代码,仅供参考

<template>
  <div id="cesiumContainer"></div>
  <div id="hawkEyeMap"></div>
</template>
<script setup>
import { onMounted, reactive, ref } from "vue";
import * as Cesium from "cesium";
import { HawkEye3DMap } from "@/utils/HawkEye3DMap.js"
const initFn = async () => {
  const viewer = new Cesium.Viewer("cesiumContainer", {
    infoBox: false,
    geocoder: false,
    homeButton: false,
    sceneModePicker: false,
    baseLayerPicker: true,
    navigationHelpButton: false,
    animation: false,
    timeline: false,
    fullscreenButton: false,
    vrButton: false,
  });
  viewer._cesiumWidget._creditContainer.style.display = "none"; //取消版权信息
  const imageLayers = viewer.scene.imageryLayers;
  imageLayers.remove(imageLayers.get(0)); //移除默认影像图层
  const TDTTK = "337bc7a038fe9d239af76ab013ff4594"; //填入你自己的天地图Key
  // 天地图影像
  const tdtLayer = new Cesium.WebMapTileServiceImageryProvider({
    url: `http://t0.tianditu.com/img_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={TileMatrix}&TILEROW={TileRow}&TILECOL={TileCol}&tk=${TDTTK}`,
    layer: "tdt",
    style: "default",
    format: "image/jpeg",
    tileMatrixSetID: "w",
    maximumLevel: 18,
    show: false,
  });
  viewer.imageryLayers.addImageryProvider(tdtLayer);
  // 天地图注记
  const tdtAnnotionLayer = new Cesium.WebMapTileServiceImageryProvider({
    url: `http://t0.tianditu.com/cia_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cia&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={TileMatrix}&TILEROW={TileRow}&TILECOL={TileCol}&tk=${TDTTK}`,
    layer: "tdtAnno",
    style: "default",
    format: "image/jpeg",
    tileMatrixSetID: "w",
    maximumLevel: 18,
    show: false,
  });
  viewer.imageryLayers.addImageryProvider(tdtAnnotionLayer);


  // 鹰眼地图初始化 联动效果
  let hawkEyeMap = new HawkEye3DMap(viewer);
  hawkEyeMap._init();

};

onMounted(() => {
  // Cesium 初始化
  initFn();
});
</script>
<style>
#app {
  width: 100%;
  height: 100%;
  font-family: sans-serif;
  text-align: center;
}

html,
body,
#cesiumContainer {
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  overflow: hidden;
}

/* 鹰眼图样式 */
#hawkEyeMap {
  position: absolute;
  left: 70%;
  top: 2%;
  border-radius: 50%;
  height: 160px;
  width: 160px;
  overflow: hidden;
  border: 2px solid #002FA7;
}
</style>

后面我还会更新更多关于cesium知识,敬请关注。