【Cesium】四、地图实现鹰眼效果2D

参考文章:cesium实现鹰眼地图(2D)效果

在原文的基础上,添加、注释各一处代码,解决两处报错问题。文章底部提供完整的vue代码

一、实现效果

在这里插入图片描述

二、实现方法

基于渲染效率和鹰眼地图的实用功能等考虑,鹰眼地图只需设置为二维即可。

这里主要介绍二维鹰眼地图的设置与视角更新。三维鹰眼地图可以直接通过设置鹰眼地图与主图的相机参数完全一致即可,但是二维鹰眼地图上方指北且不变,因此三维的方法并不适用。

而需要通过获取主图中心点,相机与中心点的距离等参数来设置鹰眼地图的相机。

2.1 核心函数

这里将主要的函数,包括鹰眼地图div的动态创建,鹰眼地图的相机设置等封装成了HawkEye2DMap类。utils下新建文件HawkEye2DMap.js,完整代码如下:

import * as Cesium from "cesium";
/**
 * @description: 二维鹰眼地图功能
 * @param {*}
 * @return {*}
 */
export class HawkEye2DMap {
    constructor(viewer) {
        // 主图
        this._viewer = viewer;
        // 鹰眼图
        this._hawkEyeMap = null;
    }

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

    // 动态创建div,及div初始化
    _divInit() {
        let hawkEyeDiv = document.createElement("div");
        hawkEyeDiv.setAttribute('id', "hawkEye2dMap");
        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() {
        this._hawkEyeMap = new Cesium.Viewer('hawkEye2dMap', {
            geocoder: false,
            homeButton: false,
            sceneModePicker: false,
            baseLayerPicker: false,
            navigationHelpButton: false,
            animation: false,
            timeline: false,
            fullscreenButton: false,
            // 鹰眼地图中设置为二维地图
            sceneMode: Cesium.SceneMode.SCENE2D,
        });
        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);
    }

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

        // 但当鹰眼图为二维地图时,则不能直接设置
        let viewCenter = new Cesium.Cartesian2(
            // Math.floor取整函数
            Math.floor(this._viewer.canvas.clientWidth / 2),
            Math.floor(this._viewer.canvas.clientHeight / 2)
        );
        // pickEllipsoid用于将屏幕坐标转换为世界坐标
        let viewCenterPos = this._viewer.scene.camera.pickEllipsoid(viewCenter);
        if (!viewCenterPos) {
            return false;
        }

        // postionWC:标准世界坐标系坐标
        let distance = Cesium.Cartesian3.distance(viewCenterPos, this._viewer.scene.camera.positionWC);
        this._hawkEyeMap.scene.camera.lookAt(viewCenterPos, new Cesium.Cartesian3(0.0, 0.0, distance));
    }
}

2.2 代码调用

引入二维鹰眼地图的js文件后,调用即可。

import { HawkEye2DMap } from '@/utils/HawkEye2DMap.js';

定义方法,后续onMounted中调用即可

// 鹰眼地图 
const HawkEye2DMapFn = () => {
  let hawkEyeMap = new HawkEye2DMap(viewer.value);
  hawkEyeMap._init();
}

三、App.vue 代码

修改完后App.vue完整代码如下(供参考,相对于之前文章,重新定义了viewer,使用时要注意viewer.value):

<template>
  <div id="cesiumContainer"></div>
</template>
<script setup>
import { onMounted, reactive, ref } from "vue";
import * as Cesium from "cesium";
import CesUtils from "@/utils/Ces_utils";
// import "@/utils/HawkEye2DMap"
import { HawkEye2DMap } from '@/utils/HawkEye2DMap.js';
const cesUtils = CesUtils();
const viewer = ref(null)
const initFn = async () => {
  viewer.value = 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.value._cesiumWidget._creditContainer.style.display = "none"; //取消版权信息
  const imageLayers = viewer.value.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.value.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.value.imageryLayers.addImageryProvider(tdtAnnotionLayer);


};

// 开场动画
const AnimationFn = () => {
  let position = {
    lon: 118.7969,
    lat: 32.0603,
    height: 20000,
  };
  cesUtils.flyToPosition(viewer.value, position, 4);
}
// 鹰眼地图 
const HawkEye2DMapFn = () => {
  let hawkEyeMap = new HawkEye2DMap(viewer.value);
  hawkEyeMap._init();
}

onMounted(() => {
  // Cesium 初始化
  initFn();
  // 鹰眼2D效果
  HawkEye2DMapFn()
  // 开场动画
  AnimationFn()
});
</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;
}
</style>

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