<template>
  <div id="map" ref="map">
    <div class="toolbox">
      <button @click="loadMarker">加载标记</button>
      <button
        :style="{ backgroundColor: isMarking ? '#ff4d4f' : '', color: isMarking ? '#fff' : '' }"
        @click="markPlace"
      >
        {{ isMarking ? '结束标记' : '标记地点' }}
      </button>
      <button
        :style="{ backgroundColor: isDrawingCircle ? '#409EFF' : '', color: isDrawingCircle ? '#fff' : '' }"
        @click="drawCircle"
      >
        {{ isDrawingCircle ? '结束画圆' : '绘制圆形' }}
      </button>
      <button @click="measure('distance')">测距离</button>
      <button @click="measure('area')">测面积</button>
      <button @click="clear">清除</button>
    </div>

    <div ref="radiusOverlayLabel" class="ol-radius-marker" style="display: none;">
      {{ liveRadiusText }}
    </div>
  </div>
</template>

<script>
import 'ol/ol.css'
import Map from 'ol/Map'
import View from 'ol/View'
import { Vector as VectorSource, OSM, XYZ } from 'ol/source'
import { Tile as TileLayer, Vector as VectorLayer } from 'ol/layer'
// Draw 绘制功能几何的交互
import { Draw, Modify } from 'ol/interaction'
import Overlay from 'ol/Overlay'
// 线条几何形状
import { LineString } from 'ol/geom'
// 具有几何和其他属性属性属性的地理特征的矢量对象，类似于像 GeoJSON 这样的矢量文件格式中的特征
import Feature from 'ol/Feature'
import { unByKey } from 'ol/Observable'
// 获取几何形状的球形长度和面积
import { getLength, getArea } from 'ol/sphere'
import Style from 'ol/style/Style'
import Stroke from 'ol/style/Stroke'
import Fill from 'ol/style/Fill'
import Circle from 'ol/style/Circle'
import { fromLonLat, toLonLat } from 'ol/proj'
import Icon from 'ol/style/Icon'
import Point from 'ol/geom/Point'
import Text from 'ol/style/Text'
import { getMapMarks } from '@/api/map'

