<template>
|
<div class="ztzf-cesium map-box" id="map">
|
<PlanarRouteLineList
|
:curRouteLineData="curRouteLineData"
|
@routeLineListClick="routeLineListClick"
|
:customClass="'airline-list'"
|
/>
|
</div>
|
</template>
|
|
<script setup>
|
import _ from 'lodash'
|
import { useRouteLine } from '@/hooks/useRouteLine/useRouteLine.js'
|
// import { getWaylineSplitApi } from '@/api/routePlan'
|
|
import PlanarRouteLineList from '@/components/PlanarRouteLineList/PlanarRouteLineList.vue'
|
|
import { flyVisual } from '@/utils/cesium/mapUtil'
|
|
import * as Cesium from 'cesium'
|
import { PublicCesium } from '@/utils/cesium/publicCesium'
|
import { ArrowLineMaterialProperty } from '@/utils/cesium/Material'
|
import aircraftGltf from '@/assets/gltf/aircraft.gltf'
|
import EventBus from '@/utils/eventBus'
|
|
// 加载航线hook
|
const {
|
curRouteLineData,
|
routeLineListClick,
|
initViewer,
|
renderPreviewLine,
|
removePreviewLine,
|
resetCurRouteLineData,
|
renderDroneRouteLine,
|
} = useRouteLine()
|
|
let viewer = null
|
let publicCesiumInstance = null
|
|
const initMap = () => {
|
publicCesiumInstance = new PublicCesium({
|
dom: 'map',
|
terrain: true,
|
flatMode: false,
|
layerMode: 4,
|
contour: true,
|
})
|
|
viewer = publicCesiumInstance.getViewer()
|
viewer.scene.globe.depthTestAgainstTerrain = true
|
|
initViewer(viewer)
|
}
|
|
// 绘制线和飞行
|
const drawLine = async detailsData => {
|
detailsData.way_lines.forEach(async item => {
|
// if (item.is_split) {
|
// getWaylineSplitApi(item.workspace_id).then(async res => {
|
// // 大航线拆分
|
// let result = res.data.data
|
// littleFileLine.value = result.wayline_file_list
|
// let bigPolygonList = await renderPreviewLine(
|
// import.meta.env.VITE_APP_AIRLINE_URL + result.object_key,
|
// result.wayline_type,
|
// result.wayline_file_list
|
// )
|
// emit('wayLineFileSelected', bigPolygonList)
|
// })
|
// } else {
|
await renderPreviewLine(item.url, item.wayline_type)
|
// }
|
})
|
}
|
|
let arrowLineMaterialProperty = new ArrowLineMaterialProperty({
|
color: new Cesium.Color(128 / 255, 215 / 255, 255 / 255, 1),
|
directionColor: new Cesium.Color(1, 1, 1, 1),
|
outlineColor: new Cesium.Color(1, 1, 1, 1),
|
outlineWidth: 0,
|
speed: 5,
|
})
|
|
let droneEntity = null
|
let planarRouteEntity = null
|
let sampledPosition
|
|
const initPlanarRoute = data => {
|
flyVisual({ positionsData: data.map(i => [i.longitude, i.latitude, i.height]), viewer, multiple: 3.2 })
|
|
if (planarRouteEntity) {
|
viewer.entities.remove(planarRouteEntity)
|
planarRouteEntity = null
|
}
|
|
planarRouteEntity = viewer.entities.add({
|
polyline: {
|
width: 4,
|
positions: data.map(i =>
|
Cesium.Cartesian3.fromDegrees(Number(i.longitude), Number(i.latitude), Number(i.height))
|
),
|
material: arrowLineMaterialProperty,
|
clampToGround: false,
|
},
|
})
|
}
|
|
let startJulian = null
|
let endJulian = null
|
|
const init = async (positionData, detailsData) => {
|
await nextTick()
|
|
if (!viewer) initMap()
|
|
resetCurRouteLineData()
|
removePreviewLine()
|
|
drawLine(detailsData)
|
|
// initPlanarRoute(positionData)
|
|
// sampledPosition = new Cesium.SampledPositionProperty()
|
// positionData.forEach(item => {
|
// const time = toJulianDate(item.create_time)
|
// const pos = Cesium.Cartesian3.fromDegrees(item.longitude, item.latitude, item.height)
|
// sampledPosition.addSample(time, pos)
|
// })
|
|
// // 3️⃣ 设置 Clock
|
// startJulian = toJulianDate(positionData[0].create_time)
|
// endJulian = toJulianDate(positionData[positionData.length - 1].create_time)
|
// viewer.clock.startTime = startJulian.clone()
|
// viewer.clock.stopTime = endJulian.clone()
|
// viewer.clock.currentTime = startJulian.clone()
|
// viewer.clock.multiplier = 1
|
// viewer.clock.shouldAnimate = false
|
// viewer.clock.clockRange = Cesium.ClockRange.CLAMPED
|
|
// if (droneEntity) {
|
// viewer.entities.remove(droneEntity)
|
// droneEntity = null
|
// }
|
|
// droneEntity = viewer.entities.add({
|
// availability: new Cesium.TimeIntervalCollection([new Cesium.TimeInterval({ start: startJulian, stop: endJulian })]),
|
// position: sampledPosition,
|
// model: {
|
// uri: aircraftGltf, //注意entitits.add方式加载gltf文件时,这里是uri,不是url,并且这种方式只能加载.glb格式的文件
|
// scale: 1, //缩放比例
|
// minimumPixelSize: 64, //最小像素大小,可以避免太小看不见
|
// maximumScale: 128,
|
// },
|
// })
|
}
|
|
// ========== 播放/暂停/倍速/重播 控制 ==========
|
const mapAnimationPlay = () => {
|
if (!viewer) return
|
viewer.clock.shouldAnimate = true
|
}
|
|
const mapAnimationPause = () => {
|
if (!viewer) return
|
viewer.clock.shouldAnimate = false
|
}
|
|
const mapAnimationSetSpeed = speed => {
|
if (!viewer) return
|
viewer.clock.multiplier = speed
|
}
|
|
const mapAnimationReplay = () => {
|
if (!viewer) return
|
viewer.clock.currentTime = startJulian.clone()
|
viewer.clock.shouldAnimate = true
|
}
|
|
// 传入一个时间,跳转到该时间点
|
const mapAnimationSetCurrentTime = time => {
|
if (!viewer) return
|
// 支持传入 Date 或毫秒数
|
let julian = toJulianDate(time)
|
|
viewer.clock.currentTime = julian
|
// 如果希望暂停时也能直接跳过去:强制暂停后更新
|
// viewer.clock.shouldAnimate = false
|
}
|
|
// 转换函数:毫秒 → JulianDate
|
function toJulianDate(ms) {
|
return Cesium.JulianDate.fromDate(new Date(ms))
|
}
|
|
onMounted(() => {
|
// EventBus.on('mapAnimationPlay', mapAnimationPlay)
|
// EventBus.on('mapAnimationPause', mapAnimationPause)
|
// EventBus.on('mapAnimationSetSpeed', mapAnimationSetSpeed)
|
// EventBus.on('mapAnimationReplay', mapAnimationReplay)
|
// EventBus.on('mapAnimationSetCurrentTime', mapAnimationSetCurrentTime)
|
})
|
|
onBeforeUnmount(() => {
|
droneEntity && viewer.entities.remove(droneEntity)
|
droneEntity = null
|
viewer?.entities?.removeAll()
|
publicCesiumInstance?.viewerDestroy()
|
publicCesiumInstance = null
|
viewer = null
|
// EventBus.off('mapAnimationPlay', mapAnimationPlay)
|
// EventBus.off('mapAnimationPause', mapAnimationPause)
|
// EventBus.off('mapAnimationSetSpeed', mapAnimationSetSpeed)
|
// EventBus.off('mapAnimationReplay', mapAnimationReplay)
|
// EventBus.off('mapAnimationSetCurrentTime', mapAnimationSetCurrentTime)
|
})
|
|
defineExpose({
|
init,
|
})
|
</script>
|
|
<style lang="scss" scoped>
|
.map-box {
|
width: 100%;
|
height: 100%;
|
}
|
</style>
|