Merge branch 'dev' of http://222.212.85.86:8222/bdzl2/bxztApp into dev
This commit is contained in:
commit
0dca401b1c
@ -87,46 +87,66 @@ export function use3DTiles() {
|
||||
return
|
||||
}
|
||||
|
||||
let timeoutId = null
|
||||
let eventHandler = null
|
||||
|
||||
// 统一清理函数
|
||||
const cleanup = () => {
|
||||
if (timeoutId) {
|
||||
clearTimeout(timeoutId)
|
||||
timeoutId = null
|
||||
}
|
||||
if (eventHandler) {
|
||||
tileset.initialTilesLoaded.removeEventListener(eventHandler)
|
||||
eventHandler = null
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// 步骤1:等待 Tileset 基础就绪
|
||||
await tileset.readyPromise
|
||||
console.log('[use3DTiles] Tileset readyPromise 已完成')
|
||||
|
||||
// 步骤2:等待初始瓦片加载完成(带超时)
|
||||
// 步骤2:早期出口 - 快速检查
|
||||
if (tileset.tilesLoaded) {
|
||||
console.log('[use3DTiles] 瓦片已加载,直接继续')
|
||||
return
|
||||
}
|
||||
|
||||
// 步骤3:等待初始瓦片加载完成(带超时)
|
||||
console.log('[use3DTiles] 等待初始瓦片加载...')
|
||||
|
||||
await Promise.race([
|
||||
// 等待initialTilesLoaded事件
|
||||
// 等待 initialTilesLoaded 事件
|
||||
new Promise((resolve) => {
|
||||
const handleInitialTilesLoaded = () => {
|
||||
eventHandler = () => {
|
||||
console.log('[use3DTiles] 初始瓦片加载完成(事件触发)')
|
||||
tileset.initialTilesLoaded.removeEventListener(handleInitialTilesLoaded)
|
||||
resolve()
|
||||
}
|
||||
|
||||
tileset.initialTilesLoaded.addEventListener(handleInitialTilesLoaded)
|
||||
|
||||
// 如果已经加载完成,可能事件已经触发过了,直接resolve
|
||||
// 通过检查tileset.tilesLoaded来判断
|
||||
if (tileset.tilesLoaded) {
|
||||
console.log('[use3DTiles] 瓦片已加载,直接继续')
|
||||
tileset.initialTilesLoaded.removeEventListener(handleInitialTilesLoaded)
|
||||
cleanup()
|
||||
resolve()
|
||||
}
|
||||
tileset.initialTilesLoaded.addEventListener(eventHandler)
|
||||
}),
|
||||
|
||||
// 超时机制
|
||||
new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
console.warn(`[use3DTiles] 等待瓦片加载超时(${timeout}ms),继续执行`)
|
||||
resolve()
|
||||
new Promise((_, reject) => {
|
||||
timeoutId = setTimeout(() => {
|
||||
cleanup()
|
||||
reject(new Error(`等待瓦片加载超时(${timeout}ms)`))
|
||||
}, timeout)
|
||||
})
|
||||
])
|
||||
|
||||
console.log('[use3DTiles] Tileset 已完全就绪')
|
||||
} catch (error) {
|
||||
console.error('[use3DTiles] 等待 Tileset 就绪失败:', error)
|
||||
if (error.message && error.message.includes('超时')) {
|
||||
// 超时但继续执行(保持原有行为)
|
||||
console.warn(`[use3DTiles] ${error.message},继续执行`)
|
||||
} else {
|
||||
console.error('[use3DTiles] 等待 Tileset 就绪失败:', error)
|
||||
}
|
||||
// 即使失败也不抛出异常,允许程序继续执行
|
||||
} finally {
|
||||
cleanup() // 保险清理
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -105,10 +105,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(),
|
||||
@ -132,8 +154,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) {
|
||||
@ -145,13 +172,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()
|
||||
@ -161,12 +202,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
|
||||
}
|
||||
})
|
||||
|
||||
@ -175,62 +221,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 (!controller.isMoving) {
|
||||
// 相机已停止移动
|
||||
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
|
||||
}
|
||||
}
|
||||
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] 智能同步已完全停止')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -120,7 +120,7 @@ export function useEntityAnimation() {
|
||||
viewer.clock.startTime = startTime.clone()
|
||||
viewer.clock.stopTime = stopTime.clone()
|
||||
viewer.clock.currentTime = startTime.clone()
|
||||
viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP // 动画结束后停止
|
||||
viewer.clock.clockRange = Cesium.ClockRange.CLAMPED // 动画到达终点后停止,不循环
|
||||
viewer.clock.multiplier = 1 // 实时速度
|
||||
viewer.clock.shouldAnimate = true
|
||||
|
||||
@ -385,7 +385,7 @@ export function useEntityAnimation() {
|
||||
viewer.clock.startTime = startTime.clone()
|
||||
viewer.clock.stopTime = stopTime.clone()
|
||||
viewer.clock.currentTime = startTime.clone()
|
||||
viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP
|
||||
viewer.clock.clockRange = Cesium.ClockRange.CLAMPED // 动画到达终点后停止,不循环
|
||||
viewer.clock.multiplier = 1
|
||||
viewer.clock.shouldAnimate = true
|
||||
|
||||
@ -470,7 +470,12 @@ export function useEntityAnimation() {
|
||||
})
|
||||
|
||||
// 计算动画时长(使用速度倍数)
|
||||
const speedMultiplier = options.speedMultiplier || 10
|
||||
// 装备移动速度更快(speedMultiplier 更大 = 动画时间更短 = 移动更快)
|
||||
const baseSpeedMultiplier = options.speedMultiplier || 10
|
||||
const speedMultiplier = route.type === 'equipment'
|
||||
? baseSpeedMultiplier * 1.5 // 装备速度是人员的1.5倍
|
||||
: baseSpeedMultiplier // 人员保持原速
|
||||
|
||||
const animationDuration = Math.min(
|
||||
Math.max(route.duration / speedMultiplier, 30), // 最小30秒
|
||||
120 // 最大120秒
|
||||
@ -510,6 +515,14 @@ export function useEntityAnimation() {
|
||||
const icon = route.type === 'equipment' ? deviceIcon : soldierIcon
|
||||
const trailColor = route.type === 'equipment' ? Cesium.Color.ORANGE : Cesium.Color.CYAN
|
||||
|
||||
// 日志输出:显示每个实体的动画时长
|
||||
console.log(
|
||||
`[useEntityAnimation] ${route.name} (${route.type}): ` +
|
||||
`原始时长=${Math.round(route.duration)}秒, ` +
|
||||
`速度倍数=${speedMultiplier.toFixed(1)}, ` +
|
||||
`动画时长=${Math.round(animationDuration)}秒`
|
||||
)
|
||||
|
||||
// 创建动画实体
|
||||
return viewer.entities.add({
|
||||
availability: new Cesium.TimeIntervalCollection([
|
||||
@ -584,7 +597,7 @@ export function useEntityAnimation() {
|
||||
viewer.clock.startTime = startTime.clone()
|
||||
viewer.clock.stopTime = stopTime.clone()
|
||||
viewer.clock.currentTime = startTime.clone()
|
||||
viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP
|
||||
viewer.clock.clockRange = Cesium.ClockRange.CLAMPED // 动画到达终点后停止,不循环
|
||||
viewer.clock.multiplier = 1
|
||||
viewer.clock.shouldAnimate = true
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user