高德地图绘制工具全解析:线路、矩形、圆形、多边形绘制与编辑指南 🗺️✏️

1,244 阅读9分钟

引言 🌟

在现代WebGIS开发中,地图绘制功能是许多应用的核心需求。本文将基于Vue和高德地图(AMap)API,详细解析四种常见图形(线路、矩形、圆形、多边形)的绘制与编辑实现方案,并加入丰富的可视化元素,帮助开发者快速掌握地图绘制技术。

一、线路绘制与编辑 🛣️

image.png

image.png

1. 线路绘制实现

核心代码

drawPolyline() {
  this.mouseTool.polyline({
    strokeColor: '#3366FF',
    strokeOpacity: 1,
    strokeWeight: 6,
    strokeStyle: 'solid',
    strokeDasharray: [10, 5]
  });
}

实现要点

  1. 🖱️ 使用AMap.MouseToolpolyline方法
  2. 🎨 可配置线条颜色、透明度、宽度等样式
  3. ➖ 支持虚线样式(通过strokeDasharray

计算长度

// 📏 计算线路总长度
const path = overlay.getPath();
let distance = 0;
for (let i = 0; i < path.length - 1; i++) {
  distance += path[i].distance(path[i + 1]);
}

2. 线路编辑功能

编辑实现

javascript

if (this.currentOverlay instanceof AMap.Polyline) {
  this.currentEditor = new AMap.PolyEditor(this.map, this.currentOverlay);
  this.currentEditor.open();
  // ✨ 提示用户进入编辑模式
  this.$message.success('已进入线路编辑模式,可拖动节点调整');
}

编辑特性

  • 🔴 可拖动节点调整线路形状
  • ➕ 可在线段上添加新节点
  • 🔄 实时更新线路长度计算

二、矩形绘制与编辑 🟦

image.png

image.png

1. 矩形绘制实现

核心代码

drawRectangle() {
  this.mouseTool.rectangle({
    strokeColor: '#FF33FF',
    strokeOpacity: 1,
    strokeWeight: 4,
    fillColor: '#1791fc',
    fillOpacity: 0.4,
    strokeStyle: 'solid'
  });
}

实现要点

  1. ↔️ 通过拖拽确定矩形对角点
  2. 🎨 可自定义边框和填充样式
  3. 📊 自动计算面积和周长

几何计算

// 📐 计算矩形几何属性
const bounds = overlay.getBounds();
const sw = bounds.getSouthWest();
const ne = bounds.getNorthEast();
const width = sw.distance(new AMap.LngLat(ne.lng, sw.lat));
const height = sw.distance(new AMap.LngLat(sw.lng, ne.lat));
const area = width * height;  // 面积
const perimeter = (width + height) * 2;  // 周长

2. 矩形编辑功能

编辑实现

if (this.currentOverlay instanceof AMap.Rectangle) {
  this.currentEditor = new AMap.RectangleEditor(this.map, this.currentOverlay);
  this.currentEditor.open();
  // 🔄 监听编辑事件
  this.currentEditor.on('adjust', this.updateRectangleInfo);
}

编辑特性

  • ↕️ 拖动边线调整矩形大小
  • ⏹️ 拖动角点同时调整宽度和高度
  • 📈 实时更新面积和周长计算

三、圆形绘制与编辑 ⭕

image.png

image.png

1. 圆形绘制实现

核心代码

drawCircle() {
  this.mouseTool.circle({
    strokeColor: '#FF33FF',
    strokeOpacity: 1,
    strokeWeight: 4,
    fillColor: '#1791fc',
    fillOpacity: 0.4,
    strokeStyle: 'solid'
  });
}

实现要点

  1. 🎯 点击确定圆心,拖拽确定半径
  2. 🌈 支持自定义边框和填充样式
  3. 🔢 自动计算半径、面积和周长

几何计算

// 🔵 圆形几何计算
const radius = overlay.getRadius();
const area = Math.PI * radius * radius;  // 面积
const perimeter = 2 * Math.PI * radius;  // 周长

2. 圆形编辑功能

编辑实现

if (this.currentOverlay instanceof AMap.Circle) {
  this.currentEditor = new AMap.CircleEditor(this.map, this.currentOverlay);
  this.currentEditor.open();
  // 🎛️ 添加编辑控制点
  this.addEditControlPoints();
}

编辑特性

  • 🔘 拖动边缘控制点调整半径
  • 🏗️ 拖动圆心改变位置
  • 📏 实时更新几何属性计算

四、多边形绘制与编辑 🔷

image.png

image.png

1. 多边形绘制实现

核心代码

drawPolygon() {
  this.mouseTool.polygon({
    strokeColor: '#FF33FF',
    strokeOpacity: 1,
    strokeWeight: 4,
    fillColor: '#1791fc',
    fillOpacity: 0.4,
    strokeStyle: 'solid'
  });
}

实现要点

  1. ✏️ 连续点击添加顶点,双击结束绘制
  2. 🧩 支持复杂多边形绘制
  3. 📐 自动计算面积和周长

几何计算

// 📏 多边形几何计算
const area = overlay.getArea();  // 内置面积计算方法
const path = overlay.getPath();
let perimeter = 0;
for (let i = 0; i < path.length; i++) {
  const j = (i + 1) % path.length;
  perimeter += path[i].distance(path[j]);  // 计算周长
}

2. 多边形编辑功能

编辑实现

if (this.currentOverlay instanceof AMap.Polygon) {
  this.currentEditor = new AMap.PolyEditor(this.map, this.currentOverlay);
  this.currentEditor.open();
  // 🖇️ 添加顶点编辑事件
  this.setupVertexEvents();
}

编辑特性

  • 🔘 可拖动现有顶点调整形状
  • ➕ 可在边上添加新顶点
  • ❌ 支持删除顶点
  • 🔄 实时更新几何属性计算

五、通用功能实现 ⚙️

1. 图形选择与删除

enableDelete() {
  if (this.currentOverlay) {
    this.map.remove(this.currentOverlay);
    // 🗑️ 从数组中移除...
    this.currentOverlay = null;
    this.$message.warning('图形已删除', { icon: '🗑️' });
  }
}

2. 图形信息展示

calculateOverlayInfo(overlay) {
  const info = { type: '未知' };
  // 📊 根据不同类型计算...
  this.overlayInfo = info;
  // 💬 显示信息面板
  this.showInfoPanel = true;

六、常见问题解决 ❓

  • 问题1:绘制时出现卡顿

    • 🔧 解决方案:检查是否有频繁的状态更新操作
  • 问题2:编辑时图形闪烁

    • 🔧 解决方案:确保编辑器实例正确管理

结语 🎯

本文详细解析了四种常见地图图形的绘制与编辑实现方案,并加入了丰富的可视化元素。掌握这些技术后,开发者可以轻松实现各种地图标注、区域划分和路径规划功能。高德地图API提供了丰富的接口,结合Vue的响应式特性,能够构建出功能强大且用户体验良好的地图应用。

完整代码示例

  <div class="container">
    <!-- 顶部工具栏 -->
    <div class="toolbar">
      <div class="left-tools">
        <el-radio-group v-model="radio" size="medium" @change="handleRadioChange">
          <el-radio-button label="0">拖动地图</el-radio-button>
          <el-radio-button label="1">绘制线路</el-radio-button>
          <el-radio-button label="2">矩形区域</el-radio-button>
          <el-radio-button label="3">圆形区域</el-radio-button>
          <el-radio-button label="4">多边形区域</el-radio-button>
          <el-radio-button label="5" v-if="currentOverlay">编辑</el-radio-button>
          <el-radio-button label="6" v-if="currentOverlay">删除</el-radio-button>
        </el-radio-group>
      </div>

      <div class="right-tools">
        <el-button size="small" @click="toggleSearch" :type="showSearch ? 'primary' : ''">
          <i class="el-icon-search"></i>
          搜索
        </el-button>

        <el-button size="small" @click="clearAll">
          <i class="el-icon-delete"></i>
          清空
        </el-button>
        <el-button size="small" @click="toggleFullscreen">
          <i class="el-icon-full-screen"></i>
          全屏
        </el-button>
      </div>
    </div>

    <!-- 搜索面板 -->
    <div v-if="showSearch" class="search-panel">
      <el-input
        v-model="searchKeyword"
        placeholder="请输入地址、POI或坐标"
        size="small"
        @keyup.enter.native="searchLocation"
        clearable
      >
        <el-button slot="append" @click="searchLocation" :loading="searchLoading">
          <i class="el-icon-search"></i>
        </el-button>
      </el-input>
      <div v-if="searchResults.length > 0" class="search-results">
        <div
          v-for="(item, index) in searchResults"
          :key="index"
          class="search-item"
          @click="selectSearchResult(item)"
        >
          <div class="item-name">{{ item.name }}</div>
          <div class="item-address">{{ item.address }}</div>
          <div class="item-distance" v-if="item.distance">{{ item.distance }}米</div>
        </div>
      </div>
    </div>

    <!-- 坐标信息显示 -->
    <div class="coordinate-info">
      <div class="coord-item">
        <span class="label">经度:</span>
        <span class="value">{{ coordinates.lng }}</span>
      </div>
      <div class="coord-item">
        <span class="label">纬度:</span>
        <span class="value">{{ coordinates.lat }}</span>
      </div>
      <div class="coord-item">
        <span class="label">缩放:</span>
        <span class="value">{{ zoomLevel }}</span>
      </div>
    </div>

    <!-- 覆盖物信息面板 -->
    <div v-if="overlayInfo" class="overlay-info">
      <h4>
        <i class="el-icon-location-information"></i>
        图形信息
        <el-button type="text" size="mini" @click="overlayInfo = null" style="float: right">
          <i class="el-icon-close"></i>
        </el-button>
      </h4>
      <div class="info-content">
        <p>
          <strong>类型:</strong>
          {{ overlayInfo.type }}
        </p>
        <p v-if="overlayInfo.area">
          <strong>面积:</strong>
          {{ overlayInfo.area }} 平方米
        </p>
        <p v-if="overlayInfo.perimeter">
          <strong>周长:</strong>
          {{ overlayInfo.perimeter }} 米
        </p>
        <p v-if="overlayInfo.radius">
          <strong>半径:</strong>
          {{ overlayInfo.radius }} 米
        </p>
        <p v-if="overlayInfo.distance">
          <strong>长度:</strong>
          {{ overlayInfo.distance }} 米
        </p>
      </div>
    </div>

    <div id="map-container"></div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      // 输入框内容(暂未使用)
      tipinput: '',
      // 高德地图实例
      map: null,
      // 加载状态
      loading: false,
      // 当前选中的绘制模式:'0'-拖动, '1'-线路, '2'-矩形, '3'-圆形, '4'-多边形, '5'-编辑, '6'-删除
      radio: '0',
      // 高德地图鼠标绘制工具
      mouseTool: null,
      // 地图是否已完全加载
      mapLoaded: false,
      // 当前选中的覆盖物(图形)
      currentOverlay: null,

      // 面板显示控制
      showSearch: false, // 是否显示搜索面板

      // 搜索功能相关
      searchKeyword: '', // 搜索关键词
      searchResults: [], // 搜索结果列表
      searchLoading: false, // 搜索加载状态
      placeSearch: null, // 高德地图地点搜索服务
      geocoder: null, // 高德地图地理编码服务

      // 坐标和地图状态信息
      coordinates: { lng: '0.000000', lat: '0.000000' }, // 当前鼠标位置坐标
      zoomLevel: 16, // 地图缩放级别

      // 覆盖物(绘制图形)管理
      overlays: [], // 所有绘制的图形列表
      overlayInfo: null, // 当前选中图形的详细信息
      currentEditor: null // 当前图形编辑器实例
    }
  },
  /**
   * 组件挂载完成后的钩子函数
   * 在DOM更新后初始化地图
   */
  mounted() {
    this.$nextTick(() => {
      this.initMap()
    })
  },

  methods: {
    /**
     * 初始化高德地图
     * 创建地图实例并设置基本配置
     */
    initMap() {
      // 检查高德地图API是否已加载
      if (!window.AMap) {
        console.error('高德地图JS API未加载')
        return
      }

      // 创建地图实例
      this.map = new AMap.Map('map-container', {
        center: [103.88282046118024, 36.05405912292153], // 地图中心点坐标
        zoom: 16, // 地图缩放级别
        mapStyle: 'amap://styles/normal', // 地图样式
        features: ['bg', 'road', 'building', 'point'] // 地图显示要素
      })

      // 等待地图完全加载完成
      this.map.on('complete', () => {
        this.initPlugins() // 初始化插件
        this.initEvents() // 初始化事件监听
        this.mapLoaded = true // 标记地图加载完成
        console.log('地图和工具初始化完成')
      })
    },

    /**
     * 初始化高德地图插件
     * 加载绘制、编辑、搜索等功能插件
     */
    initPlugins() {
      AMap.plugin(
        [
          'AMap.MouseTool', // 鼠标绘制工具
          'AMap.PolyEditor', // 折线和多边形编辑器
          'AMap.CircleEditor', // 圆形编辑器
          'AMap.RectangleEditor', // 矩形编辑器
          'AMap.PlaceSearch', // 地点搜索服务
          'AMap.Geocoder' // 地理编码服务
        ],
        () => {
          // 初始化鼠标绘制工具
          this.mouseTool = new AMap.MouseTool(this.map)

          // 初始化地点搜索服务
          this.placeSearch = new AMap.PlaceSearch({
            pageSize: 10, // 每页显示结果数量
            pageIndex: 1, // 页码
            city: '全国' // 搜索范围
          })

          // 初始化地理编码服务(坐标转地址)
          this.geocoder = new AMap.Geocoder({
            radius: 1000, // 搜索半径
            extensions: 'all' // 返回详细信息
          })
        }
      )
    },

    /**
     * 初始化地图事件监听
     * 监听鼠标移动、地图缩放、点击等事件
     */
    initEvents() {
      // 监听鼠标移动,实时显示坐标
      this.map.on('mousemove', (e) => {
        this.coordinates.lng = e.lnglat.getLng().toFixed(6)
        this.coordinates.lat = e.lnglat.getLat().toFixed(6)
      })

      // 监听地图缩放级别变化
      this.map.on('zoomchange', () => {
        this.zoomLevel = this.map.getZoom()
      })

      // 监听地图点击事件
      this.map.on('click', (e) => {
        // 拖动模式下点击获取位置信息
        if (this.radio === '0') {
          this.getLocationInfo(e.lnglat)
        }
      })
    },

    /**
     * 切换搜索面板显示状态
     */
    toggleSearch() {
      this.showSearch = !this.showSearch
    },

    /**
     * 切换全屏模式
     * 进入或退出浏览器全屏状态
     */
    toggleFullscreen() {
      const element = document.documentElement
      if (!document.fullscreenElement) {
        // 进入全屏
        element.requestFullscreen().then(() => {
          this.$message.success('已进入全屏模式')
        })
      } else {
        // 退出全屏
        document.exitFullscreen().then(() => {
          this.$message.success('已退出全屏模式')
        })
      }
    },

    /**
     * 执行地点搜索
     * 根据关键词搜索相关地点并显示结果
     */
    searchLocation() {
      // 检查搜索关键词是否为空
      if (!this.searchKeyword.trim()) {
        this.$message.warning('请输入搜索关键词')
        return
      }

      this.searchLoading = true
      // 调用高德地图搜索服务
      this.placeSearch.search(this.searchKeyword, (status, result) => {
        this.searchLoading = false
        if (status === 'complete' && result.poiList && result.poiList.pois.length > 0) {
          // 处理搜索结果,提取需要的字段
          this.searchResults = result.poiList.pois.map((poi) => ({
            name: poi.name, // 地点名称
            address: poi.address || poi.district + poi.address, // 地址
            location: poi.location, // 坐标位置
            distance: poi.distance ? Math.round(poi.distance) : null // 距离(米)
          }))
        } else {
          this.$message.warning('未找到相关位置')
          this.searchResults = []
        }
      })
    },

    /**
     * 选择搜索结果
     * 定位到选中的地点并添加标记
     * @param {Object} item 选中的搜索结果项
     */
    selectSearchResult(item) {
      const lnglat = [item.location.lng, item.location.lat]
      // 设置地图中心到选中位置
      this.map.setCenter(lnglat)
      this.map.setZoom(16)

      // 在选中位置添加标记点
      const marker = new AMap.Marker({
        position: lnglat,
        title: item.name,
        icon: new AMap.Icon({
          size: new AMap.Size(25, 34),
          image: 'https://webapi.amap.com/theme/v1.3/markers/n/mark_b.png'
        })
      })
      this.map.add(marker)

      // 清理搜索状态
      this.searchResults = []
      this.searchKeyword = ''
      this.showSearch = false

      this.$message.success(`已定位到: ${item.name}`)
    },

    /**
     * 获取指定坐标的位置信息
     * 通过逆地理编码获取地址信息并显示
     * @param {AMap.LngLat} lnglat 坐标点
     */
    getLocationInfo(lnglat) {
      this.geocoder.getAddress(lnglat, (status, result) => {
        if (status === 'complete' && result.regeocode) {
          this.$message.info(result.regeocode.formattedAddress)
        }
      })
    },

    /**
     * 清空地图上的所有内容
     * 清除所有绘制的图形、标记和编辑状态
     */
    clearAll() {
      this.map.clearMap() // 清空地图上所有内容
      this.overlays = [] // 清空覆盖物数组
      this.currentOverlay = null // 清空当前选中的覆盖物
      this.overlayInfo = null // 清空覆盖物信息
      this.radio = '0' // 重置为拖动模式
      // 关闭当前编辑器
      if (this.currentEditor) {
        this.currentEditor.close()
        this.currentEditor = null
      }
      this.$message.success('已清空所有内容')
    },

    /**
     * 处理绘制模式切换
     * 根据选择的模式执行相应的绘制或编辑操作
     * @param {string} val 选择的模式值
     */
    handleRadioChange(val) {
      // 检查地图是否已加载完成
      if (!this.mapLoaded) {
        this.$message.warning('地图正在加载,请稍后再试')
        this.radio = '0'
        return
      }

      // 关闭当前的绘制工具和编辑器
      if (this.mouseTool) {
        this.mouseTool.close()
      }
      if (this.currentEditor) {
        this.currentEditor.close()
        this.currentEditor = null
      }

      // 根据选择的模式执行相应操作
      switch (val) {
        case '0': // 拖动地图模式
          this.map.setDefaultCursor('pointer')
          break
        case '1': // 绘制线路
          this.drawPolyline()
          break
        case '2': // 绘制矩形
          this.drawRectangle()
          break
        case '3': // 绘制圆形
          this.drawCircle()
          break
        case '4': // 绘制多边形
          this.drawPolygon()
          break
        case '5': // 编辑模式
          this.enableEdit()
          break
        case '6': // 删除模式
          this.enableDelete()
          break
      }
    },

    /**
     * 设置绘图完成后的回调事件
     * 为鼠标绘制工具添加绘制完成的事件监听
     */
    setupDrawingEvents() {
      // 确保事件只绑定一次
      if (!this._drawEventBound) {
        this.mouseTool.on('draw', (e) => {
          // 清除之前选中的覆盖物
          this.clearCurrentOverlay()
          // 设置当前覆盖物为新绘制的图形
          this.currentOverlay = e.obj
          // 将新图形添加到覆盖物数组
          this.overlays.push(e.obj)

          // 计算并显示图形信息
          this.calculateOverlayInfo(e.obj)

          // 为新绘制的图形添加点击事件
          e.obj.on('click', () => {
            this.currentOverlay = e.obj
            this.calculateOverlayInfo(e.obj)
          })

          console.log('绘制完成:', e.obj)
        })

        this._drawEventBound = true // 标记事件已绑定
      }
    },

    /**
     * 计算覆盖物的几何信息
     * 根据不同类型的图形计算面积、周长、半径等信息
     * @param {AMap.Overlay} overlay 要计算的覆盖物对象
     */
    calculateOverlayInfo(overlay) {
      const info = { type: '未知' }

      if (overlay instanceof AMap.Polyline) {
        // 折线:计算总长度
        info.type = '线路'
        const path = overlay.getPath()
        let distance = 0
        for (let i = 0; i < path.length - 1; i++) {
          distance += path[i].distance(path[i + 1])
        }
        info.distance = Math.round(distance)
      } else if (overlay instanceof AMap.Rectangle) {
        // 矩形:计算面积和周长
        info.type = '矩形'
        const bounds = overlay.getBounds()
        const sw = bounds.getSouthWest()
        const ne = bounds.getNorthEast()
        const width = sw.distance(new AMap.LngLat(ne.lng, sw.lat))
        const height = sw.distance(new AMap.LngLat(sw.lng, ne.lat))
        info.area = Math.round(width * height)
        info.perimeter = Math.round((width + height) * 2)
      } else if (overlay instanceof AMap.Circle) {
        // 圆形:计算半径、面积和周长
        info.type = '圆形'
        const radius = overlay.getRadius()
        info.radius = Math.round(radius)
        info.area = Math.round(Math.PI * radius * radius)
        info.perimeter = Math.round(2 * Math.PI * radius)
      } else if (overlay instanceof AMap.Polygon) {
        // 多边形:计算面积和周长
        info.type = '多边形'
        info.area = Math.round(overlay.getArea())
        const path = overlay.getPath()
        let perimeter = 0
        for (let i = 0; i < path.length; i++) {
          const j = (i + 1) % path.length
          perimeter += path[i].distance(path[j])
        }
        info.perimeter = Math.round(perimeter)
      }

      this.overlayInfo = info
    },

    /**
     * 清除当前选中的覆盖物
     * 从地图和数组中移除当前选中的图形,并清理相关状态
     */
    clearCurrentOverlay() {
      if (this.currentOverlay) {
        // 从地图中移除图形
        this.map.remove(this.currentOverlay)
        // 从覆盖物数组中移除
        const index = this.overlays.indexOf(this.currentOverlay)
        if (index > -1) {
          this.overlays.splice(index, 1)
        }
        // 清理状态
        this.currentOverlay = null
        this.overlayInfo = null
        // 关闭编辑器
        if (this.currentEditor) {
          this.currentEditor.close()
          this.currentEditor = null
        }
      }
    },

    /**
     * 绘制折线/线路
     * 启动折线绘制工具,用户可以在地图上点击绘制路径
     */
    drawPolyline() {
      this.mouseTool.polyline({
        strokeColor: '#3366FF', // 线条颜色(蓝色)
        strokeOpacity: 1, // 线条透明度
        strokeWeight: 6, // 线条宽度
        strokeStyle: 'solid', // 线条样式
        strokeDasharray: [10, 5] // 虚线样式
      })
      this.setupDrawingEvents() // 设置绘制完成回调
    },

    /**
     * 绘制矩形区域
     * 启动矩形绘制工具,用户可以在地图上拖拽绘制矩形
     */
    drawRectangle() {
      this.mouseTool.rectangle({
        strokeColor: '#FF33FF', // 边框颜色(紫色)
        strokeOpacity: 1, // 边框透明度
        strokeWeight: 4, // 边框宽度
        fillColor: '#1791fc', // 填充颜色(蓝色)
        fillOpacity: 0.4, // 填充透明度
        strokeStyle: 'solid' // 边框样式
      })
      this.setupDrawingEvents() // 设置绘制完成回调
    },

    /**
     * 绘制圆形区域
     * 启动圆形绘制工具,用户可以在地图上拖拽绘制圆形
     */
    drawCircle() {
      this.mouseTool.circle({
        strokeColor: '#FF33FF', // 边框颜色(紫色)
        strokeOpacity: 1, // 边框透明度
        strokeWeight: 4, // 边框宽度
        fillColor: '#1791fc', // 填充颜色(蓝色)
        fillOpacity: 0.4, // 填充透明度
        strokeStyle: 'solid' // 边框样式
      })
      this.setupDrawingEvents() // 设置绘制完成回调
    },

    /**
     * 绘制多边形区域
     * 启动多边形绘制工具,用户可以在地图上点击绘制任意多边形
     */
    drawPolygon() {
      this.mouseTool.polygon({
        strokeColor: '#FF33FF', // 边框颜色(紫色)
        strokeOpacity: 1, // 边框透明度
        strokeWeight: 4, // 边框宽度
        fillColor: '#1791fc', // 填充颜色(蓝色)
        fillOpacity: 0.4, // 填充透明度
        strokeStyle: 'solid' // 边框样式
      })
      this.setupDrawingEvents() // 设置绘制完成回调
    },

    /**
     * 启用图形编辑模式
     * 根据当前选中图形的类型创建相应的编辑器
     */
    enableEdit() {
      // 检查是否有选中的图形
      if (!this.currentOverlay) {
        this.$message.warning('请先选择要编辑的图形')
        this.radio = '0'
        return
      }

      try {
        // 根据不同类型的覆盖物创建对应的编辑器
        if (this.currentOverlay instanceof AMap.Rectangle) {
          // 矩形编辑器
          this.currentEditor = new AMap.RectangleEditor(this.map, this.currentOverlay)
          this.$message.success('矩形编辑模式已启用,拖拽控制点调整大小')
        } else if (this.currentOverlay instanceof AMap.Circle) {
          // 圆形编辑器
          this.currentEditor = new AMap.CircleEditor(this.map, this.currentOverlay)
          this.$message.success('圆形编辑模式已启用,拖拽控制点调整大小和位置')
        } else if (
          this.currentOverlay instanceof AMap.Polyline ||
          this.currentOverlay instanceof AMap.Polygon
        ) {
          // 折线和多边形编辑器
          this.currentEditor = new AMap.PolyEditor(this.map, this.currentOverlay)
          this.$message.success('已进入编辑模式,拖拽节点进行编辑')
        } else {
          this.$message.warning('该图形暂不支持编辑')
          this.radio = '0'
          return
        }

        // 开启编辑模式
        this.currentEditor.open()

        // 监听编辑过程中的调整事件,实时更新图形信息
        this.currentEditor.on('adjust', () => {
          this.calculateOverlayInfo(this.currentOverlay)
        })

        // 监听编辑结束事件,更新图形信息
        this.currentEditor.on('end', () => {
          this.calculateOverlayInfo(this.currentOverlay)
        })
      } catch (error) {
        console.error('编辑器初始化失败:', error)
        this.$message.warning('编辑器初始化失败,请重试')
        this.radio = '0'
      }
    },

    /**
     * 启用删除模式
     * 删除当前选中的图形
     */
    enableDelete() {
      if (this.currentOverlay) {
        this.clearCurrentOverlay() // 清除选中的图形
        this.$message.success('已删除选中的图形')
      } else {
        this.$message.warning('请先选择要删除的图形')
      }
      this.radio = '0' // 切换回拖动模式
    }
  },

  /**
   * 组件销毁前的清理工作
   * 关闭编辑器和销毁地图实例,避免内存泄漏
   */
  beforeDestroy() {
    // 关闭当前编辑器
    if (this.currentEditor) {
      this.currentEditor.close()
    }
    // 销毁地图实例
    if (this.map) {
      this.map.destroy()
    }
  }
}
</script>

