2025-11-18 21:24:31 +08:00
|
|
|
|
import { ref, onUnmounted } from 'vue'
|
|
|
|
|
|
import * as Cesium from 'cesium'
|
|
|
|
|
|
import { use3DTiles } from './use3DTiles'
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 双地图对比模式
|
|
|
|
|
|
* 使用两个独立的Cesium Viewer实现并排对比
|
|
|
|
|
|
* 左侧显示灾前场景,右侧显示灾后场景
|
2025-11-24 17:00:50 +08:00
|
|
|
|
* 单向相机同步:右侧主地图驱动,左侧对比地图跟随
|
2025-11-18 21:24:31 +08:00
|
|
|
|
*/
|
|
|
|
|
|
export function useDualMapCompare() {
|
|
|
|
|
|
/** 左侧Viewer引用 */
|
|
|
|
|
|
const leftViewer = ref(null)
|
|
|
|
|
|
|
|
|
|
|
|
/** 右侧Viewer引用 */
|
|
|
|
|
|
const rightViewer = ref(null)
|
|
|
|
|
|
|
|
|
|
|
|
/** 对比模式是否激活 */
|
|
|
|
|
|
const isCompareMode = ref(false)
|
|
|
|
|
|
|
|
|
|
|
|
/** 相机同步监听器移除函数 */
|
|
|
|
|
|
let cameraSyncRemover = null
|
|
|
|
|
|
|
|
|
|
|
|
/** 左侧3D Tileset(灾前) */
|
|
|
|
|
|
let leftTileset = null
|
|
|
|
|
|
|
|
|
|
|
|
/** 右侧3D Tileset(灾后,主地图的tileset) */
|
|
|
|
|
|
let rightTileset = null
|
|
|
|
|
|
|
|
|
|
|
|
const { load3DTileset } = use3DTiles()
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 初始化左侧Viewer(灾前场景)
|
|
|
|
|
|
* @param {HTMLElement} container - 容器元素
|
|
|
|
|
|
* @returns {Cesium.Viewer}
|
|
|
|
|
|
*/
|
|
|
|
|
|
const initLeftViewer = (container) => {
|
|
|
|
|
|
if (!container) {
|
|
|
|
|
|
console.error('[useDualMapCompare] 左侧容器元素不存在')
|
|
|
|
|
|
return null
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-25 09:35:28 +08:00
|
|
|
|
// 验证容器尺寸
|
|
|
|
|
|
const { clientWidth, clientHeight } = container
|
|
|
|
|
|
console.log(`[useDualMapCompare] 左侧容器尺寸: ${clientWidth}x${clientHeight}`)
|
|
|
|
|
|
|
|
|
|
|
|
if (clientWidth <= 0 || clientHeight <= 0) {
|
|
|
|
|
|
console.error(`[useDualMapCompare] 左侧容器尺寸无效 (width=${clientWidth}, height=${clientHeight})`)
|
|
|
|
|
|
return null
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-18 21:24:31 +08:00
|
|
|
|
// 创建左侧viewer
|
|
|
|
|
|
const viewer = new Cesium.Viewer(container, {
|
|
|
|
|
|
animation: false,
|
|
|
|
|
|
baseLayerPicker: false,
|
|
|
|
|
|
fullscreenButton: false,
|
|
|
|
|
|
geocoder: false,
|
|
|
|
|
|
homeButton: false,
|
|
|
|
|
|
infoBox: false,
|
|
|
|
|
|
sceneModePicker: false,
|
|
|
|
|
|
selectionIndicator: false,
|
|
|
|
|
|
timeline: false,
|
|
|
|
|
|
navigationHelpButton: false,
|
|
|
|
|
|
scene3DOnly: true,
|
|
|
|
|
|
shouldAnimate: false,
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 移除默认的Cesium logo和版权信息
|
|
|
|
|
|
viewer.cesiumWidget.creditContainer.style.display = 'none'
|
|
|
|
|
|
|
2025-11-24 17:00:50 +08:00
|
|
|
|
// 完全禁用左侧Viewer的所有交互(只作为对比显示)
|
2025-11-25 17:55:13 +08:00
|
|
|
|
// viewer.scene.screenSpaceCameraController.enableRotate = false
|
|
|
|
|
|
// viewer.scene.screenSpaceCameraController.enableTranslate = false
|
|
|
|
|
|
// viewer.scene.screenSpaceCameraController.enableZoom = false
|
|
|
|
|
|
// viewer.scene.screenSpaceCameraController.enableTilt = false
|
|
|
|
|
|
// viewer.scene.screenSpaceCameraController.enableLook = false
|
2025-11-24 17:00:50 +08:00
|
|
|
|
|
2025-11-18 21:24:31 +08:00
|
|
|
|
leftViewer.value = viewer
|
2025-11-25 17:55:13 +08:00
|
|
|
|
console.log('[useDualMapCompare] 左侧Viewer初始化成功(交互已启用)') // 关键修改
|
2025-11-18 21:24:31 +08:00
|
|
|
|
|
|
|
|
|
|
return viewer
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2025-11-24 17:00:50 +08:00
|
|
|
|
* 设置单向相机同步(右→左)
|
|
|
|
|
|
* 右侧主地图驱动,左侧对比地图跟随
|
|
|
|
|
|
* @param {Cesium.Viewer} rightViewerInstance - 右侧Viewer(主地图,驱动者)
|
|
|
|
|
|
* @param {Cesium.Viewer} leftViewerInstance - 左侧Viewer(对比地图,跟随者)
|
2025-11-18 21:24:31 +08:00
|
|
|
|
*/
|
|
|
|
|
|
const setupCameraSync = (rightViewerInstance, leftViewerInstance) => {
|
|
|
|
|
|
if (!rightViewerInstance || !leftViewerInstance) {
|
|
|
|
|
|
console.warn('[useDualMapCompare] Viewer未初始化,无法设置相机同步')
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-25 17:55:13 +08:00
|
|
|
|
console.log('[useDualMapCompare] 设置智能相机同步(右→左)...')
|
2025-11-18 21:24:31 +08:00
|
|
|
|
|
2025-11-25 17:55:13 +08:00
|
|
|
|
/** 同步相机状态(带防抖) */
|
|
|
|
|
|
let isSyncing = false
|
2025-11-24 17:00:50 +08:00
|
|
|
|
const handleCameraSync = () => {
|
2025-11-25 17:55:13 +08:00
|
|
|
|
if (isSyncing) return
|
|
|
|
|
|
isSyncing = true
|
|
|
|
|
|
|
|
|
|
|
|
requestAnimationFrame(() => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const rightCamera = rightViewerInstance.camera
|
|
|
|
|
|
leftViewerInstance.camera.setView({
|
|
|
|
|
|
destination: rightCamera.position.clone(),
|
|
|
|
|
|
orientation: {
|
|
|
|
|
|
heading: rightCamera.heading,
|
|
|
|
|
|
pitch: rightCamera.pitch,
|
|
|
|
|
|
roll: rightCamera.roll
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
console.warn('[useDualMapCompare] 同步异常:', e)
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
isSyncing = false
|
2025-11-18 21:24:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-25 17:55:13 +08:00
|
|
|
|
const syncController = {
|
|
|
|
|
|
_isUserInteracting: false,
|
|
|
|
|
|
_interactionHandlers: [], // 存储 moveStart 监听器
|
|
|
|
|
|
_moveEndHandler: null,
|
|
|
|
|
|
_lastPosition: null,
|
|
|
|
|
|
_interval: null,
|
|
|
|
|
|
|
|
|
|
|
|
start: () => {
|
|
|
|
|
|
const controller = rightViewerInstance.scene.screenSpaceCameraController
|
|
|
|
|
|
|
|
|
|
|
|
if (!controller) {
|
|
|
|
|
|
console.error('[useDualMapCompare] screenSpaceCameraController未初始化')
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 1. 事件监听逻辑
|
|
|
|
|
|
if (typeof rightViewerInstance.camera.moveStart?.addEventListener === 'function' &&
|
|
|
|
|
|
typeof rightViewerInstance.camera.moveEnd?.addEventListener === 'function') {
|
|
|
|
|
|
|
|
|
|
|
|
// 监听相机移动开始(替代所有操作类型监听)
|
|
|
|
|
|
const moveStartHandler = rightViewerInstance.camera.moveStart.addEventListener(() => {
|
|
|
|
|
|
syncController._isUserInteracting = true
|
|
|
|
|
|
console.log('[useDualMapCompare] 捕获相机操作开始')
|
|
|
|
|
|
|
|
|
|
|
|
// 新增拖动持续监听
|
|
|
|
|
|
const onDragFrame = () => {
|
|
|
|
|
|
if (syncController._isUserInteracting) {
|
|
|
|
|
|
console.log('[useDualMapCompare] 主同步触发')
|
|
|
|
|
|
handleCameraSync()
|
|
|
|
|
|
requestAnimationFrame(onDragFrame)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
requestAnimationFrame(onDragFrame)
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 同步逻辑
|
|
|
|
|
|
syncController._moveEndHandler = rightViewerInstance.camera.moveEnd.addEventListener(() => {
|
|
|
|
|
|
if (syncController._isUserInteracting) {
|
|
|
|
|
|
console.log('[useDualMapCompare] 主同步触发')
|
|
|
|
|
|
handleCameraSync()
|
|
|
|
|
|
syncController._isUserInteracting = false
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
console.warn(`[useDualMapCompare] 相机事件不可用,当前Cesium版本: ${Cesium.VERSION}`)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 保险同步逻辑
|
|
|
|
|
|
syncController._lastPosition = new Cesium.Cartesian3()
|
|
|
|
|
|
syncController._interval = setInterval(() => {
|
|
|
|
|
|
const isMoving = controller.isMoving
|
|
|
|
|
|
const currentPosition = rightViewerInstance.camera.position
|
|
|
|
|
|
|
|
|
|
|
|
if (syncController._isUserInteracting) {
|
|
|
|
|
|
if (isMoving) {
|
|
|
|
|
|
Cesium.Cartesian3.clone(currentPosition, syncController._lastPosition)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
const positionChanged = !Cesium.Cartesian3.equalsEpsilon(
|
|
|
|
|
|
currentPosition,
|
|
|
|
|
|
syncController._lastPosition,
|
|
|
|
|
|
0.1
|
|
|
|
|
|
)
|
|
|
|
|
|
if (positionChanged) {
|
|
|
|
|
|
console.log('[useDualMapCompare] 保险同步触发')
|
|
|
|
|
|
handleCameraSync()
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!controller.isMoving) {
|
|
|
|
|
|
syncController._isUserInteracting = false
|
|
|
|
|
|
}
|
|
|
|
|
|
Cesium.Cartesian3.clone(currentPosition, syncController._lastPosition)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}, 300)
|
|
|
|
|
|
|
|
|
|
|
|
console.log('[useDualMapCompare] 智能同步设置完成')
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
stop: () => {
|
|
|
|
|
|
const controller = rightViewerInstance.scene.screenSpaceCameraController
|
|
|
|
|
|
|
|
|
|
|
|
// 移除 moveStart 监听
|
|
|
|
|
|
syncController._interactionHandlers.forEach(handler => {
|
|
|
|
|
|
if (typeof rightViewerInstance.camera.moveStart?.removeEventListener === 'function') {
|
|
|
|
|
|
rightViewerInstance.camera.moveStart.removeEventListener(handler)
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
syncController._interactionHandlers = []
|
|
|
|
|
|
|
|
|
|
|
|
// 移除 moveEnd 监听
|
|
|
|
|
|
if (syncController._moveEndHandler &&
|
|
|
|
|
|
typeof rightViewerInstance.camera.moveEnd?.removeEventListener === 'function') {
|
|
|
|
|
|
rightViewerInstance.camera.moveEnd.removeEventListener(syncController._moveEndHandler)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 清除保险同步
|
|
|
|
|
|
if (syncController._interval) {
|
|
|
|
|
|
clearInterval(syncController._interval)
|
|
|
|
|
|
syncController._interval = null
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
syncController._isUserInteracting = false
|
|
|
|
|
|
syncController._lastPosition = null
|
|
|
|
|
|
console.log('[useDualMapCompare] 智能同步已移除')
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 启动监听
|
|
|
|
|
|
syncController.start()
|
2025-11-18 21:24:31 +08:00
|
|
|
|
|
|
|
|
|
|
// 保存移除函数
|
|
|
|
|
|
cameraSyncRemover = () => {
|
2025-11-25 17:55:13 +08:00
|
|
|
|
syncController.stop()
|
|
|
|
|
|
console.log('[useDualMapCompare] 智能同步已移除')
|
2025-11-18 21:24:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-25 17:55:13 +08:00
|
|
|
|
console.log('[useDualMapCompare] 智能同步设置完成')
|
2025-11-18 21:24:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 启用对比模式
|
|
|
|
|
|
* @param {Cesium.Viewer} rightViewerInstance - 右侧Viewer实例(主地图,灾后场景)
|
2025-11-25 09:35:28 +08:00
|
|
|
|
* @param {Object} options - 配置选项
|
|
|
|
|
|
* @param {boolean} options.skipLeftModelLoad - 是否跳过左侧模型加载
|
|
|
|
|
|
* @param {boolean} options.loadLeftModel - 是否仅加载左侧模型(不重新初始化Viewer)
|
2025-11-18 21:24:31 +08:00
|
|
|
|
*/
|
2025-11-25 09:35:28 +08:00
|
|
|
|
const enableCompareMode = async (rightViewerInstance, options = {}) => {
|
|
|
|
|
|
const { skipLeftModelLoad = false, loadLeftModel = false } = options
|
|
|
|
|
|
|
2025-11-25 14:46:53 +08:00
|
|
|
|
// 前置检查: viewer
|
2025-11-18 21:24:31 +08:00
|
|
|
|
if (!rightViewerInstance) {
|
2025-11-25 14:46:53 +08:00
|
|
|
|
const error = new Error('右侧主地图Viewer未初始化')
|
|
|
|
|
|
console.error('[useDualMapCompare]', error.message)
|
|
|
|
|
|
throw error
|
2025-11-18 21:24:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-25 09:35:28 +08:00
|
|
|
|
// 如果只是加载左侧模型(Viewer已存在)
|
|
|
|
|
|
if (loadLeftModel && leftViewer.value) {
|
|
|
|
|
|
console.log('[useDualMapCompare] 加载左侧灾前模型...')
|
|
|
|
|
|
try {
|
|
|
|
|
|
const tileset = await load3DTileset(leftViewer.value, 'before', false)
|
|
|
|
|
|
if (tileset) {
|
|
|
|
|
|
leftTileset = tileset
|
|
|
|
|
|
console.log('[useDualMapCompare] 左侧灾前模型加载完成')
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('[useDualMapCompare] 左侧模型加载失败:', error)
|
|
|
|
|
|
}
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-18 21:24:31 +08:00
|
|
|
|
console.log('[useDualMapCompare] 启用对比模式...')
|
|
|
|
|
|
|
|
|
|
|
|
rightViewer.value = rightViewerInstance
|
|
|
|
|
|
|
|
|
|
|
|
// 查找左侧容器(容器已存在于DOM中)
|
|
|
|
|
|
const leftContainer = document.getElementById('leftCesiumContainer')
|
|
|
|
|
|
if (!leftContainer) {
|
2025-11-25 14:46:53 +08:00
|
|
|
|
const error = new Error('找不到左侧容器元素 #leftCesiumContainer')
|
|
|
|
|
|
console.error('[useDualMapCompare]', error.message)
|
|
|
|
|
|
throw error
|
2025-11-18 21:24:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 先设置状态,触发CSS动画
|
|
|
|
|
|
isCompareMode.value = true
|
|
|
|
|
|
|
2025-11-25 17:55:13 +08:00
|
|
|
|
// 增强型布局等待策略
|
|
|
|
|
|
await new Promise(resolve => {
|
|
|
|
|
|
// 1. 基础等待 → 2. 强制重绘 → 3. 循环检查
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
// 强制触发浏览器重绘
|
|
|
|
|
|
void leftContainer.offsetWidth
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 循环验证容器尺寸
|
|
|
|
|
|
const startTime = Date.now()
|
|
|
|
|
|
const checkLayout = () => {
|
|
|
|
|
|
if (leftContainer.clientWidth > 0 && leftContainer.clientHeight > 0) {
|
|
|
|
|
|
resolve()
|
|
|
|
|
|
} else if (Date.now() - startTime < 2000) { // 总等待不超过2秒
|
|
|
|
|
|
setTimeout(checkLayout, 50)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
console.error('左侧容器最终尺寸:',
|
|
|
|
|
|
`width: ${leftContainer.clientWidth}px, height: ${leftContainer.clientHeight}px`)
|
|
|
|
|
|
throw new Error('左侧容器布局超时')
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
checkLayout()
|
|
|
|
|
|
}, 350) // 原等待时间保持
|
|
|
|
|
|
})
|
2025-11-18 21:24:31 +08:00
|
|
|
|
|
|
|
|
|
|
// 初始化左侧Viewer
|
|
|
|
|
|
const leftViewerInstance = initLeftViewer(leftContainer)
|
|
|
|
|
|
if (!leftViewerInstance) {
|
2025-11-25 14:46:53 +08:00
|
|
|
|
const error = new Error('左侧Viewer初始化失败')
|
|
|
|
|
|
console.error('[useDualMapCompare]', error.message)
|
|
|
|
|
|
isCompareMode.value = false // 回滚状态
|
|
|
|
|
|
throw error
|
2025-11-18 21:24:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 立即同步右侧相机的当前位置到左侧
|
|
|
|
|
|
console.log('[useDualMapCompare] 同步初始相机位置...')
|
|
|
|
|
|
const rightCamera = rightViewerInstance.camera
|
|
|
|
|
|
leftViewerInstance.camera.setView({
|
|
|
|
|
|
destination: rightCamera.position.clone(),
|
|
|
|
|
|
orientation: {
|
|
|
|
|
|
heading: rightCamera.heading,
|
|
|
|
|
|
pitch: rightCamera.pitch,
|
|
|
|
|
|
roll: rightCamera.roll
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
|
2025-11-24 17:00:50 +08:00
|
|
|
|
// 设置相机同步(单向:右→左)
|
2025-11-18 21:24:31 +08:00
|
|
|
|
setupCameraSync(rightViewerInstance, leftViewerInstance)
|
|
|
|
|
|
|
2025-11-25 09:35:28 +08:00
|
|
|
|
// 根据选项决定是否加载左侧模型
|
|
|
|
|
|
if (!skipLeftModelLoad) {
|
|
|
|
|
|
// 异步加载灾前模型到左侧(不阻塞对比模式启用)
|
|
|
|
|
|
console.log('[useDualMapCompare] 开始异步加载左侧灾前模型...')
|
|
|
|
|
|
load3DTileset(leftViewerInstance, 'before', false)
|
|
|
|
|
|
.then(tileset => {
|
|
|
|
|
|
if (tileset) {
|
|
|
|
|
|
leftTileset = tileset
|
|
|
|
|
|
console.log('[useDualMapCompare] 左侧灾前模型加载完成')
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
.catch(error => {
|
|
|
|
|
|
console.error('[useDualMapCompare] 左侧模型加载失败:', error)
|
|
|
|
|
|
})
|
|
|
|
|
|
} else {
|
|
|
|
|
|
console.log('[useDualMapCompare] 跳过左侧模型加载(将延迟加载)')
|
|
|
|
|
|
}
|
2025-11-18 21:24:31 +08:00
|
|
|
|
|
|
|
|
|
|
// 右侧保持灾后模型(已加载)
|
|
|
|
|
|
|
|
|
|
|
|
// 触发左侧viewer resize
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
if (leftViewerInstance && leftViewerInstance.canvas) {
|
|
|
|
|
|
leftViewerInstance.resize()
|
|
|
|
|
|
leftViewerInstance.camera.changed.raiseEvent()
|
|
|
|
|
|
}
|
|
|
|
|
|
// 同时触发右侧viewer resize
|
|
|
|
|
|
if (rightViewerInstance && rightViewerInstance.canvas) {
|
|
|
|
|
|
rightViewerInstance.resize()
|
|
|
|
|
|
}
|
|
|
|
|
|
}, 350)
|
|
|
|
|
|
|
|
|
|
|
|
console.log('[useDualMapCompare] 对比模式已启用')
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 禁用对比模式
|
|
|
|
|
|
*/
|
|
|
|
|
|
const disableCompareMode = () => {
|
|
|
|
|
|
console.log('[useDualMapCompare] 禁用对比模式...')
|
|
|
|
|
|
|
|
|
|
|
|
// 移除相机同步
|
|
|
|
|
|
if (cameraSyncRemover) {
|
|
|
|
|
|
cameraSyncRemover()
|
|
|
|
|
|
cameraSyncRemover = null
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 销毁左侧Viewer
|
|
|
|
|
|
if (leftViewer.value && !leftViewer.value.isDestroyed()) {
|
|
|
|
|
|
// 清理左侧tileset
|
|
|
|
|
|
if (leftTileset) {
|
|
|
|
|
|
leftViewer.value.scene.primitives.remove(leftTileset)
|
|
|
|
|
|
leftTileset = null
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
leftViewer.value.destroy()
|
|
|
|
|
|
leftViewer.value = null
|
|
|
|
|
|
console.log('[useDualMapCompare] 左侧Viewer已销毁')
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 触发右侧viewer resize恢复全屏
|
|
|
|
|
|
if (rightViewer.value && !rightViewer.value.isDestroyed()) {
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
if (rightViewer.value && rightViewer.value.canvas) {
|
|
|
|
|
|
rightViewer.value.resize()
|
|
|
|
|
|
}
|
|
|
|
|
|
}, 350)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
isCompareMode.value = false
|
|
|
|
|
|
console.log('[useDualMapCompare] 对比模式已禁用')
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 切换对比模式
|
|
|
|
|
|
* @param {boolean} active - true启用,false禁用
|
|
|
|
|
|
* @param {Cesium.Viewer} rightViewerInstance - 右侧Viewer实例(主地图)
|
2025-11-25 09:35:28 +08:00
|
|
|
|
* @param {Object} options - 配置选项(传递给 enableCompareMode)
|
2025-11-25 14:46:53 +08:00
|
|
|
|
* @throws {Error} 当切换失败时抛出错误
|
2025-11-18 21:24:31 +08:00
|
|
|
|
*/
|
2025-11-25 09:35:28 +08:00
|
|
|
|
const toggleCompareMode = async (active, rightViewerInstance, options) => {
|
2025-11-25 14:46:53 +08:00
|
|
|
|
try {
|
|
|
|
|
|
console.log(`[useDualMapCompare] 切换对比模式: ${active}`)
|
|
|
|
|
|
|
|
|
|
|
|
if (active) {
|
|
|
|
|
|
// 前置检查
|
|
|
|
|
|
if (!rightViewerInstance) {
|
|
|
|
|
|
throw new Error('右侧Viewer未初始化,无法启用对比模式')
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
await enableCompareMode(rightViewerInstance, options)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
disableCompareMode()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
console.log(`[useDualMapCompare] 对比模式切换成功: ${active}`)
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
console.error('[useDualMapCompare] 切换对比模式失败:', error)
|
|
|
|
|
|
|
|
|
|
|
|
// 确保状态回滚
|
|
|
|
|
|
isCompareMode.value = !active
|
|
|
|
|
|
|
|
|
|
|
|
// 向上层传播错误
|
|
|
|
|
|
throw error
|
2025-11-18 21:24:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 清理
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
|
|
|
disableCompareMode()
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
leftViewer,
|
|
|
|
|
|
rightViewer,
|
|
|
|
|
|
isCompareMode,
|
|
|
|
|
|
enableCompareMode,
|
|
|
|
|
|
disableCompareMode,
|
|
|
|
|
|
toggleCompareMode
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export default useDualMapCompare
|