1.添加屏幕鼠标事件的模式(浏览、绘制),绘制操作属于绘制模式,点击地图要素显示属性属于浏览模式,防止两者事件冲突;

This commit is contained in:
zhangquan 2025-07-19 16:20:39 +08:00
parent 74d661c8a7
commit 4827a7da46
12 changed files with 59 additions and 52 deletions

View File

@ -15,12 +15,12 @@ import { createAttackArrowPositions } from './draw/attackArrowGraphic'
* @returns Promise 绘制完成的所有点坐标数组 * @returns Promise 绘制完成的所有点坐标数组
*/ */
export const drawAttackArrow = (deps) => { export const drawAttackArrow = (deps) => {
const { viewer, bus, position, status, registerAbort, globalAbort } = deps const { viewer, bus, ScreenMode, position, registerAbort, globalAbort } = deps
// 如果在执行其它操作,则取消 // 如果在执行其它操作,则取消
globalAbort() globalAbort()
status.value = 'Drawing' bus.mode.value = ScreenMode.DRAW
const featurePositions = [] const featurePositions = []
// 临时多边形实体 (包含填充和边界线) // 临时多边形实体 (包含填充和边界线)
@ -79,11 +79,11 @@ export const drawAttackArrow = (deps) => {
// 清理资源 // 清理资源
const dispose = () => { const dispose = () => {
registerAbort(null) // 取消注册当前的 abort 回调 registerAbort(null) // 取消注册当前的 abort 回调
status.value = 'Default'
viewer.entities.remove(tempPolygon) viewer.entities.remove(tempPolygon)
bus.offScreen(ScreenSpaceEventType.LEFT_CLICK, handleAddPoint) bus.offScreen(ScreenSpaceEventType.LEFT_CLICK, handleAddPoint)
bus.offScreen(ScreenSpaceEventType.RIGHT_CLICK, handleCancelDraw) bus.offScreen(ScreenSpaceEventType.RIGHT_CLICK, handleCancelDraw)
bus.offScreen(ScreenSpaceEventType.LEFT_DOUBLE_CLICK, handleEndDraw) bus.offScreen(ScreenSpaceEventType.LEFT_DOUBLE_CLICK, handleEndDraw)
bus.mode.value = ScreenMode.VIEW
} }
// 取消绘制 // 取消绘制

View File

@ -15,12 +15,12 @@ import { createCurvePolygonPositions } from './draw/curvePolygonGraphic'
* @returns Promise 绘制完成的所有点坐标数组 * @returns Promise 绘制完成的所有点坐标数组
*/ */
export const drawCurvePolygon = (deps) => { export const drawCurvePolygon = (deps) => {
const { viewer, bus, position, status, registerAbort, globalAbort } = deps const { viewer, bus, ScreenMode, position, registerAbort, globalAbort } = deps
// 如果在执行其它操作,则取消 // 如果在执行其它操作,则取消
globalAbort() globalAbort()
status.value = 'Drawing' bus.mode.value = ScreenMode.DRAW
const featurePositions = [] const featurePositions = []
// 临时多边形实体 (包含填充和边界线) // 临时多边形实体 (包含填充和边界线)
@ -74,11 +74,11 @@ export const drawCurvePolygon = (deps) => {
// 清理资源 // 清理资源
const dispose = () => { const dispose = () => {
registerAbort(null) // 取消注册当前的 abort 回调 registerAbort(null) // 取消注册当前的 abort 回调
status.value = 'Default'
viewer.entities.remove(tempPolygon) viewer.entities.remove(tempPolygon)
bus.offScreen(ScreenSpaceEventType.LEFT_CLICK, handleAddPoint) bus.offScreen(ScreenSpaceEventType.LEFT_CLICK, handleAddPoint)
bus.offScreen(ScreenSpaceEventType.RIGHT_CLICK, handleCancelDraw) bus.offScreen(ScreenSpaceEventType.RIGHT_CLICK, handleCancelDraw)
bus.offScreen(ScreenSpaceEventType.LEFT_DOUBLE_CLICK, handleEndDraw) bus.offScreen(ScreenSpaceEventType.LEFT_DOUBLE_CLICK, handleEndDraw)
bus.mode.value = ScreenMode.VIEW
} }
// 取消绘制 // 取消绘制

View File

@ -15,12 +15,12 @@ import { createDoubleArrowPositions } from './draw/doubleArrowGraphic'
* @returns Promise 绘制完成的所有点坐标数组 * @returns Promise 绘制完成的所有点坐标数组
*/ */
export const drawDoubleArrow = (deps) => { export const drawDoubleArrow = (deps) => {
const { viewer, bus, position, status, registerAbort, globalAbort } = deps const { viewer, bus, ScreenMode, position, registerAbort, globalAbort } = deps
// 如果在执行其它操作,则取消 // 如果在执行其它操作,则取消
globalAbort() globalAbort()
status.value = 'Drawing' bus.mode.value = ScreenMode.DRAW
const featurePositions = [] const featurePositions = []
// 临时多边形实体 (包含填充和边界线) // 临时多边形实体 (包含填充和边界线)
@ -79,11 +79,11 @@ export const drawDoubleArrow = (deps) => {
// 清理资源 // 清理资源
const dispose = () => { const dispose = () => {
registerAbort(null) // 取消注册当前的 abort 回调 registerAbort(null) // 取消注册当前的 abort 回调
status.value = 'Default'
viewer.entities.remove(tempPolygon) viewer.entities.remove(tempPolygon)
bus.offScreen(ScreenSpaceEventType.LEFT_CLICK, handleAddPoint) bus.offScreen(ScreenSpaceEventType.LEFT_CLICK, handleAddPoint)
bus.offScreen(ScreenSpaceEventType.RIGHT_CLICK, handleCancelDraw) bus.offScreen(ScreenSpaceEventType.RIGHT_CLICK, handleCancelDraw)
bus.offScreen(ScreenSpaceEventType.LEFT_DOUBLE_CLICK, handleEndDraw) bus.offScreen(ScreenSpaceEventType.LEFT_DOUBLE_CLICK, handleEndDraw)
bus.mode.value = ScreenMode.VIEW
} }
// 取消绘制 // 取消绘制

View File

@ -6,20 +6,20 @@ import { Cartesian3, ScreenSpaceEventType } from 'cesium'
* @returns Promise 绘制完成的点坐标 * @returns Promise 绘制完成的点坐标
*/ */
export const drawPoint = (deps) => { export const drawPoint = (deps) => {
const { bus, position, status, registerAbort, globalAbort } = deps const { bus, ScreenMode, position, registerAbort, globalAbort } = deps
// 如果在执行其它操作,则取消 // 如果在执行其它操作,则取消
globalAbort() globalAbort()
status.value = 'Drawing' bus.mode.value = ScreenMode.DRAW
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
// 清理资源 // 清理资源
const dispose = () => { const dispose = () => {
registerAbort(null) // 取消注册当前的 abort 回调 registerAbort(null) // 取消注册当前的 abort 回调
status.value = 'Default'
bus.offScreen(ScreenSpaceEventType.LEFT_CLICK, handleDraw) bus.offScreen(ScreenSpaceEventType.LEFT_CLICK, handleDraw)
bus.offScreen(ScreenSpaceEventType.RIGHT_CLICK, handleCancel) bus.offScreen(ScreenSpaceEventType.RIGHT_CLICK, handleCancel)
bus.mode.value = ScreenMode.VIEW
} }
// 取消绘制 // 取消绘制

View File

@ -14,12 +14,12 @@ import {
* @returns Promise 绘制完成的所有点坐标数组 * @returns Promise 绘制完成的所有点坐标数组
*/ */
export const drawPolygon = (deps) => { export const drawPolygon = (deps) => {
const { viewer, bus, position, status, registerAbort, globalAbort } = deps const { viewer, bus, ScreenMode, position, registerAbort, globalAbort } = deps
// 如果在执行其它操作,则取消 // 如果在执行其它操作,则取消
globalAbort() globalAbort()
status.value = 'Drawing' bus.mode.value = ScreenMode.DRAW
const featurePositions = [] const featurePositions = []
// 临时多边形实体 (包含填充和边界线) // 临时多边形实体 (包含填充和边界线)
@ -74,11 +74,11 @@ export const drawPolygon = (deps) => {
// 清理资源 // 清理资源
const dispose = () => { const dispose = () => {
registerAbort(null) // 取消注册当前的 abort 回调 registerAbort(null) // 取消注册当前的 abort 回调
status.value = 'Default'
viewer.entities.remove(tempPolygon) viewer.entities.remove(tempPolygon)
bus.offScreen(ScreenSpaceEventType.LEFT_CLICK, handleAddPoint) bus.offScreen(ScreenSpaceEventType.LEFT_CLICK, handleAddPoint)
bus.offScreen(ScreenSpaceEventType.RIGHT_CLICK, handleCancelDraw) bus.offScreen(ScreenSpaceEventType.RIGHT_CLICK, handleCancelDraw)
bus.offScreen(ScreenSpaceEventType.LEFT_DOUBLE_CLICK, handleEndDraw) bus.offScreen(ScreenSpaceEventType.LEFT_DOUBLE_CLICK, handleEndDraw)
bus.mode.value = ScreenMode.VIEW
} }
// 取消绘制 // 取消绘制

View File

@ -12,12 +12,12 @@ import {
* @returns Promise 绘制完成的所有点坐标数组 * @returns Promise 绘制完成的所有点坐标数组
*/ */
export const drawPolyline = (deps) => { export const drawPolyline = (deps) => {
const { viewer, bus, position, status, registerAbort, globalAbort } = deps const { viewer, bus, ScreenMode, position, registerAbort, globalAbort } = deps
// 如果在执行其它操作,则取消 // 如果在执行其它操作,则取消
globalAbort() globalAbort()
status.value = 'Drawing' bus.mode.value = ScreenMode.DRAW
const featurePositions = [] const featurePositions = []
// 临时折线实体 // 临时折线实体
@ -47,11 +47,11 @@ export const drawPolyline = (deps) => {
// 清理资源 // 清理资源
const dispose = () => { const dispose = () => {
registerAbort(null) // 取消注册当前的 abort 回调 registerAbort(null) // 取消注册当前的 abort 回调
status.value = 'Default'
viewer.entities.remove(tempPolyline) viewer.entities.remove(tempPolyline)
bus.offScreen(ScreenSpaceEventType.LEFT_CLICK, handleAddPoint) bus.offScreen(ScreenSpaceEventType.LEFT_CLICK, handleAddPoint)
bus.offScreen(ScreenSpaceEventType.RIGHT_CLICK, handleCancelDraw) bus.offScreen(ScreenSpaceEventType.RIGHT_CLICK, handleCancelDraw)
bus.offScreen(ScreenSpaceEventType.LEFT_DOUBLE_CLICK, handleEndDraw) bus.offScreen(ScreenSpaceEventType.LEFT_DOUBLE_CLICK, handleEndDraw)
bus.mode.value = ScreenMode.VIEW
} }
// 取消绘制 // 取消绘制

View File

@ -15,12 +15,12 @@ import { createStraightArrowPositions } from './draw/straightArrowGraphic'
* @returns Promise 绘制完成的所有点坐标数组 * @returns Promise 绘制完成的所有点坐标数组
*/ */
export const drawStraightArrow = (deps) => { export const drawStraightArrow = (deps) => {
const { viewer, bus, position, status, registerAbort, globalAbort } = deps const { viewer, bus, ScreenMode, position, registerAbort, globalAbort } = deps
// 如果在执行其它操作,则取消 // 如果在执行其它操作,则取消
globalAbort() globalAbort()
status.value = 'Drawing' bus.mode.value = ScreenMode.DRAW
const featurePositions = [] const featurePositions = []
// 临时多边形实体 (包含填充和边界线) // 临时多边形实体 (包含填充和边界线)
@ -75,11 +75,11 @@ export const drawStraightArrow = (deps) => {
// 清理资源 // 清理资源
const dispose = () => { const dispose = () => {
registerAbort(null) // 取消注册当前的 abort 回调 registerAbort(null) // 取消注册当前的 abort 回调
status.value = 'Default'
viewer.entities.remove(tempPolygon) viewer.entities.remove(tempPolygon)
bus.offScreen(ScreenSpaceEventType.LEFT_CLICK, handleAddPoint) bus.offScreen(ScreenSpaceEventType.LEFT_CLICK, handleAddPoint)
bus.offScreen(ScreenSpaceEventType.RIGHT_CLICK, handleCancelDraw) bus.offScreen(ScreenSpaceEventType.RIGHT_CLICK, handleCancelDraw)
bus.offScreen(ScreenSpaceEventType.LEFT_DOUBLE_CLICK, handleEndDraw) bus.offScreen(ScreenSpaceEventType.LEFT_DOUBLE_CLICK, handleEndDraw)
bus.mode.value = ScreenMode.VIEW
} }
// 取消绘制 // 取消绘制

View File

@ -15,12 +15,12 @@ import { createWideArrowPositions } from './draw/wideArrowGraphic'
* @returns Promise 绘制完成的所有点坐标数组 * @returns Promise 绘制完成的所有点坐标数组
*/ */
export const drawWideArrow = (deps) => { export const drawWideArrow = (deps) => {
const { viewer, bus, position, status, registerAbort, globalAbort } = deps const { viewer, bus, ScreenMode, position, registerAbort, globalAbort } = deps
// 如果在执行其它操作,则取消 // 如果在执行其它操作,则取消
globalAbort() globalAbort()
status.value = 'Drawing' bus.mode.value = ScreenMode.DRAW
const featurePositions = [] const featurePositions = []
// 临时多边形实体 (包含填充和边界线) // 临时多边形实体 (包含填充和边界线)
@ -76,11 +76,11 @@ export const drawWideArrow = (deps) => {
// 清理资源 // 清理资源
const dispose = () => { const dispose = () => {
registerAbort(null) // 取消注册当前的 abort 回调 registerAbort(null) // 取消注册当前的 abort 回调
status.value = 'Default'
viewer.entities.remove(tempPolygon) viewer.entities.remove(tempPolygon)
bus.offScreen(ScreenSpaceEventType.LEFT_CLICK, handleAddPoint) bus.offScreen(ScreenSpaceEventType.LEFT_CLICK, handleAddPoint)
bus.offScreen(ScreenSpaceEventType.RIGHT_CLICK, handleCancelDraw) bus.offScreen(ScreenSpaceEventType.RIGHT_CLICK, handleCancelDraw)
bus.offScreen(ScreenSpaceEventType.LEFT_DOUBLE_CLICK, handleEndDraw) bus.offScreen(ScreenSpaceEventType.LEFT_DOUBLE_CLICK, handleEndDraw)
bus.mode.value = ScreenMode.VIEW
} }
// 取消绘制 // 取消绘制

View File

@ -8,7 +8,7 @@ import {
Color as CesiumColor, Color as CesiumColor,
HeightReference, HeightReference,
} from 'cesium' } from 'cesium'
import { useEventBus } from '../useEventBus' import { useEventBus, ScreenMode } from '../useEventBus'
import { useHoverPosition } from '../useHoverPosition' import { useHoverPosition } from '../useHoverPosition'
// 导入拆分后的类型和绘制逻辑 // 导入拆分后的类型和绘制逻辑
@ -39,13 +39,13 @@ export const useDrawTool = (viewer) => {
const { isHover, position } = useHoverPosition(viewer) const { isHover, position } = useHoverPosition(viewer)
// 获取事件总线 // 获取事件总线
const bus = useEventBus(viewer) const bus = useEventBus(viewer)
const status = ref('Default') // const status = ref('Default')
// 判断辅助点是否显示 // 判断辅助点是否显示
watch( watch(
() => [status.value, isHover.value], () => [bus.mode.value, isHover.value],
([nowStatus, hover]) => { ([nowStatus, hover]) => {
if (hover && nowStatus === 'Drawing') { if (hover && nowStatus === ScreenMode.DRAW) {
assistPoint.show = true assistPoint.show = true
} else { } else {
assistPoint.show = false assistPoint.show = false
@ -92,8 +92,8 @@ export const useDrawTool = (viewer) => {
const drawDependencies = { const drawDependencies = {
viewer, viewer,
bus, bus,
ScreenMode,
position, position,
status,
registerAbort, registerAbort,
globalAbort: abort, // 将全局 abort 函数也传递进去,方便内部调用 globalAbort: abort, // 将全局 abort 函数也传递进去,方便内部调用
} }
@ -137,8 +137,6 @@ export const useDrawTool = (viewer) => {
drawAttackArrow, drawAttackArrow,
drawDoubleArrow, drawDoubleArrow,
abort, abort,
// 如果需要,可以暴露 status
// status
} }
} }

View File

@ -1,11 +1,18 @@
import mitt from 'mitt' import mitt from 'mitt'
import { Viewer, ScreenSpaceEventHandler, ScreenSpaceEventType } from 'cesium' import { ref } from 'vue'
import { ScreenSpaceEventHandler, ScreenSpaceEventType } from 'cesium'
// 使用 Map 来缓存每个 viewer 对应的事件总线组件 // 使用 Map 来缓存每个 viewer 对应的事件总线组件
// Viewer 实例作为 Map 的键 // Viewer 实例作为 Map 的键
const viewerEventBusCache = new Map() const viewerEventBusCache = new Map()
// 屏幕鼠标事件模式
export const ScreenMode = {
VIEW: 1000,
DRAW: 2000,
}
/** /**
* 消息总线接管全局屏幕空间事件仅作用于单个 Viewer * 消息总线接管全局屏幕空间事件仅作用于单个 Viewer
* 调用该hook后所有鼠标事件必须改为调用返回对象中的方法 * 调用该hook后所有鼠标事件必须改为调用返回对象中的方法
@ -18,6 +25,7 @@ export const useEventBus = (viewer) => {
let cache = viewerEventBusCache.get(viewer) let cache = viewerEventBusCache.get(viewer)
if (!cache) { if (!cache) {
cache = { cache = {
mode: ref(ScreenMode.VIEW),
// 创建一个 mitt 实例用于处理所有屏幕空间事件 // 创建一个 mitt 实例用于处理所有屏幕空间事件
screenEmitter: mitt(), screenEmitter: mitt(),
// 创建一个 mitt 实例用于处理自定义事件 // 创建一个 mitt 实例用于处理自定义事件
@ -35,19 +43,20 @@ export const useEventBus = (viewer) => {
// 构建返回的 EventBus 对象 // 构建返回的 EventBus 对象
const bus = { const bus = {
// 移除 mode 属性的定义 mode: cache.mode,
// onScreen 直接注册到 screenEmitter // onScreen 直接注册到 screenEmitter
// onScreen(event, handler) { onScreen(event, handler, mode) {
// screenEmitter.on(event, handler) mode = mode || cache.mode.value
// }, cache.screenEmitter.on(mode + event, handler)
onScreen: cache.screenEmitter.on, },
// onScreen: cache.screenEmitter.on,
// offScreen 直接从 screenEmitter 移除 // offScreen 直接从 screenEmitter 移除
// offScreen(event, handler) { offScreen(event, handler, mode) {
// screenEmitter.off(event, handler) mode = mode || cache.mode.value
// }, cache.screenEmitter.off(mode + event, handler)
offScreen: cache.screenEmitter.off, },
// offScreen: cache.screenEmitter.off,
// on 保持不变 // on 保持不变
// on(event, handler) { // on(event, handler) {
@ -71,7 +80,7 @@ export const useEventBus = (viewer) => {
} else if (Object.values(ScreenSpaceEventType).includes(event)) { } else if (Object.values(ScreenSpaceEventType).includes(event)) {
// 触发屏幕空间事件 (触发所有监听器,无模式检查) // 触发屏幕空间事件 (触发所有监听器,无模式检查)
// 屏幕空间事件通常只有一个参数 // 屏幕空间事件通常只有一个参数
cache.screenEmitter.emit(event, args[0]) cache.screenEmitter.emit(cache.mode.value + event, args[0])
} else { } else {
console.warn(`EventBus: 不符合规范的触发事件: ${event}`) console.warn(`EventBus: 不符合规范的触发事件: ${event}`)
} }

View File

@ -8,7 +8,7 @@ import {
} from 'cesium' } from 'cesium'
import { computed, ref, shallowRef } from 'vue' import { computed, ref, shallowRef } from 'vue'
import { useElementHover } from '@vueuse/core' import { useElementHover } from '@vueuse/core'
import { useEventBus } from './useEventBus' import { useEventBus, ScreenMode } from './useEventBus'
// 使用 Map 来缓存每个 viewer 对应的位置缓存 // 使用 Map 来缓存每个 viewer 对应的位置缓存
// Viewer 实例作为 Map 的键 // Viewer 实例作为 Map 的键
@ -25,7 +25,7 @@ export const useHoverPosition = (viewer) => {
// const coordinate = shallowRef<Cartographic | null>(null) // const coordinate = shallowRef<Cartographic | null>(null)
// 添加鼠标移动事件 // 添加鼠标移动事件
const bus = useEventBus(viewer) const bus = useEventBus(viewer)
bus.onScreen(ScreenSpaceEventType.MOUSE_MOVE, (param) => { const hoverHandler = (param) => {
screenPosition.value = param.endPosition.clone() screenPosition.value = param.endPosition.clone()
position.value = viewer.scene.pickPosition(param.endPosition) position.value = viewer.scene.pickPosition(param.endPosition)
bus.emit('hoverTest', { bus.emit('hoverTest', {
@ -33,7 +33,10 @@ export const useHoverPosition = (viewer) => {
position: position.value, position: position.value,
}) })
// coordinate.value = Cartographic.fromCartesian(position.value) // coordinate.value = Cartographic.fromCartesian(position.value)
}) }
// 每个模式都关联事件
bus.onScreen(ScreenSpaceEventType.MOUSE_MOVE, hoverHandler, ScreenMode.VIEW)
bus.onScreen(ScreenSpaceEventType.MOUSE_MOVE, hoverHandler, ScreenMode.DRAW)
cache = { cache = {
isHover, isHover,
screenPosition, screenPosition,

View File

@ -10,7 +10,7 @@
import { shallowRef } from 'vue'; import { shallowRef } from 'vue';
import * as Cesium from 'cesium'; import * as Cesium from 'cesium';
import CesiumMap from '@/components/CesiumMap/index.vue'; import CesiumMap from '@/components/CesiumMap/index.vue';
import { useEventBus } from '@/components/CesiumMap/mixins/useEventBus'; import { useEventBus, ScreenMode } from '@/components/CesiumMap/mixins/useEventBus';
import Toolbar from './Toolbar'; import Toolbar from './Toolbar';
import DialogPropertyGrid from './DialogPropertyGrid'; import DialogPropertyGrid from './DialogPropertyGrid';
import { setPropertyData } from './DialogPropertyGrid/property'; import { setPropertyData } from './DialogPropertyGrid/property';
@ -38,10 +38,7 @@ const initMap = (v) => {
console.log('地图已初始化', v); console.log('地图已初始化', v);
const bus = useEventBus(viewerRef.value) const bus = useEventBus(viewerRef.value)
// bus.on('hoverTest', ({ screenPosition }) => { // view
// console.log('hoverTest :', screenPosition);
// });
bus.onScreen(Cesium.ScreenSpaceEventType.LEFT_CLICK, ({ position }) => { bus.onScreen(Cesium.ScreenSpaceEventType.LEFT_CLICK, ({ position }) => {
console.log('左键点击屏幕位置:', position); console.log('左键点击屏幕位置:', position);
// //
@ -71,7 +68,7 @@ const initMap = (v) => {
} }
} }
} }
}) }, ScreenMode.VIEW)
}; };
</script> </script>