Cesium实现实时联动鹰眼缩略图

本文基于 Vue3 + Cesium 搭建完整 Demo,采用双 Viewer 实现鹰眼缩略图与主场景实时视角同步;主场景地图使用实景影像图层、鹰眼缩略地图使用矢量道路图层,二者视觉层次分明。

前言:

做三维 GIS 大屏项目时,经常需要一个全局缩略鹰眼图,解决两个核心痛点:

  1. 主三维场景视角拉远 / 拉近后,用户无法快速感知当前地理位置。
  2. 复杂城市场景漫游时,需要直观展示当前相机覆盖范围。

本文完整实现一套实用的鹰眼方案,特性如下:

  1. 双 Viewer 独立渲染,主场景地图使用实时影像图层的底图、鹰眼缩略地图使用矢量道路图层的底图,以便分层区分。
  2. 实时相机联动,主场景底图拖拽 / 旋转 / 缩放,鹰眼缩略图瞬间同步视角。
  3. 锁定鹰眼所有交互,禁止用户操作打乱预览。

演示动态图示如下:

本案例效果展示说明:

  1. 主窗口:实景影像图层,支持自由拖拽、缩放、旋转。
  2. 右下角悬浮窗口:鹰眼矢量路网缩略图,主场景视角任意变化,小地图实时同步。

实现核心原理:

  1. 双 Viewer 实例:页面创建两个独立 Cesium.Viewer,一个用作主场景地图,另一个用作鹰眼缩略地图,两者完全独立渲染。
  2. 相机监听联动 :通过 camera.changed 监听主地图相机变化,设置 percentageChanged 控制触发灵敏度,视角变动 1% 就同步坐标、航向、俯仰、翻滚到鹰眼相机,duration:0 实现无延迟实时同步。
  3. 鹰眼交互锁定:禁用鹰眼小地图平移、缩放、旋转、倾斜等全部操作,仅作为静态预览窗口,避免用户误操作破坏联动逻辑。
  4. 分层底图差异化:主场景地图加载实景影像瓦片,鹰眼缩略地图使用矢量道路瓦片,视觉上清晰区分主次场景,用户一眼就能分辨。

完整代码

1. template 结构:

xml 复制代码
<template>
    <div class="main">

        <!-- 主地图渲染容器 -->
        <div class="content" ref="content" id="earth"></div>

        <!-- 鹰眼小地图容器,通过isShow控制显示透明度 -->
        <div class="hawkeye" :class="{'hawkeyeShow': isShow}" ref="hawkeye" id="hawkeye"></div>

        <!-- 加载遮罩,地图初始化完成后隐藏 -->
        <div class="loading" v-if="!isLoading">Loading...</div>
        
    </div>
</template>

2. script 代码:

xml 复制代码
<script setup>
import { onMounted, nextTick, ref, onUnmounted } from 'vue';
import { token } from '../../utils/common.js';

// 控制鹰眼小地图是否显示
let isShow = ref(false);

// 控制Loading加载状态,地图飞到目标点位后隐藏Loading
let isLoading = ref(false);

// 定时器标识,页面销毁时清除,防止内存泄漏
let myMar = null;
let myMar2 = null;

onUnmounted(() => {
    // 销毁主地图Viewer实例
    if (window.viewer) {
        window.viewer.destroy();
        window.viewer = null;
    }

    // 销毁鹰眼小地图Viewer实例
    if (window.viewerEye) {
        window.viewerEye.destroy();
        window.viewerEye = null;
    }

    // 清除显示鹰眼的定时器
    if (myMar) {
        clearTimeout(myMar);
        myMar = null;
    }

    // 清除加载完成飞行镜头的定时器
    if (myMar2) {
        clearTimeout(myMar2);
        myMar2 = null;
    }
});

onMounted(() => {
    nextTick(() => {
        // 初始化主三维地图
        initMap();
        // 3600毫秒后显示右下角鹰眼小地图
        myMar = setTimeout(() => {
            isShow.value = true;
        }, 3600);
    });
});

// 初始化主Cesium三维地图的方法
const initMap = () => {

    // 设置 Cesium Ion 的token
    Cesium.Ion.defaultAccessToken = token;

    // 设置默认视角范围(中国区域)
    Cesium.Camera.DEFAULT_VIEW_RECTANGLE = Cesium.Rectangle.fromDegrees(89.5, 20.4, 110.4, 61.2);

    // 实例化主地图Viewer,关闭全部多余UI控件,简化界面
    window.viewer = new Cesium.Viewer('earth', {
        animation: false,  // 时间动画控件
        timeline: false,  // 时间轴
        infoBox: false,  // 点击要素弹窗
        geocoder: false,  // 搜索框
        homeButton: false,  // 复位视角按钮
        sceneModePicker: false,  // 2D/3D切换按钮
        baseLayerPicker: false,  // 底图切换面板
        navigationHelpButton: false,  // 操作帮助弹窗
        fullscreenButton: false,  // 全屏按钮
        selectionIndicator: false,  // 选中要素高亮框
        shouldAnimate: false  // 关闭自动动画渲染,节省性能
    });

    // 加载高德卫星影像底图(主三维场景)
    let imgLayer = new Cesium.UrlTemplateImageryProvider({
        url: "https://webst02.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}",
        minimumLevel: 4,  // 最小加载层级,避免低层级空白
        maximumLevel: 18  // 最大瓦片层级,精度上限
    });

    // 将高德卫星图层添加到主地图
    window.viewer.imageryLayers.addImageryProvider(imgLayer);

    // 调用初始化右下角鹰眼小地图的方法
    addHawkeye();

    // 6秒后加载完成,隐藏Loading并飞向初始化定义好的视角
    myMar2 = setTimeout(() => {
        isLoading.value = true;
        flyTo();
    }, 6000);
};

