From 47074b6d5683f040ec0396d414d0601f084b47e9 Mon Sep 17 00:00:00 2001 From: huangchenhao <123673748@qq.com> Date: Tue, 25 Nov 2025 17:55:13 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B7=A6=E5=8F=B3=E5=AF=B9=E6=AF=94=E9=83=A8?= =?UTF-8?q?=E5=88=86=20=E8=B0=83=E6=95=B4=E5=90=8C=E6=AD=A5=E6=96=B9?= =?UTF-8?q?=E5=BC=8F=20=E5=B7=A6=E4=BE=A7=E5=8F=AF=E4=BB=A5=E4=BB=BB?= =?UTF-8?q?=E6=84=8F=E6=8B=96=E5=8A=A8=20=E5=8F=AA=E6=9C=89=E5=8F=B3?= =?UTF-8?q?=E4=BE=A7=E6=8B=96=E5=8A=A8=E6=97=B6=E6=89=8D=E4=BC=9A=E8=A7=A6?= =?UTF-8?q?=E5=8F=91=E5=90=8C=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../composables/useDualMapCompare.js | 196 +++++++++++++++--- 1 file changed, 163 insertions(+), 33 deletions(-) diff --git a/packages/screen/src/views/3DSituationalAwarenessRefactor/composables/useDualMapCompare.js b/packages/screen/src/views/3DSituationalAwarenessRefactor/composables/useDualMapCompare.js index 4296828..13fdbb5 100644 --- a/packages/screen/src/views/3DSituationalAwarenessRefactor/composables/useDualMapCompare.js +++ b/packages/screen/src/views/3DSituationalAwarenessRefactor/composables/useDualMapCompare.js @@ -69,14 +69,14 @@ export function useDualMapCompare() { viewer.cesiumWidget.creditContainer.style.display = 'none' // 完全禁用左侧Viewer的所有交互(只作为对比显示) - 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 + // 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 leftViewer.value = viewer - console.log('[useDualMapCompare] 左侧Viewer初始化成功(交互已禁用)') + console.log('[useDualMapCompare] 左侧Viewer初始化成功(交互已启用)') // 关键修改 return viewer } @@ -84,7 +84,6 @@ export function useDualMapCompare() { /** * 设置单向相机同步(右→左) * 右侧主地图驱动,左侧对比地图跟随 - * 使用 postRender 实现逐帧同步,直接传递 position 引用以获得最佳性能 * @param {Cesium.Viewer} rightViewerInstance - 右侧Viewer(主地图,驱动者) * @param {Cesium.Viewer} leftViewerInstance - 左侧Viewer(对比地图,跟随者) */ @@ -94,42 +93,152 @@ export function useDualMapCompare() { return } - console.log('[useDualMapCompare] 设置单向相机同步(右→左)...') + console.log('[useDualMapCompare] 设置智能相机同步(右→左)...') - /** - * 相机同步处理函数 - * 在右侧 Viewer 的 postRender 中调用,将右侧相机状态同步到左侧 - */ + /** 同步相机状态(带防抖) */ + let isSyncing = false const handleCameraSync = () => { - // 检查 Viewer 是否有效 - if (!leftViewerInstance || leftViewerInstance.isDestroyed()) return - if (!rightViewerInstance || rightViewerInstance.isDestroyed()) return + if (isSyncing) return + isSyncing = true - const rightCamera = rightViewerInstance.camera - - // 直接传递 position 引用(不 clone),获得最佳性能 - // Cesium 内部会处理拷贝,且在单向同步场景下安全 - leftViewerInstance.camera.setView({ - destination: rightCamera.position, - orientation: { - heading: rightCamera.heading, - pitch: rightCamera.pitch, - roll: rightCamera.roll + 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 } }) } - // 只在右侧 Viewer 的 postRender 中注册同步函数 - // 确保右侧相机更新完成后再同步到左侧 - rightViewerInstance.scene.postRender.addEventListener(handleCameraSync) + 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() // 保存移除函数 cameraSyncRemover = () => { - rightViewerInstance.scene.postRender.removeEventListener(handleCameraSync) - console.log('[useDualMapCompare] 相机同步已移除') + syncController.stop() + console.log('[useDualMapCompare] 智能同步已移除') } - console.log('[useDualMapCompare] 单向相机同步设置完成') + console.log('[useDualMapCompare] 智能同步设置完成') } /** @@ -179,8 +288,29 @@ export function useDualMapCompare() { // 先设置状态,触发CSS动画 isCompareMode.value = true - // 等待CSS过渡完成(300ms + 50ms buffer) - await new Promise(resolve => setTimeout(resolve, 350)) + // 增强型布局等待策略 + 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) // 原等待时间保持 + }) // 初始化左侧Viewer const leftViewerInstance = initLeftViewer(leftContainer)