diff --git a/packages/screen/src/views/3DSituationalAwarenessRefactor/composables/useDualMapCompare.js b/packages/screen/src/views/3DSituationalAwarenessRefactor/composables/useDualMapCompare.js index 4b0c6ce..1676603 100644 --- a/packages/screen/src/views/3DSituationalAwarenessRefactor/composables/useDualMapCompare.js +++ b/packages/screen/src/views/3DSituationalAwarenessRefactor/composables/useDualMapCompare.js @@ -102,10 +102,32 @@ export function useDualMapCompare() { let isSyncing = false const handleCameraSync = () => { if (isSyncing) return + + // 防御检查1:viewer 存在性检查 + if (!rightViewerInstance || !leftViewerInstance) { + return + } + + // 防御检查2:viewer destroyed 状态检查 + if (rightViewerInstance.isDestroyed?.() || leftViewerInstance.isDestroyed?.()) { + return + } + isSyncing = true requestAnimationFrame(() => { try { + // 再次检查(requestAnimationFrame 可能延迟执行) + if (!rightViewerInstance || !leftViewerInstance) { + isSyncing = false + return + } + + if (rightViewerInstance.isDestroyed?.() || leftViewerInstance.isDestroyed?.()) { + isSyncing = false + return + } + const rightCamera = rightViewerInstance.camera leftViewerInstance.camera.setView({ destination: rightCamera.position.clone(), @@ -129,8 +151,13 @@ export function useDualMapCompare() { _moveEndHandler: null, _lastPosition: null, _interval: null, + _stopped: false, // 新增:原子性停止标志 + _moveEndReceived: false, // 新增:标记 moveEnd 是否已触发 start: () => { + // 重置停止标志 + syncController._stopped = false + const controller = rightViewerInstance.scene.screenSpaceCameraController if (!controller) { @@ -142,13 +169,27 @@ export function useDualMapCompare() { if (typeof rightViewerInstance.camera.moveStart?.addEventListener === 'function' && typeof rightViewerInstance.camera.moveEnd?.addEventListener === 'function') { - // 监听相机移动开始(替代所有操作类型监听) + // 监听相机移动开始 const moveStartHandler = rightViewerInstance.camera.moveStart.addEventListener(() => { + if (syncController._stopped) return // 检查停止标志 + syncController._isUserInteracting = true console.log('[useDualMapCompare] 捕获相机操作开始') - // 新增拖动持续监听 + // 改进:只在首次触发时启动递归 const onDragFrame = () => { + // 停止检查 + if (syncController._stopped) { + console.log('[useDualMapCompare] 停止标志已设置,退出递归') + return + } + + // viewer 有效性检查 + if (!rightViewerInstance || rightViewerInstance.isDestroyed?.()) { + console.log('[useDualMapCompare] Viewer已销毁,退出递归') + return + } + if (syncController._isUserInteracting) { console.log('[useDualMapCompare] 主同步触发') handleCameraSync() @@ -158,12 +199,17 @@ export function useDualMapCompare() { requestAnimationFrame(onDragFrame) }) - // 2. 同步逻辑 + syncController._interactionHandlers.push(moveStartHandler) + + // 2. 监听相机移动结束 syncController._moveEndHandler = rightViewerInstance.camera.moveEnd.addEventListener(() => { + if (syncController._stopped) return // 检查停止标志 + if (syncController._isUserInteracting) { - console.log('[useDualMapCompare] 主同步触发') - handleCameraSync() - syncController._isUserInteracting = false + console.log('[useDualMapCompare] moveEnd 事件触发,等待相机完全停止...') + // 不要立即重置 _isUserInteracting,让 setInterval 继续检测 + // 标记为"移动已结束但可能还在惯性滑动" + syncController._moveEndReceived = true } }) @@ -172,62 +218,113 @@ export function useDualMapCompare() { return } - // 3. 保险同步逻辑 + // 3. 保险同步逻辑(setInterval) syncController._lastPosition = new Cesium.Cartesian3() + syncController._moveEndReceived = false // 重置标志 syncController._interval = setInterval(() => { + // 停止检查 + if (syncController._stopped) return + + // viewer 有效性检查 + if (!rightViewerInstance || rightViewerInstance.isDestroyed?.()) { + console.log('[useDualMapCompare] Viewer已销毁,停止定时同步') + if (syncController._interval) { + clearInterval(syncController._interval) + syncController._interval = null + } + return + } + const isMoving = controller.isMoving const currentPosition = rightViewerInstance.camera.position if (syncController._isUserInteracting) { if (isMoving) { + // 相机正在移动,持续更新位置 Cesium.Cartesian3.clone(currentPosition, syncController._lastPosition) + syncController._moveEndReceived = false // 重置标志 } else { - const positionChanged = !Cesium.Cartesian3.equalsEpsilon( - currentPosition, - syncController._lastPosition, - 0.1 - ) - if (positionChanged) { - console.log('[useDualMapCompare] 保险同步触发') - handleCameraSync() + // 相机已停止移动 + if (syncController._moveEndReceived) { + // moveEnd 已触发且相机已停止,执行最终同步 + const positionChanged = !Cesium.Cartesian3.equalsEpsilon( + currentPosition, + syncController._lastPosition, + 0.001 // 更高精度 + ) + + if (positionChanged) { + console.log('[useDualMapCompare] 相机完全停止,执行最终同步') + handleCameraSync() + Cesium.Cartesian3.clone(currentPosition, syncController._lastPosition) + } else { + console.log('[useDualMapCompare] 相机完全停止,位置无变化') + } + + // 重置状态 + syncController._isUserInteracting = false + syncController._moveEndReceived = false + } else { + // 相机停止但 moveEnd 未触发(可能是微小移动后停止) + const positionChanged = !Cesium.Cartesian3.equalsEpsilon( + currentPosition, + syncController._lastPosition, + 0.1 + ) + + if (positionChanged) { + console.log('[useDualMapCompare] 保险同步触发(相机停止但moveEnd未触发)') + handleCameraSync() + Cesium.Cartesian3.clone(currentPosition, syncController._lastPosition) + syncController._isUserInteracting = false + } } - if (!controller.isMoving) { - syncController._isUserInteracting = false - } - Cesium.Cartesian3.clone(currentPosition, syncController._lastPosition) } } }, 300) - console.log('[useDualMapCompare] 智能同步设置完成') + console.log('[useDualMapCompare] 智能同步已启动') }, stop: () => { - const controller = rightViewerInstance.scene.screenSpaceCameraController + // 原子性设置停止标志(最优先) + syncController._stopped = true - // 移除 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 } + // 移除事件监听器(需要检查 viewer 是否仍然有效) + if (rightViewerInstance && !rightViewerInstance.isDestroyed?.()) { + syncController._interactionHandlers.forEach(handler => { + if (typeof rightViewerInstance.camera.moveStart?.removeEventListener === 'function') { + try { + rightViewerInstance.camera.moveStart.removeEventListener(handler) + } catch (e) { + console.warn('[useDualMapCompare] 移除 moveStart 监听器失败:', e) + } + } + }) + + if (syncController._moveEndHandler && + typeof rightViewerInstance.camera.moveEnd?.removeEventListener === 'function') { + try { + rightViewerInstance.camera.moveEnd.removeEventListener(syncController._moveEndHandler) + } catch (e) { + console.warn('[useDualMapCompare] 移除 moveEnd 监听器失败:', e) + } + } + } + + syncController._interactionHandlers = [] + syncController._moveEndHandler = null syncController._isUserInteracting = false + syncController._moveEndReceived = false // 重置标志 syncController._lastPosition = null - console.log('[useDualMapCompare] 智能同步已移除') + + console.log('[useDualMapCompare] 智能同步已完全停止') } }