tcctyn-ui/src/components/CesiumMap/mixins/useDrawTool/drawStraightArrow.js

149 lines
4.7 KiB
JavaScript
Raw Normal View History

import {
Cartesian3,
Entity,
CallbackProperty,
Color as CesiumColor,
ScreenSpaceEventType,
PolygonHierarchy,
HeightReference,
} from 'cesium'
import { createStraightArrowPositions } from './draw/straightArrowGraphic'
/**
* 绘制直箭头的具体逻辑
* @param deps 绘制所需的依赖
* @returns Promise 绘制完成的所有点坐标数组
*/
export const drawStraightArrow = (deps) => {
const { viewer, bus, position, status, registerAbort, globalAbort } = deps
// 如果在执行其它操作,则取消
globalAbort()
status.value = 'Drawing'
const featurePositions = []
// 临时多边形实体 (包含填充和边界线)
const tempPolygon = new Entity({
name: '__draw_temp_straight_arrow',
polygon: {
hierarchy: new CallbackProperty(() => {
const positions = [...featurePositions]
// 添加当前鼠标位置作为最后一个点,形成动态效果
if (
position.value &&
!position.value.equals(featurePositions[featurePositions.length - 1]) // 避免重复添加同一个点
) {
positions.push(position.value)
}
// 直箭头需要2个点形成
if (positions.length < 2) {
return null
}
return new PolygonHierarchy(createStraightArrowPositions(positions))
}, false),
heightReference: HeightReference.CLAMP_TO_GROUND,
material: CesiumColor.fromCssColorString('#ff0000').withAlpha(0.3),
},
// 绘制边界线,连接所有点和第一个点,形成闭合效果
polyline: {
positions: new CallbackProperty(() => {
const positions = [...featurePositions]
// 添加当前鼠标位置作为最后一个点
if (
position.value &&
!position.value.equals(featurePositions[featurePositions.length - 1])
) {
positions.push(position.value)
}
// 直箭头需要2个点形成
if (positions.length < 2) {
return null
}
const pts = createStraightArrowPositions(positions)
return [...pts, pts[0]]
}, false),
// clampToGround: true, // 多边形边界线通常不需要 clampToGround因为多边形本身已经处理了高度
width: 2,
material: CesiumColor.fromCssColorString('#ff0000'),
},
})
viewer.entities.add(tempPolygon)
return new Promise((resolve, reject) => {
// 清理资源
const dispose = () => {
registerAbort(null) // 取消注册当前的 abort 回调
status.value = 'Default'
viewer.entities.remove(tempPolygon)
bus.offScreen(ScreenSpaceEventType.LEFT_CLICK, handleAddPoint)
bus.offScreen(ScreenSpaceEventType.RIGHT_CLICK, handleCancelDraw)
bus.offScreen(ScreenSpaceEventType.LEFT_DOUBLE_CLICK, handleEndDraw)
}
// 取消绘制
const abort = (info) => {
dispose()
reject(info || '取消曲面绘制!')
}
// 左键加点
const handleAddPoint = () => {
// 直箭头最多绘制2个点
if (featurePositions.length >= 2) return
if (position.value && !position.value.equals(featurePositions[featurePositions.length - 1])) {
featurePositions.push(position.value)
// 如果达到2个点自动完成绘制
if (featurePositions.length === 2) {
dispose()
setTimeout(() => {
featurePositions[0] &&
featurePositions[1] &&
resolve([featurePositions[0], featurePositions[1]])
}, 0)
}
}
}
// 左键双击完成绘制
const handleEndDraw = () => {
// 双击时,如果鼠标位置与最后一个点不同,先添加当前点
handleAddPoint()
if (featurePositions.length < 2) {
// TODO: 替换为实际的错误提示方式
console.error('请保证直箭头有2个特征点')
return
}
dispose()
// 使用 setTimeout 避免立即 resolve 可能导致的事件冲突或其他问题
setTimeout(() => {
featurePositions[0] &&
featurePositions[1] &&
resolve([featurePositions[0], featurePositions[1]])
}, 0)
}
// 右键取消绘制或删除最后一个点
const handleCancelDraw = () => {
if (featurePositions.length > 0) {
// 取消最后绘制的点
featurePositions.pop()
} else {
// 如果没有点,则取消整个绘制
abort()
}
}
// 注册当前的取消回调
registerAbort(abort)
// 绑定绘制相关事件
bus.onScreen(ScreenSpaceEventType.LEFT_CLICK, handleAddPoint)
bus.onScreen(ScreenSpaceEventType.RIGHT_CLICK, handleCancelDraw)
bus.onScreen(ScreenSpaceEventType.LEFT_DOUBLE_CLICK, handleEndDraw)
})
}