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


1. 线路绘制实现
核心代码:
php
drawPolyline() {
this.mouseTool.polyline({
strokeColor: '#3366FF',
strokeOpacity: 1,
strokeWeight: 6,
strokeStyle: 'solid',
strokeDasharray: [10, 5]
});
}
实现要点:
- 🖱️ 使用
AMap.MouseTool
的polyline
方法 - 🎨 可配置线条颜色、透明度、宽度等样式
- ➖ 支持虚线样式(通过
strokeDasharray
)
计算长度:
ini
// 📏 计算线路总长度
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
kotlin
if (this.currentOverlay instanceof AMap.Polyline) {
this.currentEditor = new AMap.PolyEditor(this.map, this.currentOverlay);
this.currentEditor.open();
// ✨ 提示用户进入编辑模式
this.$message.success('已进入线路编辑模式,可拖动节点调整');
}
编辑特性:
- 🔴 可拖动节点调整线路形状
- ➕ 可在线段上添加新节点
- 🔄 实时更新线路长度计算
二、矩形绘制与编辑 🟦


1. 矩形绘制实现
核心代码:
php
drawRectangle() {
this.mouseTool.rectangle({
strokeColor: '#FF33FF',
strokeOpacity: 1,
strokeWeight: 4,
fillColor: '#1791fc',
fillOpacity: 0.4,
strokeStyle: 'solid'
});
}
实现要点:
- ↔️ 通过拖拽确定矩形对角点
- 🎨 可自定义边框和填充样式
- 📊 自动计算面积和周长
几何计算:
ini
// 📐 计算矩形几何属性
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. 矩形编辑功能
编辑实现:
kotlin
if (this.currentOverlay instanceof AMap.Rectangle) {
this.currentEditor = new AMap.RectangleEditor(this.map, this.currentOverlay);
this.currentEditor.open();
// 🔄 监听编辑事件
this.currentEditor.on('adjust', this.updateRectangleInfo);
}
编辑特性:
- ↕️ 拖动边线调整矩形大小
- ⏹️ 拖动角点同时调整宽度和高度
- 📈 实时更新面积和周长计算
三、圆形绘制与编辑 ⭕


1. 圆形绘制实现
核心代码:
php
drawCircle() {
this.mouseTool.circle({
strokeColor: '#FF33FF',
strokeOpacity: 1,
strokeWeight: 4,
fillColor: '#1791fc',
fillOpacity: 0.4,
strokeStyle: 'solid'
});
}
实现要点:
- 🎯 点击确定圆心,拖拽确定半径
- 🌈 支持自定义边框和填充样式
- 🔢 自动计算半径、面积和周长
几何计算:
ini
// 🔵 圆形几何计算
const radius = overlay.getRadius();
const area = Math.PI * radius * radius; // 面积
const perimeter = 2 * Math.PI * radius; // 周长
2. 圆形编辑功能
编辑实现:
kotlin
if (this.currentOverlay instanceof AMap.Circle) {
this.currentEditor = new AMap.CircleEditor(this.map, this.currentOverlay);
this.currentEditor.open();
// 🎛️ 添加编辑控制点
this.addEditControlPoints();
}
编辑特性:
- 🔘 拖动边缘控制点调整半径
- 🏗️ 拖动圆心改变位置
- 📏 实时更新几何属性计算
四、多边形绘制与编辑 🔷


1. 多边形绘制实现
核心代码:
php
drawPolygon() {
this.mouseTool.polygon({
strokeColor: '#FF33FF',
strokeOpacity: 1,
strokeWeight: 4,
fillColor: '#1791fc',
fillOpacity: 0.4,
strokeStyle: 'solid'
});
}
实现要点:
- ✏️ 连续点击添加顶点,双击结束绘制
- 🧩 支持复杂多边形绘制
- 📐 自动计算面积和周长
几何计算:
ini
// 📏 多边形几何计算
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. 多边形编辑功能
编辑实现:
kotlin
if (this.currentOverlay instanceof AMap.Polygon) {
this.currentEditor = new AMap.PolyEditor(this.map, this.currentOverlay);
this.currentEditor.open();
// 🖇️ 添加顶点编辑事件
this.setupVertexEvents();
}
编辑特性:
- 🔘 可拖动现有顶点调整形状
- ➕ 可在边上添加新顶点
- ❌ 支持删除顶点
- 🔄 实时更新几何属性计算
五、通用功能实现 ⚙️
1. 图形选择与删除
kotlin
enableDelete() {
if (this.currentOverlay) {
this.map.remove(this.currentOverlay);
// 🗑️ 从数组中移除...
this.currentOverlay = null;
this.$message.warning('图形已删除', { icon: '🗑️' });
}
}
2. 图形信息展示
ini
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>