From b775b3077324cb9dd7dfdedbed8baaf7d40bf9f1 Mon Sep 17 00:00:00 2001
From: shuishen <1109946754@qq.com>
Date: Thu, 17 Apr 2025 20:45:18 +0800
Subject: [PATCH] feat:事件点、聚合点---点击事件抽离
---
src/hooks/useSingleDroneMap/useSingleDroneMap.js | 135 +++----------------
src/hooks/components/useMapHandlerClick.js | 89 +++++++++---
src/hooks/useMapAggregation/useMapAggregation.js | 139 ++++---------------
3 files changed, 117 insertions(+), 246 deletions(-)
diff --git a/src/hooks/components/useMapHandlerClick.js b/src/hooks/components/useMapHandlerClick.js
index a4854ce..82d59c5 100644
--- a/src/hooks/components/useMapHandlerClick.js
+++ b/src/hooks/components/useMapHandlerClick.js
@@ -2,33 +2,72 @@
* @Author: shuishen 1109946754@qq.com
* @Date: 2025-04-15 22:41:40
* @LastEditors: shuishen 1109946754@qq.com
- * @LastEditTime: 2025-04-16 19:02:39
+ * @LastEditTime: 2025-04-17 19:43:36
* @FilePath: \command-center-dashboard\src\hooks\components\useMapHandlerClick.js
* @Description:
*
* Copyright (c) 2025 by shuishen, All Rights Reserved.
*/
import * as Cesium from 'cesium'
+import { render } from 'vue'
+import { useStore } from 'vuex'
+
+import DevicePopUpBox from '@/hooks/components/DevicePopUpBox.vue'
import EventPopUpBox from '@/hooks/components/EventPopUpBox.vue'
/**
*
* @param {Object} options - 配置选项
*/
-export function useMapHandlerClick (viewer, options = {
- type: 'single-drone-event',
- customDom: EventPopUpBox
-}) {
- const { type } = options
+export function useMapHandlerClick (options = {}) {
+ const {
+ popupType = 'event-popup',
+ eventType = 'single-drone-event',
+ styleTransform = 'translate(-50%,-110%)',
+ getViewer
+ } = options
- const currentClickEntity = ref(null)
+ const store = useStore()
+
+ const popupData = {
+ 'event-popup': EventPopUpBox,
+ 'device-popup': DevicePopUpBox
+ }
+
+ const MapPopUpBox = popupData[popupType]
+
+ let viewer = null
let handler = null
+ let currentClickEntity = null
// 查找特定类型的实体
const findEntityByType = (entities, type) => {
- return entities.find(entity =>
- entity?.properties?.customData?._value?.data?.type === type
- )
+ let types = []
+
+ Array.isArray(type) ? types = type : types = [type]
+
+ return types.reduce((pre, curType) => {
+ let entity = entities.find(entity => entity?.properties?.customData?._value?.data?.type === curType)
+
+ return entity ? (pre.push({
+ type: curType,
+ entity
+ }), pre) : pre
+ }, [])
+ }
+
+ const publicEvent = (entity) => {
+ viewer.scene.postRender.addEventListener(labelBoxRender)
+ }
+
+ const typeEvent = {
+ 'deviceAggregation': publicEvent,
+ 'single-drone-event': publicEvent,
+ 'event': publicEvent,
+ 'device': (entity) => {
+ const device = entity.properties.customData._value.data
+ store.commit('setSingleUavHome', device)
+ }
}
// 左键单机事件
@@ -36,17 +75,21 @@
let clickedEntities = viewer?.scene.drillPick(click.position).map(item => item.id)
if (!clickedEntities.length) return
- currentClickEntity.value = findEntityByType(clickedEntities, type)
+ let curClick = findEntityByType(clickedEntities, eventType)
removeLabel()
- if (currentClickEntity.value) {
- viewer?.scene.postRender.addEventListener(labelBoxRender)
+ if (curClick.length > 0 && typeEvent[curClick[0].type]) {
+ currentClickEntity = curClick[0].entity
+
+ typeEvent[curClick[0].type](currentClickEntity)
}
}
// 事件初始化
const handlerInit = () => {
+ !viewer && (viewer = getViewer())
+
if (handler) return
handler = new Cesium.ScreenSpaceEventHandler(viewer?.scene.canvas)
@@ -62,7 +105,7 @@
// 获取弹框box
const getLabelDom = data => {
- const vNode = h(customDom, { data, removeLabel })
+ const vNode = h(MapPopUpBox, { data, removeLabel })
const tooltipContainer = document.createElement('div')
tooltipContainer.id = 'mapPopUpBox'
tooltipContainer.style.position = 'absolute'
@@ -75,12 +118,12 @@
// 弹框位置刷新
const labelBoxRender = () => {
- if (!currentEntity) return
+ if (!currentClickEntity) return
let dom = document.querySelector('#mapPopUpBox')
if (!dom) {
- dom = getLabelDom(currentEntity.properties.customData._value.data)
+ dom = getLabelDom(currentClickEntity.properties.customData._value.data)
}
- const screenPosition = viewer?.scene.cartesianToCanvasCoordinates(currentEntity?.position?._value)
+ const screenPosition = viewer?.scene.cartesianToCanvasCoordinates(currentClickEntity?.position?._value)
if (screenPosition) {
dom.style.left = `${screenPosition.x}px`
dom.style.top = `${screenPosition.y}px`
@@ -101,15 +144,19 @@
removeDom()
}
- // 自动清理
- onUnmounted(() => {
+ const removeAll = () => {
removeHandler()
removeLabel()
+ }
+
+ // 自动清理
+ onUnmounted(() => {
+ removeAll()
})
return {
- currentClickEntity,
handlerInit,
- removeHandler
+ removeAll,
+ removeLabel
}
}
\ No newline at end of file
diff --git a/src/hooks/useMapAggregation/useMapAggregation.js b/src/hooks/useMapAggregation/useMapAggregation.js
index 5557967..d46d74a 100644
--- a/src/hooks/useMapAggregation/useMapAggregation.js
+++ b/src/hooks/useMapAggregation/useMapAggregation.js
@@ -3,30 +3,19 @@
import eventAggregationImg from '@/assets/images/home/useUavHome/eventAggregationImg.png'
import uavImg from '@/assets/images/home/useUavHome/uavImg.png'
-// 事件图标
-import eventSingle from '@/assets/images/home/useEventOperate/eventSingle.png'
+import { getEventImage } from '@/utils/stateToImageMap/event'
+import { getDroneStatusImage } from '@/utils/stateToImageMap/drone'
-import eventPending from '@/assets/images/home/useEventOperate/eventPending.png' // 待处理 0
-import eventWaitAudit from '@/assets/images/home/useEventOperate/eventWaitAudit.png' // 待审核 2
-import eventProcessing from '@/assets/images/home/useEventOperate/eventProcessing.png' // 处理中 3
-import eventCompleted from '@/assets/images/home/useEventOperate/eventCompleted.png' // 已完成 4
-import eventClosed from '@/assets/images/home/useEventOperate/eventClosed.png' // 已完结 5
-
-import DevicePopUpBox from '@/hooks/components/DevicePopUpBox.vue'
-import EventPopUpBox from '@/hooks/components/EventPopUpBox.vue'
-
-
-// 机巢图标
-import endingImg from '@/assets/images/aiNowFly/ending.png'
-import endingHighImg from '@/assets/images/aiNowFly/ending-high.png'
-
-import { render } from 'vue'
import { useStore } from 'vuex'
import { getCenterPoint } from '@/utils/cesium/mapUtil'
import cesiumOperation from '@/utils/cesium-tsa'
import { getDeviceRegion, getDeviceRegionCount, getEventDetails, getMapEvents } from '@/api/home/aggregation'
import { PolyGradientMaterial } from '@/utils/cesium/Material'
import { start } from 'nprogress'
+
+// hook
+import { useMapHandlerClick } from '@/hooks/components/useMapHandlerClick'
+
/**
* 机巢聚合功能
*/
@@ -51,8 +40,21 @@
const { flyTo } = cesiumOperation()
const mergeImg = type === 'device' ? aggregationImg : eventAggregationImg
- const MapPopUpBox = type === 'device' ? DevicePopUpBox : EventPopUpBox
const styleTransform = type === 'device' ? 'translateY(-50%)' : 'translate(-50%,-110%)'
+ const eventType = type === 'device' ? ['deviceAggregation', 'device'] : 'event'
+
+ const {
+ handlerInit: mapHandlerInit,
+ removeAll: removeMapHandlerAll,
+ removeLabel: removeMapLabel
+ } = useMapHandlerClick({
+ popupType: `${type}-popup`,
+ eventType: eventType,
+ styleTransform,
+ getViewer () {
+ return viewer
+ }
+ })
let scalingJudgment = [
{ name: '县', splashedList: [], gJson: null, show: false, outline: {}, value: [0, 48651], height: 31753 },
@@ -69,8 +71,6 @@
]
let viewer = null
let active = null
- let handler = null
- let currentEntity = null
const store = useStore()
const userAreaCode = computed(() => store.state.user.userInfo.detail.areaCode)
@@ -104,7 +104,7 @@
if (active === item.name) return
active = item.name
removeEntities()
- removeLabel()
+ removeMapLabel()
renderOutline(item)
if (!item.gJson && !item.splashedList?.length) return
item.gJson ? aggregation(item) : splashed(item)
@@ -288,7 +288,7 @@
needFly = true
if (!viewer) return
- handlerInit()
+ mapHandlerInit()
viewer.scene.postRender.removeEventListener(determineScaling)
@@ -302,15 +302,7 @@
//散点机巢
function splashed (row) {
row.splashedList.forEach((item, index) => {
- const eventImage = {
- 0: eventPending,
- 2: eventWaitAudit,
- 3: eventProcessing,
- 4: eventCompleted,
- 5: eventClosed
- }
-
- const image = type === 'device' ? (item.status === "OFFLINE" ? endingHighImg : endingImg) : eventImage[item.status] || eventSingle
+ const image = type === 'device' ? getDroneStatusImage(item.status) : getEventImage(item.status)
viewer.entities.add({
id: `aggregation-splashed-${index}`,
@@ -470,33 +462,6 @@
})
}
- // 获取弹框box
- const getLabelDom = data => {
- const vNode = h(MapPopUpBox, { 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'
- }
- }
/**
* 根据条件获取项
@@ -506,41 +471,6 @@
*/
const findTypeItem = (arr, condition) => {
return arr.find(item => condition(item))
- }
-
- // 左键单机事件
- const singleMachineEvent = async click => {
- let clickTargets = viewer.scene.drillPick(click.position).map(item => item.id)
- if (!clickTargets.length) return
-
- let deviceAggregationFind = findTypeItem(
- clickTargets,
- item => item?.properties?.customData?._value?.data?.type === 'deviceAggregation'
- )
- let deviceFind = findTypeItem(clickTargets, item => item?.properties?.customData?._value?.data?.type === 'device')
- // "event"
- let eventFind = findTypeItem(clickTargets, item => item?.properties?.customData?._value?.data?.type === 'event')
- // let eventFind = findTypeItem(clickTargets, (item) => item?.properties?.customData?._value?.data?.type === 'eventAggregation')
- currentEntity = deviceAggregationFind || deviceFind || eventFind
-
- if (!currentEntity) return
- if (!currentEntity?.position?._value) return
- // 一定要移除
- removeLabel()
- if (deviceAggregationFind || eventFind) {
- viewer.scene.postRender.addEventListener(labelBoxRender)
- }
- if (deviceFind) {
- const device = deviceFind.properties.customData._value.data
- store.commit('setSingleUavHome', device)
- }
- }
-
- const removeDom = () => {
- const dom = document.querySelector('#mapPopUpBox')
- if (dom && dom.parentNode) {
- dom.parentNode.removeChild(dom)
- }
}
// 移除 点 和 gjson 实体
@@ -556,11 +486,7 @@
item.includes('aggregation-') && viewer.entities.removeById(item)
})
}
- // 移除弹框标签
- const removeLabel = () => {
- viewer?.scene.postRender.removeEventListener(labelBoxRender)
- removeDom()
- }
+
// 移除所有监听事件,变量置空
const removeAll = () => {
@@ -571,14 +497,12 @@
const clearMapEntity = () => {
if (!viewer) return
removeEntities()
- removeLabel()
+ removeMapHandlerAll()
+
// viewer.camera.moveEnd.removeEventListener(determineScaling);
viewer.scene.postRender.removeEventListener(determineScaling)
- handler?.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK)
- handler?.destroy()
+
active = null
- handler = null
- currentEntity = null
}
const init = () => {
@@ -588,14 +512,7 @@
viewer.scene.postRender.addEventListener(determineScaling)
})
- handlerInit()
- }
-
- const handlerInit = () => {
- if (handler) return
-
- handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
- handler.setInputAction(singleMachineEvent, Cesium.ScreenSpaceEventType.LEFT_CLICK)
+ mapHandlerInit()
}
onBeforeUnmount(() => { })
diff --git a/src/hooks/useSingleDroneMap/useSingleDroneMap.js b/src/hooks/useSingleDroneMap/useSingleDroneMap.js
index ff7f0c3..b8b7aa7 100644
--- a/src/hooks/useSingleDroneMap/useSingleDroneMap.js
+++ b/src/hooks/useSingleDroneMap/useSingleDroneMap.js
@@ -2,25 +2,18 @@
* @Author: shuishen 1109946754@qq.com
* @Date: 2025-04-15 22:41:40
* @LastEditors: shuishen 1109946754@qq.com
- * @LastEditTime: 2025-04-17 15:05:32
+ * @LastEditTime: 2025-04-17 20:24:19
* @FilePath: \command-center-dashboard\src\hooks\useSingleDroneMap\useSingleDroneMap.js
* @Description:
*
* Copyright (c) 2025 by shuishen, All Rights Reserved.
*/
import * as Cesium from 'cesium'
-import { render } from 'vue'
-import endingImg from '@/assets/images/aiNowFly/ending.png'
-import endingHighImg from '@/assets/images/aiNowFly/ending-high.png'
-import EventPopUpBox from '@/hooks/components/EventPopUpBox.vue'
-import eventSingle from '@/assets/images/home/useEventOperate/eventSingle.png'
+import { getEventImage } from '@/utils/stateToImageMap/event'
+import { getDroneFlagImage } from '@/utils/stateToImageMap/drone'
-import eventPending from '@/assets/images/home/useEventOperate/eventPending.png' // 待处理 0
-import eventWaitAudit from '@/assets/images/home/useEventOperate/eventWaitAudit.png' // 待审核 2
-import eventProcessing from '@/assets/images/home/useEventOperate/eventProcessing.png' // 处理中 3
-import eventCompleted from '@/assets/images/home/useEventOperate/eventCompleted.png' // 已完成 4
-import eventClosed from '@/assets/images/home/useEventOperate/eventClosed.png' // 已完结 5
+import { useMapHandlerClick } from '@/hooks/components/useMapHandlerClick'
/**
*
@@ -31,20 +24,18 @@
eventApi: null,
eventApiParams: {}
}) {
- const styleTransform = 'translate(-50%,-110%)'
-
const { eventPositions, eventApi, eventApiParams } = options
- const eventImage = {
- 0: eventPending,
- 2: eventWaitAudit,
- 3: eventProcessing,
- 4: eventCompleted,
- 5: eventClosed
- }
let viewer = null
- let handler = null
- let currentEntity = null
+
+ const {
+ handlerInit: mapHandlerInit,
+ removeAll: removeMapHandlerAll
+ } = useMapHandlerClick({
+ getViewer () {
+ return viewer
+ }
+ })
// 初始化机场位置
const initDroneEntity = (dronePosition) => {
@@ -52,7 +43,7 @@
if (!lng || !lat) return
- const markerImg = status ? endingHighImg : endingImg
+ const markerImg = getDroneFlagImage(status)
const position = Cesium.Cartesian3.fromDegrees(+lng, +lat, 0)
const droneEntity = viewer?.entities.add({
@@ -93,7 +84,7 @@
eventData.length && eventData.forEach((item, index) => {
const { longitude, latitude, status, id } = item
- const curImg = eventImage[status] || eventSingle
+ const curImg = getEventImage(status)
const position = Cesium.Cartesian3.fromDegrees(+longitude, +latitude, 0)
@@ -109,7 +100,7 @@
customData: {
data: {
...item,
- eventId: item.id,
+ eventId: id,
type: 'single-drone-event'
}
}
@@ -155,104 +146,20 @@
})
}
- // 查找特定类型的实体
- const findEntityByType = (entities, type) => {
- return entities.find(entity =>
- entity?.properties?.customData?._value?.data?.type === type
- )
- }
-
- // 左键单机事件
- const singleMachineEvent = async click => {
- currentEntity = null
-
- let clickedEntities = viewer?.scene.drillPick(click.position).map(item => item.id)
-
- if (!clickedEntities?.length) return
-
- 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
- handlerInit()
+ mapHandlerInit()
}
const removeAll = () => {
removeLayer()
- removeHandler()
- removeLabel()
+ removeMapHandlerAll()
}
- onMounted(() => {
- nextTick(() => {
- init()
- })
+ onMounted(async () => {
+ await nextTick()
+ init()
})
// 自动清理
--
Gitblit v1.9.3