吉安感知网项目-前端
chenyao
2026-01-27 6c7cdb644f765cdb4ad923095a36550b7d46e91d
applications/drone-command/src/components/map-container/device-map-container.vue
@@ -119,6 +119,14 @@
let droneTrackTickHandler = null
let droneTrackStartTime = null
let droneTrackRuntime = []
let favoritePulseRafId = null
let favoritePulseStartAt = 0
let favoritePulseElapsed = 0
const favoritePulseEntities = []
const pulseBaseColor = Cesium.Color.fromCssColorString('#FF3B30')
const PULSE_MIN_RADIUS_M = 60
const PULSE_MAX_RADIUS_M = 180
const PULSE_DURATION_S = 1.6
const detailVisible = ref(true)
const clusterVisible = ref(false)
const countyCenterMap = new Map()
@@ -172,6 +180,57 @@
 */
const adminBoundaryVisible = ref(treeCheckedKeys.value.includes('admin'))
const isFavorited = item => {
   const value = item?.favorited ?? item?.isFavorite
   return value === 1 || value === '1' || value === true
}
let pulseCanvas = null
const getPulseCanvas = () => {
   if (pulseCanvas) return pulseCanvas
   const size = 256
   const canvas = document.createElement('canvas')
   canvas.width = size
   canvas.height = size
   const ctx = canvas.getContext('2d')
   const center = size / 2
   const radius = center - 2
   const gradient = ctx.createRadialGradient(center, center, radius * 0.1, center, center, radius)
   gradient.addColorStop(0, 'rgba(255,59,48,0.55)')
   gradient.addColorStop(0.35, 'rgba(255,59,48,0.35)')
   gradient.addColorStop(0.7, 'rgba(255,59,48,0.15)')
   gradient.addColorStop(1, 'rgba(255,59,48,0)')
   ctx.fillStyle = gradient
   ctx.beginPath()
   ctx.arc(center, center, radius, 0, Math.PI * 2)
   ctx.fill()
   pulseCanvas = canvas
   return canvas
}
const createFavoritePulseEntity = (billboard) => {
   if (!viewer || !billboard) return
   const material = new Cesium.ImageMaterialProperty({
      image: getPulseCanvas(),
      transparent: true,
   })
   const pulse = {
      material,
      offset: Math.random() * PULSE_DURATION_S,
      entity: null,
   }
   pulse.entity = viewer.entities.add({
      position: new Cesium.CallbackProperty(() => billboard.position, false),
      ellipse: {
         semiMajorAxis: new Cesium.CallbackProperty(() => getPulseRadius(pulse), false),
         semiMinorAxis: new Cesium.CallbackProperty(() => getPulseRadius(pulse), false),
         material,
         heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
      },
   })
   favoritePulseEntities.push(pulse)
}
const getDevicePosition = item => {
   const longitudeRaw = item.longitude ?? item.lng ?? item.lon
@@ -311,6 +370,12 @@
   }
}
const getPulseRadius = pulse => {
   const phase = ((favoritePulseElapsed + pulse.offset) % PULSE_DURATION_S) / PULSE_DURATION_S
   const wave = phase < 0.5 ? phase * 2 : (1 - phase) * 2
   return PULSE_MIN_RADIUS_M + (PULSE_MAX_RADIUS_M - PULSE_MIN_RADIUS_M) * wave
}
const setDetailVisibility = visible => {
   detailVisible.value = visible
   if (defenseZonePrimitive) defenseZonePrimitive.show = visible
@@ -345,6 +410,11 @@
const setDroneVisibility = visible => {
   if (droneTrackBillboardCollection) droneTrackBillboardCollection.show = visible
   if (droneTrackPolylineCollection) droneTrackPolylineCollection.show = visible
   if (favoritePulseEntities.length) {
      favoritePulseEntities.forEach(pulse => {
         if (pulse?.entity) pulse.entity.show = visible
      })
   }
   if (!visible && selectedTargetType.value === 'drone') {
      closePopup()
   }
@@ -453,6 +523,7 @@
const clearDroneTrackEntities = () => {
   if (!viewer) return
   stopDroneTrackAnimation()
   stopFavoritePulseAnimation()
   if (droneTrackBillboardCollection) {
      if (!droneTrackBillboardCollection.isDestroyed?.()) {
         removeCockpitPrimitive(droneTrackBillboardCollection)
@@ -466,6 +537,12 @@
      droneTrackPolylineCollection = null
   }
   droneTrackRuntime = []
   if (favoritePulseEntities.length) {
      favoritePulseEntities.forEach(pulse => {
         if (pulse?.entity) viewer?.entities?.remove(pulse.entity)
      })
      favoritePulseEntities.length = 0
   }
   dronePickMap.clear()
   if (selectedTargetType.value === 'drone') {
      closePopup()
@@ -532,6 +609,28 @@
   droneTrackTickHandler = null
}
const startFavoritePulseAnimation = () => {
   if (!viewer || favoritePulseRafId) return
   favoritePulseStartAt = performance.now()
   const tick = now => {
      if (!viewer || viewer.isDestroyed?.() || !favoritePulseEntities.length) {
         favoritePulseRafId = null
         return
      }
      favoritePulseElapsed = (now - favoritePulseStartAt) / 1000
      viewer.scene.requestRender()
      favoritePulseRafId = requestAnimationFrame(tick)
   }
   favoritePulseRafId = requestAnimationFrame(tick)
}
const stopFavoritePulseAnimation = () => {
   if (favoritePulseRafId) {
      cancelAnimationFrame(favoritePulseRafId)
      favoritePulseRafId = null
   }
}
const renderSimulatedDroneTrack = (list) => {
   if (!viewer) return
   clearDroneTrackEntities()
@@ -576,16 +675,19 @@
         })
         billboard.id = droneId
         const speedMs = Math.round(Cesium.Cartesian3.distance(positions[0], positions[1]) / segmentDuration)
         dronePickMap.set(droneId, {
            data: {
               ...item,
               flightHeightM: item.flightHeightM ?? points[0].height,
               flightSpeedMs: item.flightSpeedMs ?? speedMs,
               longitude: item.longitude ?? points[0].longitude,
               latitude: item.latitude ?? points[0].latitude,
            },
            billboard,
         })
      dronePickMap.set(droneId, {
         data: {
            ...item,
            flightHeightM: item.flightHeightM ?? points[0].height,
            flightSpeedMs: item.flightSpeedMs ?? speedMs,
            longitude: item.longitude ?? points[0].longitude,
            latitude: item.latitude ?? points[0].latitude,
         },
         billboard,
      })
      if (isFavorited(item)) {
         createFavoritePulseEntity(billboard)
      }
         droneTrackRuntime.push({
            positions,
            billboard,
@@ -595,6 +697,7 @@
      })
   viewer.clock.multiplier = 1
   startDroneTrackAnimation()
   startFavoritePulseAnimation()
   reorderCockpitPrimitives()
}