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)