// 创建右下角鹰眼缩略小地图,实时同步主地图相机视角的方法
const addHawkeye = () => {
    // 实例化鹰眼独立Viewer,同样关闭所有UI控件
    window.viewerEye = new Cesium.Viewer('hawkeye', {
        animation: false,  // 时间动画控件
        timeline: false,  // 时间轴
        infoBox: false,  // 点击要素弹窗
        geocoder: false,  // 搜索框
        homeButton: false,  // 复位视角按钮
        sceneModePicker: false,  // 2D/3D切换按钮
        baseLayerPicker: false,  // 底图切换面板
        navigationHelpButton: false,  // 操作帮助弹窗
        fullscreenButton: false,  // 全屏按钮
        selectionIndicator: false,  // 选中要素高亮框
        shouldAnimate: false  // 关闭自动动画渲染,节省性能
    });

    // 鹰眼使用高德矢量道路图,和主卫星图做视觉区分
    let layer = 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: 4,
        maximumLevel: 18
    });
    window.viewerEye.imageryLayers.addImageryProvider(layer);
    window.viewerEye.cesiumWidget.creditContainer.style.display = 'none';

    // 禁用鹰眼小地图所有相机操作,仅作为预览,禁止用户拖拽/缩放/旋转
    window.viewerEye.scene.screenSpaceCameraController.enableRotate = false;  // 禁止旋转
    window.viewerEye.scene.screenSpaceCameraController.enableTranslate = false;  // 禁止平移
    window.viewerEye.scene.screenSpaceCameraController.enableZoom = false;  // 禁止缩放
    window.viewerEye.scene.screenSpaceCameraController.enableTilt = false;  // 禁止俯仰倾斜
    window.viewerEye.scene.screenSpaceCameraController.enableLook = false;  // 禁止视角环顾

    // 设置相机变化灵敏度:相机位置变动1%即触发更新鹰眼
    window.viewer.camera.percentageChanged = 0.01;

    // 监听主地图相机视角变化事件,同步更新鹰眼相机
    window.viewer.camera.changed.addEventListener(reViewer);
};


/**
 * 主地图相机变化回调函数
 * 实时同步主地图相机位置、旋转角度到鹰眼小地图
 */
const reViewer = () => {
    window.viewerEye.camera.flyTo({
        destination: window.viewer.camera.position,  // 同步主地图相机三维坐标
        // 同步主地图三轴旋转角度:航向、俯仰、翻滚
        orientation: {
            heading: window.viewer.camera.heading,
            pitch: window.viewer.camera.pitch,
            roll: window.viewer.camera.roll
        },
        duration: 0.0  // 过渡时长0,无动画、瞬间同步,保证实时性
    });
};


// 飞向初始化定义好的视角的方法,本案例是初始化定位到上海陆家嘴东方明珠区域
const flyTo = () => {
    window.viewer.camera.flyTo({
        destination: Cesium.Cartesian3.fromDegrees(121.50182100128413, 31.218959447345714, 886.4263961282597),
        orientation: {
            heading: Cesium.Math.toRadians(3.778551545723811),  // 航向角
            pitch: Cesium.Math.toRadians(-23.269096837121424),  // 俯仰角
            roll: Cesium.Math.toRadians(359.9999900192268)  // 翻滚角
        },
        duration: 6  // 飞行时长6秒
    });
};
</script>

3.css样式代码:

css 复制代码
* {
    margin: 0;
    padding: 0;
}

.main {
    width: 100%;
    height: 100vh;
    position: relative;
}

.content {
    width: 100%;
    height: 100%;
    position: relative;
    z-index: 1;
}

.hawkeye {
    width: 450px;
    height: 450px;
    position: absolute;
    right: 20px;
    bottom: 20px;
    z-index: 2;
    background-color: #EEE;
    opacity: 0;
    border-radius: 4px;
    border: 4px solid #EEE;
}

.hawkeyeShow {
    opacity: 1;
}

.loading {
    width: 100%;
    height: 100%;
    position: absolute;
    left: 0;
    top: 0;
    z-index: 3;
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: 34px;
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: 50px;
    color: #000000;
}

现有方案优化可拓展的参数调整(性能可优化点):

  1. 鹰眼瓦片层级限制:可降低鹰眼 maximumLevel 至 14,减少小地图瓦片请求数量,低配设备防掉帧。
  2. 降低同步频率:调大 percentageChanged 数值(如 0.03),减少相机回调执行次数。

本文案例中使用的高德瓦片资源仅用于学习、技术研究演示,不作线上商用部署场景使用。若企业项目正式上线使用同类地图瓦片资源,请自行前往对应地图服务商平台完成资质认证并申请合规调用密钥。

相关推荐
qq_422152572 小时前
视频转 GIF 工具怎么选?2026 年动图制作方案与画质参数对比
javascript·vue.js·音视频
2501_912784082 小时前
跨境电商独立站技术选型:为什么React+Vue+Laravel成为主流?
vue.js·react.js·laravel·taocarts
一坨阿亮3 小时前
使用e-tree开发树形穿梭框
javascript·vue.js·elementui
独泪了无痕3 小时前
Vue集成uuid生成唯一标识实践指南
前端·vue.js
学Linux的语莫14 小时前
Vue 3 入门教程
前端·javascript·vue.js
qq43569470116 小时前
Vue04
前端·vue.js
万物更新_19 小时前
vue框架
前端·javascript·vue.js·笔记
英勇无比的消炎药1 天前
一文吃透TinyRobot Bubble:从基础组件搭建完整AI消息渲染体系
vue.js
英勇无比的消炎药1 天前
深挖底层:TinyRobot Bubble消息气泡组件核心技术原理
vue.js