export default {
  name: 'OpenLayersMap',
  data() {
    return {
      center: [104.068071, 30.576432],
      zoom: 12, // 比例尺 10 公里
      map: null,
      vectorLayer: null,
      vectorSource: null,
      // 标记地点
      isMarking: false,
      clickListenerKey: null,
      // --- 新增：绘制圆形相关变量 ---
      isDrawingCircle: false, // 是否处于画圆状态
      liveRadiusText: '', // 实时半径文字
      radiusOverlay: null, // 存放半径文本的 Overlay 实例
      draw: null,
      select: null,
      modify: null,
      measureType: 'distance',
      tipDiv: null,
      pointermoveEvent: null, // 地图pointermove事件
      sketchFeature: null, // 绘制的要素
      geometryListener: null, // 要素几何change事件
      measureResult: '0', // 测量结果
      markerSource: null // 新增：专门存放后台加载的标记点
    }
  },
  mounted() {
    this.markerSource = new VectorSource({ wrapX: false })
    const markerLayer = new VectorLayer({
      source: this.markerSource,
      name: '后台标记图层'
    })

    // 底图使用 OpenStreetMap, 对应 view
    var baseLayer = new TileLayer({
      source: new OSM()
    })
    // 矢量图层源
    this.vectorSource = new VectorSource({
      wrapX: false
    })
    // 矢量图层
    this.vectorLayer = new VectorLayer({
      source: this.vectorSource
    })

    var url = 'https://webrd04.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}'
    // 切换为高德地图的电子地图底图
    var amapLayer = new TileLayer({
      source: new XYZ({
        // 高德官方切片地址（t1-t4可选，lang=zh_cn代表中文，style=7代表标准地图）
        url: url,
        crossOrigin: 'anonymous',
        maxZoom: 18
      }),
      name: '高德底图'
    })
    /* this.map = new Map({
      layers: [baseLayer, this.vectorLayer, markerLayer],
      target: 'map',
      view: new View({
      projection: 'EPSG:4326',
      center: [104.06531800244139, 30.65852484539117],
      zoom: 10
    })
    })*/

    this.map = new Map({
      layers: [amapLayer, this.vectorLayer, markerLayer], // 替换掉 baseLayer
      target: 'map',
      view: new View({
        projection: 'EPSG:3857', // ⚠️注意：高德切片是墨卡托(3857)投影，建议View也改为3857
        center: fromLonLat(this.center), // 用 fromLonLat 转换中心点
        zoom: 12,
        maxZoom: 18
      })
    })
  },
  created() {
    document.title = 'OpenLayersMap'
  },
  methods: {
    drawCircle() {
      this.isDrawingCircle = !this.isDrawingCircle

      // 清理上一次的组件
      if (this.draw) this.map.removeInteraction(this.draw)
      if (this.modify) this.map.removeInteraction(this.modify)
      if (this.radiusOverlay) this.map.removeOverlay(this.radiusOverlay)

      if (this.isDrawingCircle) {
        this.map.getTargetElement().style.cursor = 'crosshair'

        // 1. 创建半径气泡标签 DOM
        const labelEl = document.createElement('div')
        labelEl.className = 'ol-radius-marker'

        this.radiusOverlay = new Overlay({
          element: labelEl,
          offset: [15, -15],
          positioning: 'bottom-left',
          stopEvent: false
        })
        this.map.addOverlay(this.radiusOverlay)

        // 2. 初始化绘制器
        this.draw = new Draw({
          source: this.vectorSource,
          type: 'Circle'
        })

        let centerFeature = null

        // 3. 监听开始绘制
        this.draw.on('drawstart', (evt) => {
          const geometry = evt.feature.getGeometry()

          // 绘制圆心红点
          const initialCenter = geometry.getCenter()
          centerFeature = new Feature({ geometry: new Point(initialCenter) })
          centerFeature.setStyle(new Style({
            image: new Circle({
              radius: 5,
              fill: new Fill({ color: '#ff4d4f' }),
              stroke: new Stroke({ color: '#ffffff', width: 2 })
            })
          }))
          this.vectorSource.addFeature(centerFeature)

          // 绑定高频拖拽计算半径事件
          const bindGeometryChange = (geom) => {
            geom.on('change', () => {
              const radiusInMeters = geom.getRadius()
              const text = radiusInMeters < 1000 ? `${radiusInMeters.toFixed(1)}m` : `${(radiusInMeters / 1000).toFixed(2)}km`
              labelEl.innerText = text

              // 标签死死跟着圆周上的鼠标/控制点边缘
              const lastCoordinate = geom.getLastCoordinate()
              if (this.radiusOverlay) {
                this.radiusOverlay.setPosition(lastCoordinate)
              }
              // 同步纠正圆心物理位置
              if (centerFeature) centerFeature.getGeometry().setCoordinates(geom.getCenter())
            })
          }

          bindGeometryChange(geometry)
          // 将这个绑定函数挂载到 feature 上，方便后期二次编辑修改时复用
          evt.feature.set('changeBinder', bindGeometryChange)
        })

        // 4. 核心新增：监听绘制结束，立刻无缝移交控制权给 Modify
        this.draw.on('drawend', (evt) => {
          // 移除画圆交互（不让继续画新圆了），但保留图形和标签
          this.map.removeInteraction(this.draw)
          this.map.getTargetElement().style.cursor = 'default'

          const finishedFeature = evt.feature

          // 5. 激活修改交互器（传入指定的图层源）
          this.modify = new Modify({
            source: this.vectorSource
          })
          this.map.addInteraction(this.modify)

          // 6. 当用户再次用鼠标按住圆周边缘控制点拖拽调整时
          this.modify.on('modifystart', (mEvt) => {
            // 重新绑定几何变化监听，让半径气泡文字在拖拽修改时再度跟着动起来！
            mEvt.features.forEach((f) => {
              const geom = f.getGeometry()
              const binder = f.get('changeBinder')
              if (binder) binder(geom)
            })
          })

          this.modify.on('modifyend', () => {
            console.log('圆半径二次调整结束')
          })
        })

        this.map.addInteraction(this.draw)
      } else {
        // 退出状态
        this.map.getTargetElement().style.cursor = ''
      }
    },
    initFeatureClick() {
      this.map.on('singleclick', (evt) => {
        // 核心：如果是地点标记状态，优先允许用户打点，不触发图标点击事件
        if (this.isMarking) return

        // 1. 获取点击处的屏幕像素坐标
        const pixel = this.map.getEventPixel(evt.originalEvent)

        // 2. 探测当前像素点下是否存在 Feature 要素
        const feature = this.map.forEachFeatureAtPixel(pixel, (clickedFeature) => {
          return clickedFeature // 如果有，直接返回这个要素
        })

        // 3. 如果抓到了要素，说明用户点中了某个图标
        if (feature) {
          // 4. 健壮性检查：通过我们在创建要素时注入的 customType 属性，判定它是不是我们要的标记点
          const customType = feature.get('customType')
          if (customType === 'api-marker') {
            const name = feature.get('title')
            const id = feature.get('id')
            this.$message.info(`你点击了后台标记点：${name} (ID: ${id})`)
          } else if (feature.getGeometry() instanceof Point && !customType) {
            // === 处理手动通过 markPlace 打的橙色小圆点点击 ===
            // 因为在 addMarker 里你没有加 customType，但它的几何类型是 Point
            this.$message.info('你点击了手动标记的圆点位置')
            // 示例：点击手动标记点时，可以把它从数据源中删掉
            // this.vectorSource.removeFeature(feature)
          }
        }
      })
    },
    // 加载标记点主方法
    async loadMarker() {
      this.initFeatureClick()
      // 1. 先清除之前加载过的历史标记
      if (this.markerSource) {
        this.markerSource.clear()
      }

      getMapMarks().then(resp => {
        if (resp.code === 0) {
          for (const item of resp.data) {
            const numLng1 = item.lng
            const numLat1 = item.lat
            // 创建要素几何（使用转换后的坐标，如果是高德底图，记得在外面套一层 fromLonLat）
            const finalCoord = fromLonLat([numLng1, numLat1]) // 如果底图是高德请解开这行，下面传入 finalCoord
            const feature = new Feature({
              geometry: new Point(finalCoord),
              customType: 'api-marker',
              ...item
            })

            var text = item.title + '\n[,' + numLng1.toFixed(4) + ' ' + numLat1.toFixed(4) + ']'
            // 设置样式
            feature.setStyle(
              new Style({
                // 1. 图标样式
                image: new Icon({
                  src: 'https://cdn-icons-png.flaticon.com/512/684/684908.png',
                  crossOrigin: 'anonymous',
                  anchor: [0.5, 1], // 锚点在底部尖角，图标整体向上伸展约 36 像素
                  scale: 0.07
                }),

                // 2. 文字样式
                text: new Text({
                  text: text,
                  font: '12px sans-serif',
                  fill: new Fill({ color: '#3a55c2' }),
                  stroke: new Stroke({ color: '#ffffff', width: 3 }),
                  offsetY: -42, // 调大负数！直接把文字推到图标头顶上方（36px 图标高度 + 6px 呼吸间距）
                  textBaseline: 'bottom', // 保持底部对齐，确保多行文本也能整齐向上排列
                  placement: 'point'
                })
              })
            )

            // 添加到数据源
            this.markerSource.addFeature(feature)
            if (this.markerSource && this.markerSource.getFeatures().length > 0) {
              const extent = this.markerSource.getExtent()

              // 安全校验
              if (extent && isFinite(extent[0]) && isFinite(extent[1])) {
                this.map.getView().fit(extent, {
                  padding: [50, 50, 50, 50],
                  maxZoom: 14,
                  duration: 800
                })
              }
            }
          }
        }
      }).catch(error => {
        console.error('加载标记点失败：', error.message)
      })
    },
    // 在地图上标记经纬度
    addMarker(coordinate) {
      // 经度(保留6位小数)
      const lng = coordinate[0].toFixed(6)
      // 纬度(保留6位小数)
      const lat = coordinate[1].toFixed(6)
      /* const lng = Number(lngStr)
      const lat = Number(latStr)*/

      // 1. 创建一个点几何
      const pointGeom = new Point([lng, lat])

      // 2. 创建一个要素（Feature），并将几何图形赋予它
      const markerFeature = new Feature({
        geometry: pointGeom
      })

      const lonLat = toLonLat(coordinate)
      const lng1 = lonLat[0].toFixed(6)
      const lat1 = lonLat[1].toFixed(6)
      // 格式化需要显示的文字（保留6位小数）
      const textLabel = `[${lng1}, ${lat1}]`

      // 3. 设置标记的样式（这里画一个实心圆，你也可以用 Icon 贴图）
      markerFeature.setStyle(
        new Style({
          text: new Text({
            text: textLabel, // 要显示的文字内容
            font: '12px sans-serif', // 字体大小和家族
            fill: new Fill({ color: '#333333' }), // 文字颜色
            stroke: new Stroke({ color: '#ffffff', width: 3 }), // 文字白边背景（防瞎，更清晰）
            offsetY: -12, // 改为负数，将文字向上推 12 像素
            textBaseline: 'bottom', // 文本基线设为底部，确保文字的屁股对齐偏移位置，不会压到圆点
            placement: 'point' // 渲染类型
          }),
          image: new Circle({
            radius: 4, // 圆半径
            fill: new Fill({ color: '#ff7300' }), // 填充红色
            stroke: new Stroke({ color: '#ffffff', width: 2 }) // 白色外边框
          })
        })
      )

      // 4. 将这个要素添加到你现有的矢量图层源中
      // 注意：这里建议先清除之前的标记，或者你可以专门建一个标记图层
      this.vectorSource.addFeature(markerFeature)

      // 5. 动画平移让地图中心对准这个标记点
      /* this.map.getView().animate({
        center: [lng, lat],
        duration: 800, // 动画持续时间（毫秒）
        zoom: 14 // 顺便放大地图级别
      })*/
    },
    creatDraw(type) {
      let maxPoints = null
      if (this.measureType === 'angle') maxPoints = 3
      else maxPoints = null

      // 矢量图层源
      const vectorSource = new VectorSource({
        wrapX: false
      })
      // 矢量图层
      this.vectorLayer = new VectorLayer({
        source: vectorSource,
        style: new Style({
          fill: new Fill({
            color: 'rgba(252, 86, 49, 0.1)'
          }),
          stroke: new Stroke({
            color: '#fc5531',
            width: 3
          }),
          image: new Circle({
            radius: 0,
            fill: new Fill({
              color: '#fc5531'
            })
          })
        }),
        name: '测量图层'
      })
      this.map.addLayer(this.vectorLayer)
      this.draw = new Draw({
        source: vectorSource,
        type: type,
        maxPoints: maxPoints,
        style: new Style({
          fill: new Fill({
            color: 'rgba(252, 86, 49, 0.1)'
          }),
          stroke: new Stroke({
            color: '#fc5531',
            lineDash: [10, 10],
            width: 3
          }),
          image: new Circle({
            radius: 0,
            fill: new Fill({
              color: '#fc5531'
            })
          })
        }),
        // 绘制时点击处理事件
        condition: (evt) => {
          // 测距时添加点标注
          if (this.measureResult !== '0' && !this.map.getOverlayById(this.measureResult) && this.measureType === 'distance') {
            this.creatMark(
              null,
              this.measureResult,
              this.measureResult
            ).setPosition(evt.coordinate)
          }
          return true
        }
      })
      this.map.addInteraction(this.draw)

      /**
       * 绘制开始事件
       */
      this.draw.on('drawstart', (e) => {
        this.sketchFeature = e.feature
        const proj = this.map.getView().getProjection()
        //* *****距离测量开始时*****//
        if (this.measureType === 'distance') {
          this.creatMark(null, '起点', 'start').setPosition(
            this.map.getCoordinateFromPixel(e.target.downPx_)
          )
          this.tipDiv.innerHTML = '总长：0 m</br>单击确定地点，双击结束'
          this.geometryListener = this.sketchFeature
            .getGeometry()
            .on('change', (evt) => {
              this.measureResult = this.distanceFormat(
                getLength(evt.target, { projection: proj, radius: 6378137 })
              )
              this.tipDiv.innerHTML =
                '总长：' + this.measureResult + '</br>单击确定地点，双击结束'
            })
        } else if (this.measureType === 'area') {
          //* *****面积测量开始时*****//
          this.tipDiv.innerHTML = '面积：0 m<sup>2</sup></br>继续单击确定地点'
          this.geometryListener = this.sketchFeature
            .getGeometry()
            .on('change', (evt) => {
              if (evt.target.getCoordinates()[0].length < 4) {
                this.tipDiv.innerHTML =
                  '面积：0m<sup>2</sup></br>继续单击确定地点'
              } else {
                this.measureResult = this.formatArea(
                  getArea(evt.target, { projection: proj, radius: 6378137 })
                )
                this.tipDiv.innerHTML =
                  '面积：' + this.measureResult + '</br>单击确定地点，双击结束'
              }
            })
        } else if (this.measureType === 'angle') {
          //* *****角度测量开始时*****//
          this.tipDiv.innerHTML = '继续单击确定顶点'
          this.geometryListener = this.sketchFeature
            .getGeometry()
            .on('change', (evt) => {
              if (evt.target.getCoordinates().length < 3) { this.tipDiv.innerHTML = '继续单击确定顶点' } else {
                this.measureResult = this.formatAngle(evt.target)
                this.tipDiv.innerHTML =
                  '角度：' + this.measureResult + '</br>继续单击结束'
              }
            })
        }
      })

      /**
       * 绘制开始事件
       */
      this.draw.on('drawend', (e) => {
        const closeBtn = document.createElement('span')
        closeBtn.innerHTML = '×'
        closeBtn.title = '清除测量'
        closeBtn.style =
          'width: 10px;height:10px;line-height: 12px;text-align: center;border-radius: 5px;display: inline-block;padding: 2px;color: rgb(255, 68, 0);border: 2px solid rgb(255, 68, 0);background-color: rgb(255, 255, 255);font-weight: 600;position: absolute;top: -25px;right: -2px;cursor: pointer;'
        closeBtn.addEventListener('click', () => {
          this.clearMeasure()
        })
        //* *****距离测量结束时*****//
        if (this.measureType === 'distance') {
          this.creatMark(closeBtn, null, 'close1').setPosition(
            e.feature.getGeometry().getLastCoordinate()
          )
          this.creatMark(
            null,
            '总长：' + this.measureResult + '',
            'length'
          ).setPosition(e.feature.getGeometry().getLastCoordinate())
          this.map.removeOverlay(this.map.getOverlayById(this.measureResult))
        } else if (this.measureType === 'area') {
          //* *****面积测量结束时*****//
          this.creatMark(closeBtn, null, 'close2').setPosition(
            e.feature.getGeometry().getInteriorPoint().getCoordinates()
          )
          this.creatMark(
            null,
            '总面积：' + this.measureResult + '',
            'area'
          ).setPosition(
            e.feature.getGeometry().getInteriorPoint().getCoordinates()
          )
        } else if (this.measureType === 'angle') {
          //* *****角度测量结束时*****//
          this.creatMark(closeBtn, null, 'close3').setPosition(
            e.feature.getGeometry().getCoordinates()[1]
          )
          this.creatMark(
            null,
            '角度：' + this.measureResult + '',
            'angle'
          ).setPosition(e.feature.getGeometry().getCoordinates()[1])
        }
        // 停止测量
        this.stopMeasure()
      })
    },
    markPlace() {
      // 切换状态
      this.isMarking = !this.isMarking

      if (this.isMarking) {
        // 1. 改变鼠标指针为十字准星
        this.map.getTargetElement().style.cursor = 'crosshair'
        // 2. 定义点击时的执行函数
        const handleMapClick = (evt) => {
          // 获取点击位置的原始墨卡托坐标(高德地图) [米, 米]
          // evt.coordinate 是一个数组：[lng, lat]
          const coordinate = evt.coordinate
          this.addMarker(coordinate)
        }

        // 3. 绑定持久点击事件，并把返回的 key 存起来以便后续解绑
        this.clickListenerKey = this.map.on('singleclick', handleMapClick)
      } else {
        // ================= 退出标记地点状态 =================
        // 1. 恢复默认鼠标指针
        this.map.getTargetElement().style.cursor = ''

        // 2. 核心：解除绑定的点击事件，让地图恢复正常
        if (this.clickListenerKey) {
          // OpenLayers 6+ 中解绑事件的方式：使用 ol/Observable 的 unByKey 或者直接传入 key
          // 如果你的版本支持, 可以直接使用下面的标准方法：
          this.map.un('singleclick', this.clickListenerKey.listener)
          this.clickListenerKey = null
        }
      }
    },
    /**
     * 测量
     */
    measure(type) {
      if (this.draw !== null) return false // 防止在绘制过程再创建测量
      this.measureType = type
      if (this.vectorLayer !== null) this.clearMeasure()
      this.tipDiv = document.createElement('div')
      this.tipDiv.innerHTML = '单击确定起点'
      this.tipDiv.className = 'tipDiv'
      this.tipDiv.style = 'width:auto;height:auto;padding:4px;border:1px solid #fc5531;font-size:12px;background-color:#fff;position:relative;top:60%;left:60%;font-weight:600;'
      const overlay = new Overlay({
        element: this.tipDiv,
        autoPan: false,
        positioning: 'bottom-center',
        id: 'tipLay',
        stopEvent: false // 停止事件传播到地图
      })
      this.map.addOverlay(overlay)

      this.pointermoveEvent = this.map.on('pointermove', (evt) => {
        overlay.setPosition(evt.coordinate)
      })
      if (this.measureType === 'distance' || this.measureType === 'angle') {
        this.creatDraw('LineString')
      } else if (this.measureType === 'area') {
        this.creatDraw('Polygon')
      }
    },
    /**
     * 创建标记
     */
    creatMark(markDom, txt, idstr) {
      if (markDom === null) {
        markDom = document.createElement('div')
        markDom.innerHTML = txt
        markDom.style =
          'width:auto;height:auto;padding:4px;border:1px solid #fc5531;font-size:12px;background-color:#fff;position:relative;top:60%;left:60%;font-weight:600;'
      }
      const overlay = new Overlay({
        element: markDom,
        autoPan: false,
        positioning: 'bottom-center',
        id: idstr,
        stopEvent: false
      })
      this.map.addOverlay(overlay)
      return overlay
    },
    /**
     * 格式化距离结果输出
     */
    distanceFormat(length) {
      let output
      if (length > 100) {
        output = Math.round((length / 1000) * 100) / 100 + ' ' + 'km' // 换算成km单位
      } else {
        output = Math.round(length * 100) / 100 + ' ' + 'm' // m为单位
      }
      return output // 返回线的长度
    },
    /**
     * 格式化面积输出
     */
    formatArea(area) {
      let output
      if (area > 10000) {
        output =
          Math.round((area / 1000000) * 100) / 100 + ' ' + 'km<sup>2</sup>' // 换算成km单位
      } else {
        output = Math.round(area * 100) / 100 + ' ' + 'm<sup>2</sup>' // m为单位
      }
      return output // 返回多边形的面积
    },
    /**
     * 计算角度输出
     */
    formatAngle(line) {
      var coordinates = line.getCoordinates()
      var angle = '0°'
      if (coordinates.length === 3) {
        const disa = getLength(
          new Feature({
            geometry: new LineString([coordinates[0], coordinates[1]])
          }).getGeometry(),
          {
            radius: 6378137,
            projection: this.map.getView().getProjection()
          }
        )

        const disb = getLength(
          new Feature({
            geometry: new LineString([coordinates[1], coordinates[2]])
          }).getGeometry(),
          {
            radius: 6378137,
            projection: this.map.getView().getProjection()
          }
        )

        const disc = getLength(
          new Feature({
            geometry: new LineString([coordinates[0], coordinates[2]])
          }).getGeometry(),
          {
            radius: 6378137,
            projection: this.map.getView().getProjection()
          }
        )
        var cos = (disa * disa + disb * disb - disc * disc) / (2 * disa * disb) // 计算cos值
        angle = (Math.acos(cos) * 180) / Math.PI // 角度值
        angle = angle.toFixed(2) // 结果保留两位小数
      }
      if (isNaN(angle)) return '0°'
      else return angle + '°' // 返回角度
    },
    /**
     * 停止测量
     */
    stopMeasure() {
      this.tipDiv = null
      this.map.removeInteraction(this.draw) // 移除绘制组件
      this.draw = null
      this.map.removeOverlay(this.map.getOverlayById('tipLay')) // 移除动态提示框
    },
    /**
     * 清除测量
     */
    clearMeasure() {
      this.vectorLayer.getSource().clear()
      this.map.getOverlays().clear()
      // 移除监听事件
      unByKey(this.pointermoveEvent) // 清除鼠标在地图的pointermove事件
      unByKey(this.geometryListener) // 清除绘制图像change事件
      this.pointermoveEvent = null
      this.geometryListener = null
      this.measureResult = '0'
    },
    // 坐标
    single() {
      this.map.on('singleclick', function(e) {
        console.log(e.coordinate)
      })
    },
    // 清除
    clear() {
      // 清空测量矢量图层
      if (this.vectorLayer) this.vectorLayer.getSource().clear()
      // 清空后台加载的标记图层
      if (this.markerSource) this.markerSource.clear()
      // 清空所有弹窗 Overlay
      this.map.getOverlays().clear()
    }
  }
}
</script>

