吉安感知网项目-前端
罗广辉
2026-03-04 b5bbbd19cf0b3c2b7674e5ecb6c1847f0ec734e4
packages/utils/map/DrawPolygon.js
@@ -2,6 +2,7 @@
import * as turf from '@turf/turf'
import { ElMessage } from 'element-plus'
import { flyVisual, getPointPositionsHeight } from './index'
import { MapTooltip } from './MapTooltip'
/**
 * 多边形绘制与编辑工具类
@@ -13,7 +14,10 @@
 *  - 外部订阅/通知机制
 */
export class DrawPolygon {
   constructor() {
   constructor(options = {}) {
      // 设备覆盖范围列表(经纬度 + 5000m半径)
      this.deviceList = options.deviceList || []
      this.coverageRadius = 5000
      // 图斑预览模式标记
      this.isPureSpotPreview = false
      // 是否删除测区
@@ -63,6 +67,8 @@
      this.delPoint = this.delPoint.bind(this)
      // 外部订阅者
      this.listeners = []
      // 绘制提示 tooltip
      this.drawingTooltip = null
   }
   // 实体命名常量
@@ -395,6 +401,19 @@
   handleLeftUp() {
      if (!(this.editingMode && this.curPolygon?.positions && this.draggedEntity)) return
      // 检查松手位置是否在设备覆盖范围内
      if (this.isDragging && !this.isWithinDeviceCoverage(this.curPolygon.positions[this.draggedEntity?.customData.ind])) {
         ElMessage.warning('该位置不在设备覆盖范围内,请在设备5公里范围内绘制')
         // 回弹到拖拽前的位置
         this.draggedEntity.position = this.currentDragPointPosition
         this.curPolygon.positions[this.draggedEntity?.customData.ind] = this.currentDragPointPosition
         this.isDragging = false
         this.draggedEntity = null
         this.enableMapControl()
         this.rebuildMidPoints()
         return
      }
      if (this.currentDragPointIsValid && this.isDragging) {
         // 更新点位置
         this.draggedEntity.position = this.currentDragPointPosition
@@ -430,6 +449,11 @@
      const cartesian = this.viewer.scene.pickPosition(movement.endPosition)
      if (!cartesian) return
      // 更新绘制提示 tooltip 位置
      if (this.drawingMode && this.drawingTooltip) {
         this.drawingTooltip.move(movement.endPosition)
      }
      // 编辑模式下,拖拽点实时更新
      if (this.editingMode && this.draggedEntity?.customData) {
@@ -507,6 +531,12 @@
      const cartesian = this.viewer.scene.pickPosition(click.position)
      if (!cartesian) return
      // 检查点击位置是否在设备覆盖范围内
      if (!this.isWithinDeviceCoverage(cartesian)) {
         ElMessage.warning('该位置不在设备覆盖范围内,请在设备5公里范围内绘制')
         return
      }
      let arr = [...this.curPolygon.positions]
      arr.pop()
      // 校验多边形是否自交
@@ -579,6 +609,11 @@
   finishDrawing() {
      this.curPolygon.positions.pop()
      // 隐藏绘制提示
      if (this.drawingTooltip) {
         this.drawingTooltip.hide()
      }
      if (this.curPolygon.positions.length >= 3) {
         this.drawingMode = false
         this.editingMode = true
@@ -607,6 +642,11 @@
      this.removeMenuPopup()
      this.notify('getPolygonPositions', [])
      this.startDrawing()
      // 重新显示绘制提示
      if (this.drawingTooltip) {
         this.drawingTooltip.show('左键点击绘制,双击结束绘制')
      }
   }
   // 删除图斑
   delSpot() {
@@ -644,7 +684,7 @@
      const menuItems =
         type === 'polygon'
            ? [{ title: '删除测区', class: 'del-planar-polygon' }]
            ? [{ title: '删除范围', class: 'del-planar-polygon' }]
            : [{ title: '删除端点', class: 'del-planar-point' }]
      menuItems.forEach(item => {
@@ -708,6 +748,20 @@
      return intersections.features.length === 0
   }
   // 检查位置是否在任意设备的覆盖范围内(5km)
   isWithinDeviceCoverage(cartesian) {
      if (!this.deviceList || this.deviceList.length === 0) return true
      const cartographic = Cesium.Cartographic.fromCartesian(cartesian)
      const clickPoint = turf.point([Cesium.Math.toDegrees(cartographic.longitude), Cesium.Math.toDegrees(cartographic.latitude)])
      return this.deviceList
         .filter(item => item.latitude)
         .some(item => {
            const rangePoint = turf.point([item.longitude, item.latitude])
            const distance = turf.distance(rangePoint, clickPoint, { units: 'kilometers' })
            return distance <= 5
         })
   }
   // 初始化已有多边形
   async initPolygon(viewer, positions, isPurePreview = false) {
      this.initHandler(viewer)
@@ -760,6 +814,12 @@
      this.viewer = viewer
      this.startDrawing()
      // 初始化绘制提示 tooltip
      if (!this.drawingTooltip) {
         this.drawingTooltip = new MapTooltip(viewer)
         this.drawingTooltip.show('左键点击绘制,双击结束绘制')
      }
      if (!this.handler) {
         this.handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
@@ -807,5 +867,11 @@
      this.removeEntities()
      this.removeHandler()
      this.enableMapControl()
      // 销毁绘制提示 tooltip
      if (this.drawingTooltip) {
         this.drawingTooltip.destroy()
         this.drawingTooltip = null
      }
   }
}