本文基于 Vue3 + Cesium 搭建完整 Demo,采用双 Viewer 实现鹰眼缩略图与主场景实时视角同步;主场景地图使用实景影像图层、鹰眼缩略地图使用矢量道路图层,二者视觉层次分明。
前言:
做三维 GIS 大屏项目时,经常需要一个全局缩略鹰眼图,解决两个核心痛点:
- 主三维场景视角拉远 / 拉近后,用户无法快速感知当前地理位置。
- 复杂城市场景漫游时,需要直观展示当前相机覆盖范围。
本文完整实现一套实用的鹰眼方案,特性如下:
- 双 Viewer 独立渲染,主场景地图使用实时影像图层的底图、鹰眼缩略地图使用矢量道路图层的底图,以便分层区分。
- 实时相机联动,主场景底图拖拽 / 旋转 / 缩放,鹰眼缩略图瞬间同步视角。
- 锁定鹰眼所有交互,禁止用户操作打乱预览。
演示动态图示如下:

本案例效果展示说明:
- 主窗口:实景影像图层,支持自由拖拽、缩放、旋转。
- 右下角悬浮窗口:鹰眼矢量路网缩略图,主场景视角任意变化,小地图实时同步。
实现核心原理:
- 双 Viewer 实例:页面创建两个独立 Cesium.Viewer,一个用作主场景地图,另一个用作鹰眼缩略地图,两者完全独立渲染。
- 相机监听联动 :通过
camera.changed监听主地图相机变化,设置percentageChanged控制触发灵敏度,视角变动 1% 就同步坐标、航向、俯仰、翻滚到鹰眼相机,duration:0实现无延迟实时同步。 - 鹰眼交互锁定:禁用鹰眼小地图平移、缩放、旋转、倾斜等全部操作,仅作为静态预览窗口,避免用户误操作破坏联动逻辑。
- 分层底图差异化:主场景地图加载实景影像瓦片,鹰眼缩略地图使用矢量道路瓦片,视觉上清晰区分主次场景,用户一眼就能分辨。
完整代码
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;
}
现有方案优化可拓展的参数调整(性能可优化点):
- 鹰眼瓦片层级限制:可降低鹰眼
maximumLevel至 14,减少小地图瓦片请求数量,低配设备防掉帧。 - 降低同步频率:调大
percentageChanged数值(如 0.03),减少相机回调执行次数。
本文案例中使用的高德瓦片资源仅用于学习、技术研究演示,不作线上商用部署场景使用。若企业项目正式上线使用同类地图瓦片资源,请自行前往对应地图服务商平台完成资质认证并申请合规调用密钥。