<style scoped>
#map {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
}

/* 右上角工具箱容器 */
.toolbox {
  position: absolute;
  z-index: 999;
  top: 20px;          /* 距离顶部 20px */
  right: 20px;        /* 距离右侧 20px */
  background: rgba(255, 255, 255, 0.9); /* 半透明白底背景 */
  padding: 8px;
  border-radius: 6px; /* 圆角 */
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.15); /* 地图控件常用的阴影 */

  display: grid;
  grid-template-columns: repeat(2, 75px); /* 固定为两列，每列宽 75px */
  gap: 6px;           /* 按钮之间的间距 */
}

/* 工具箱内的按钮通用样式 */
.toolbox button {
  height: 28px;
  border: 1px solid #dcdfe6;
  background-color: #fff;
  color: #606266;
  font-size: 12px;
  border-radius: 4px;
  cursor: pointer;
  transition: all 0.2s;
  padding: 0 4px;
}

/* 鼠标悬浮和点击效果 */
.toolbox button:hover {
  color: #fc5531;
  border-color: #fc5531;
  background-color: rgba(252, 86, 49, 0.05);
}

/* 实时跟随鼠标的半径标签气泡样式 */
.ol-radius-marker {
  background: rgba(64, 158, 255, 0.95); /* 漂亮的科技蓝 */
  color: #ffffff;
  padding: 4px 8px;
  border-radius: 4px;
  font-size: 11px;
  font-weight: bold;
  white-space: nowrap;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
  border: 1px solid #ffffff;
  position: relative;
  pointer-events: none; /* 极其重要：确保 DOM 穿透，否则会挡住鼠标导致无法继续绘制 */
}

/* 气泡下方的微型小尖角 */
.ol-radius-marker::after {
  content: "";
  position: absolute;
  bottom: -4px;
  left: 10px;
  border-width: 4px 4px 0;
  border-style: solid;
  border-color: rgba(64, 158, 255, 0.95) transparent;
}
</style>