<style lang="scss" scoped>
.container {
  width: 100%;
  height: 100%;
  background-color: #fff;
  position: relative;
  font-family: 'Helvetica Neue', Helvetica, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei',
    '微软雅黑', Arial, sans-serif;

  #map-container {
    width: 100%;
    height: 100%;
  }

  // 顶部工具栏
  .toolbar {
    position: absolute;
    top: 15px;
    left: 15px;
    right: 15px;
    z-index: 1000;
    display: flex;
    justify-content: space-between;
    align-items: center;
    background: rgba(255, 255, 255, 0.95);
    backdrop-filter: blur(8px);
    padding: 12px 16px;
    border-radius: 12px;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
    border: 1px solid rgba(255, 255, 255, 0.2);

    .left-tools {
      display: flex;
      align-items: center;
    }

    .right-tools {
      display: flex;
      gap: 8px;

      .el-button {
        border-radius: 8px;
        font-weight: 500;
        transition: all 0.3s ease;

        &:hover {
          transform: translateY(-1px);
          box-shadow: 0 4px 12px rgba(64, 158, 255, 0.3);
        }
      }
    }
  }

  // 搜索面板
  .search-panel {
    position: absolute;
    top: 85px;
    left: 15px;
    z-index: 999;
    background: rgba(255, 255, 255, 0.95);
    backdrop-filter: blur(8px);
    padding: 20px;
    border-radius: 12px;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
    border: 1px solid rgba(255, 255, 255, 0.2);
    width: 320px;
    max-height: 400px;
    overflow: hidden;

    .search-results {
      margin-top: 12px;
      max-height: 280px;
      overflow-y: auto;

      .search-item {
        padding: 12px;
        border-bottom: 1px solid rgba(0, 0, 0, 0.05);
        cursor: pointer;
        border-radius: 8px;
        margin-bottom: 4px;
        transition: all 0.2s ease;

        &:hover {
          background: rgba(64, 158, 255, 0.05);
          transform: translateX(4px);
        }

        .item-name {
          font-weight: 600;
          margin-bottom: 4px;
          color: #303133;
        }

        .item-address {
          font-size: 12px;
          color: #909399;
          margin-bottom: 2px;
        }

        .item-distance {
          font-size: 11px;
          color: #409eff;
          font-weight: 500;
        }
      }
    }
  }

  // 坐标信息显示
  .coordinate-info {
    position: absolute;
    bottom: 15px;
    left: 15px;
    z-index: 999;
    background: rgba(0, 0, 0, 0.75);
    backdrop-filter: blur(8px);
    color: white;
    padding: 10px 16px;
    border-radius: 8px;
    font-size: 12px;
    font-family: 'Monaco', 'Menlo', monospace;
    display: flex;
    gap: 16px;

    .coord-item {
      display: flex;
      align-items: center;

      .label {
        opacity: 0.8;
        margin-right: 4px;
      }

      .value {
        font-weight: 600;
        color: #00ff88;
      }
    }
  }

  // 覆盖物信息面板
  .overlay-info {
    position: absolute;
    bottom: 15px;
    right: 15px;
    z-index: 999;
    background: rgba(255, 255, 255, 0.95);
    backdrop-filter: blur(8px);
    padding: 16px;
    border-radius: 12px;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
    border: 1px solid rgba(255, 255, 255, 0.2);
    min-width: 200px;
    max-width: 280px;

    h4 {
      margin: 0 0 12px 0;
      font-size: 14px;
      font-weight: 600;
      color: #303133;
      display: flex;
      align-items: center;

      i {
        margin-right: 8px;
        color: #409eff;
      }
    }

    .info-content {
      p {
        margin: 6px 0;
        font-size: 13px;
        color: #606266;

        strong {
          color: #303133;
          margin-right: 8px;
        }
      }
    }
  }
}

// 响应式设计
@media (max-width: 768px) {
  .container {
    .toolbar {
      left: 10px;
      right: 10px;
      flex-direction: column;
      gap: 10px;

      .left-tools,
      .right-tools {
        width: 100%;
        justify-content: center;
      }
    }

    .search-panel {
      left: 10px;
      right: 10px;
      top: 120px;
      width: auto;
    }

    .coordinate-info {
      left: 10px;
      right: 10px;
      bottom: 10px;
      flex-direction: column;
      gap: 4px;
      text-align: center;
    }

    .overlay-info {
      left: 10px;
      right: 10px;
      bottom: 80px;
    }
  }
}

// 动画效果
@keyframes fadeInUp {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.search-panel,
.overlay-info {
  animation: fadeInUp 0.3s ease-out;
}

// 滚动条样式
::-webkit-scrollbar {
  width: 6px;
}

::-webkit-scrollbar-track {
  background: rgba(0, 0, 0, 0.05);
  border-radius: 3px;
}

::-webkit-scrollbar-thumb {
  background: rgba(64, 158, 255, 0.3);
  border-radius: 3px;

  &:hover {
    background: rgba(64, 158, 255, 0.5);
  }
}
</style>