| New file |
| | |
| | | /* |
| | | * @Author: shuishen 1109946754@qq.com |
| | | * @Date: 2025-04-15 22:41:40 |
| | | * @LastEditors: shuishen 1109946754@qq.com |
| | | * @LastEditTime: 2025-04-16 18:31:11 |
| | | * @FilePath: \command-center-dashboard\src\hooks\useSingleDroneMap\useSingleDroneMap.js |
| | | * @Description: |
| | | * |
| | | * Copyright (c) 2025 by shuishen, All Rights Reserved. |
| | | */ |
| | | import * as Cesium from 'cesium' |
| | | import endingImg from '@/assets/images/aiNowFly/ending.png' |
| | | import endingHighImg from '@/assets/images/aiNowFly/ending-high.png' |
| | | |
| | | /** |
| | | * |
| | | * @param {Object} options - 配置选项 |
| | | */ |
| | | export function useSingleDroneMap (options = { |
| | | eventPositions: [], |
| | | eventApi: null, |
| | | eventApiParams: {} |
| | | }) { |
| | | const { eventPositions, eventApi, eventApiParams } = options |
| | | |
| | | let viewer = null |
| | | let handler = null |
| | | let currentEntity = null |
| | | |
| | | // 初始化机场位置 |
| | | const initDroneEntity = (dronePosition) => { |
| | | const { lng, lat, status } = dronePosition |
| | | |
| | | if (!lng || !lat) return |
| | | |
| | | const markerImg = status ? endingHighImg : endingImg |
| | | const position = Cesium.Cartesian3.fromDegrees(+lng, +lat, 0) |
| | | |
| | | const droneEntity = viewer?.entities.add({ |
| | | id: `single-drone-position`, |
| | | position: position, |
| | | |
| | | billboard: { |
| | | image: new Cesium.ConstantProperty(markerImg), |
| | | width: 35, |
| | | height: 35, |
| | | }, |
| | | |
| | | ellipse: { |
| | | semiMinorAxis: 5000, |
| | | semiMajorAxis: 5000, |
| | | outline: true, |
| | | material: Cesium.Color.CORNFLOWERBLUE.withAlpha(0.3), |
| | | }, |
| | | |
| | | properties: { |
| | | customData: { |
| | | data: { |
| | | type: 'single-drone-event' |
| | | } |
| | | } |
| | | } |
| | | }) |
| | | |
| | | viewer?.flyTo(droneEntity, { |
| | | offset: new Cesium.HeadingPitchRange(0, Cesium.Math.toRadians(-60), 0), |
| | | duration: 0.5, |
| | | }) |
| | | } |
| | | |
| | | // 机巢事件地图撒点 |
| | | const initDroneEventEntity = (eventPositions = eventPositions) => { |
| | | // 遍历特征并添加实体 |
| | | eventPositions.length && eventPositions.forEach((item, index) => { |
| | | const { longitude, latitude, status, id } = item |
| | | |
| | | const position = Cesium.Cartesian3.fromDegrees(+longitude, +latitude, 0) |
| | | |
| | | viewer?.entities.add({ |
| | | id: `single-drone-event-${index}`, |
| | | position: position, |
| | | billboard: { |
| | | image: new Cesium.ConstantProperty(endingHighImg), |
| | | width: 35, |
| | | height: 35, |
| | | }, |
| | | properties: { |
| | | customData: { |
| | | data: { |
| | | type: 'single-drone-sign' |
| | | } |
| | | } |
| | | }, |
| | | }) |
| | | }) |
| | | } |
| | | |
| | | // 调用传入api |
| | | const initEventApiEntity = () => { |
| | | removeEventLayer() |
| | | |
| | | eventApi( |
| | | { |
| | | ...eventApiParams, |
| | | } |
| | | ).then(res => { |
| | | const result = res.data.data.records |
| | | |
| | | initDroneEventEntity(result) |
| | | }) |
| | | } |
| | | |
| | | // 事件地图撒点加载方式 |
| | | const initEventLayer = () => { |
| | | eventApi ? initEventApiEntity() : initDroneEventEntity() |
| | | } |
| | | |
| | | const removeEventLayer = () => { |
| | | // entities移除 |
| | | const entitiesIDs = viewer?.entities.values.map(i => i.id) |
| | | entitiesIDs && entitiesIDs.forEach(item => { |
| | | item.includes('single-drone-event') && viewer?.entities.removeById(item) |
| | | }) |
| | | } |
| | | |
| | | // 移除当前地图所有entity |
| | | const removeLayer = () => { |
| | | // entities移除 |
| | | const entitiesIDs = viewer?.entities.values.map(i => i.id) |
| | | entitiesIDs.forEach(item => { |
| | | item.includes('single-drone-') && viewer?.entities.removeById(item) |
| | | }) |
| | | } |
| | | |
| | | // 查找特定类型的实体 |
| | | const findEntityByType = (entities, type) => { |
| | | return entities.find(entity => |
| | | entity?.properties?.customData?._value?.data?.type === type |
| | | ) |
| | | } |
| | | |
| | | // 左键单机事件 |
| | | const singleMachineEvent = async click => { |
| | | let clickedEntities = viewer?.scene.drillPick(click.position).map(item => item.id) |
| | | if (!clickedEntities.length) return |
| | | |
| | | const currentEntity = findEntityByType(clickedEntities, 'single-drone-event') |
| | | |
| | | removeLabel() |
| | | |
| | | if (currentEntity) { |
| | | viewer?.scene.postRender.addEventListener(labelBoxRender) |
| | | } |
| | | } |
| | | |
| | | // 事件初始化 |
| | | const handlerInit = () => { |
| | | if (handler) return |
| | | |
| | | handler = new Cesium.ScreenSpaceEventHandler(viewer?.scene.canvas) |
| | | handler.setInputAction(singleMachineEvent, Cesium.ScreenSpaceEventType.LEFT_CLICK) |
| | | } |
| | | |
| | | // 事件移除 |
| | | const removeHandler = () => { |
| | | handler?.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK) |
| | | handler?.destroy() |
| | | handler = null |
| | | } |
| | | |
| | | // 获取弹框box |
| | | const getLabelDom = data => { |
| | | const vNode = h(EventPopUpBox, { data, removeLabel }) |
| | | const tooltipContainer = document.createElement('div') |
| | | tooltipContainer.id = 'mapPopUpBox' |
| | | tooltipContainer.style.position = 'absolute' |
| | | tooltipContainer.style.transform = styleTransform |
| | | tooltipContainer.style.pointerEvents = 'none' |
| | | document.querySelector('.page-index').append(tooltipContainer) |
| | | render(vNode, tooltipContainer) |
| | | return tooltipContainer |
| | | } |
| | | |
| | | // 弹框位置刷新 |
| | | const labelBoxRender = () => { |
| | | if (!currentEntity) return |
| | | let dom = document.querySelector('#mapPopUpBox') |
| | | if (!dom) { |
| | | dom = getLabelDom(currentEntity.properties.customData._value.data) |
| | | } |
| | | const screenPosition = viewer?.scene.cartesianToCanvasCoordinates(currentEntity?.position?._value) |
| | | if (screenPosition) { |
| | | dom.style.left = `${screenPosition.x}px` |
| | | dom.style.top = `${screenPosition.y}px` |
| | | dom.style.display = 'block' |
| | | } |
| | | } |
| | | |
| | | const removeDom = () => { |
| | | const dom = document.querySelector('#mapPopUpBox') |
| | | if (dom && dom.parentNode) { |
| | | dom.parentNode.removeChild(dom) |
| | | } |
| | | } |
| | | |
| | | // 移除弹框标签 |
| | | const removeLabel = () => { |
| | | viewer?.scene.postRender.removeEventListener(labelBoxRender) |
| | | removeDom() |
| | | } |
| | | |
| | | |
| | | const init = () => { |
| | | viewer = window.$viewer |
| | | |
| | | console.log(viewer, window, 111111) |
| | | |
| | | handlerInit() |
| | | } |
| | | |
| | | const removeAll = () => { |
| | | removeLayer() |
| | | removeHandler() |
| | | removeLabel() |
| | | } |
| | | |
| | | // 自动清理 |
| | | onUnmounted(() => { |
| | | removeAll() |
| | | }) |
| | | |
| | | return { |
| | | init, |
| | | removeAll, |
| | | initEventLayer, |
| | | initDroneEntity, |
| | | } |
| | | } |