console
function loadMap (key, plugins, v = '1.4.14') {
return new Promise(function (resolve, reject) {
if (typeof AMap !== 'undefined') {
// eslint-disable-next-line no-undef
resolve(AMap)
return true
}
window.onCallback = function () {
// eslint-disable-next-line no-undef
resolve(AMap)
}
let script = document.createElement('script')
script.type = 'text/javascript'
script.src = `https://webapi.amap.com/maps?v=${v}&key=${key}&plugin=${plugins}&callback=onCallback`
script.onerror = reject
document.head.appendChild(script)
})
}
var Main = {
data () {
return {
// 地图实例
GDMap: null,
// 加载的一些插件
// 更多参考:https://lbs.amap.com/api/javascript-api/guide/abc/plugins#plugins
plugins: [
'AMap.OverView',
'AMap.MouseTool',
'AMap.PolyEditor',
'AMap.RectangleEditor',
'AMap.PlaceSearch',
'AMap.DistrictLayer',
'AMap.CustomLayer'
],
// key
key: 'c5eac55551560531336988396dacbf53',
// 地图版本
v: '1.4.14',
loading: true,
// 多边形集合
polygons: [
[
[ 116.402921, 39.984507 ],
[ 116.531324, 39.938719 ],
[ 116.525144, 39.858648 ],
[ 116.423521, 39.821742 ]
]
],
polygonsGroup: null, // 多边形OverlayGroup集合实例,方便管理
isDrawing: false, // 是否正在绘制
drawingPolygon: {
polyline: null, // 绘制过程中的折线实例
polylinePath: [], // 折线的path
polygon: null, // 根据折线路径自动生成的多边形的实例
pointsGroup: null, // 绘制过程中点的集合的实例
pointOnLine: null, // 多边形边上的点的实例
isOnPolygon: null // 点是否在多边形上
},
styles: {
// 圆点option
circleMarker: {
radius: 4,
strokeColor: '#010301',
strokeWeight: 2,
strokeOpacity: 1,
fillColor: '#FFFFFF',
fillOpacity: 1,
bubble: true,
cursor: 'pointer',
clickable: true,
zIndex: 999999
},
// 绘制过程中折线的option
drawingPolyline: {
strokeColor: '#dd9ab0',
strokeWeight: 5,
strokeStyle: 'dashed',
strokeDasharray: [5, 20],
bubble: true
},
polygon: {
fillColor: '#DC3021', // 填充色
fillOpacity: 0.2, // 填充透明度
strokeColor: '#DC3021', // 轮廓颜色
strokeWeight: 1, // 轮廓宽度
strokeOpacity: 0.9 // 轮廓透明度
}
}
}
},
mounted () {
loadMap(this.key, this.plugins, this.v)
.then(AMap => {
this.GDMap = new AMap.Map('GDMap', {
zoom: 11,
center: [116.397428, 39.90923],
isHotspot: false
})
// 绑定地图单击事件
this.GDMap.on('click', this.mapOnClick)
// 地图双击事件
this.GDMap.on('dblclick', this.mapOnDblclick)
// 绑定地图鼠标移动事件
this.GDMap.on('mousemove', this.mapOnMouseMove)
this.GDMap.on('complete', () => {
// 地图加载完成后初始化已有的多边形
this.polygons.forEach(polygon => {
this.addPolygon(polygon)
})
})
})
.catch(() => {
console.log('地图加载失败!')
})
},
methods: {
drawPolygon () {
this.isDrawing = true
},
// 地图点击事件
mapOnClick (ev) {
if (!this.isDrawing) return
let position = [ev.lnglat.lng, ev.lnglat.lat] // 鼠标点击的坐标
// 判断是否存在存在线上圆点实例及是否在线上
if (this.drawingPolygon.isOnPolygon && this.drawingPolygon.pointOnLine) {
const center = this.drawingPolygon.pointOnLine.getCenter() // 获取线上圆点的中心
position = [center.lng, center.lat]
}
this.addPolygonPoint(position) // 地图上增加相应的点
this.addDrawingPolyline([position, position]) // 添加绘制过程中的鼠标移动位置的折线
this.drawPolygonByPoints() // 通过点围成多边形
},
// 地图双击事件
mapOnDblclick (ev) {
if (!this.isDrawing) return
this.complateDraw()
},
// 地图鼠标移动事件
mapOnMouseMove (ev) {
if (!this.isDrawing) return
const position = [ev.lnglat.lng, ev.lnglat.lat]
const linePath = this.getPointLine(position) // 获取点所在的线
let recentPoint = null // 定义最近的点
if (this.drawingPolygon.isOnPolygon) {
// 如果点在线上(这个点存在偏移,所以还得通过getRecentPoint获取到正在的最近的一个点)
// 获取该点到线的最近的一个点
recentPoint = this.getRecentPoint(linePath, position)
this.addDrawingOnLinePoint(recentPoint) // 在线上添加圆点,也就是自动吸附的时候创建的点
} else {
this.removeDrawingOnLinePoint()
}
this.setDrawingPolyline(position)
},
// 添加围成多边形的点
addPolygonPoint (position) {
// 样式及坐标option
const option = {
...this.styles.circleMarker,
center: position
}
const circlePointMarker = new AMap.CircleMarker(option) // 单个圆点实例
// 先判断是否存在圆点集合实例
// 所有的圆点这里通过高德提供的OverlayGroup统一管理
if (!this.drawingPolygon.pointsGroup) { // 如果不存在
this.drawingPolygon.pointsGroup = new AMap.OverlayGroup() // 创建绘制过程中点的集合的实例
this.GDMap.add(this.drawingPolygon.pointsGroup) // 将集合添加到地图上显示
}
this.drawingPolygon.pointsGroup.addOverlay(circlePointMarker) // 将点添加到集合里面
},
// 新增绘制中的折线
addDrawingPolyline (paths) {
// 判断有无折线
if (this.drawingPolygon.polyline) {
this.drawingPolygon.polyline.setPath(paths) // 有的话直接设置折线路径
} else { // 没有的话需要创建折线
// 折线样式及路径
const option = {
...this.styles.drawingPolyline,
path: paths
}
this.drawingPolygon.polyline = new AMap.Polyline(option) // 生成折线
this.GDMap.add(this.drawingPolygon.polyline) // 地图上添加折线
}
this.drawingPolygon.polylinePath = paths // 存一下折线的路径
},
// 设置绘制中的折线的路径
setDrawingPolyline (position) {
if (this.drawingPolygon.polyline) {
// 新增的折线的路径,由上次记录折线的开始点+鼠标坐标位置点
const linePath = [
this.drawingPolygon.polylinePath[0], // 上次记录折线的开始点
position // 鼠标坐标位置点
]
this.drawingPolygon.polyline.setPath(linePath)
this.drawingPolygon.polylinePath = linePath
}
},
// 根据点画区块多边形
drawPolygonByPoints () {
const pointsGroup = this.drawingPolygon.pointsGroup // 点及的集合实例
const pointsLength = pointsGroup ? pointsGroup.getOverlays().length : 0 // 点的长度
if (pointsLength > 1) {
// 获取每个点的中心点组成path
const paths = pointsGroup.getOverlays().map(item => {
const path = item.getCenter()
return [path.lng, path.lat]
})
// 地图上绘制多边形
if (this.drawingPolygon.polygon) {
this.drawingPolygon.polygon.setPath(paths)
} else {
const option = {
...this.styles.polygon,
path: paths
}
this.drawingPolygon.polygon = new AMap.Polygon(option)
this.drawingPolygon.polygon.setMap(this.GDMap)
}
}
},
// 绘制完成
complateDraw () {
const paths = this.drawingPolygon.polygon.getPath().map(item => [item.lng, item.lat]) // 绘制完成的多边形path
this.isDrawing = false // 取消绘制
this.polygons.push(paths) // 添加绘制的多边形
this.addPolygon(paths) // 地图上添加绘制的多边形
this.clearUselessOverlays() // 清理数据
},
// 清理无用的图层
clearUselessOverlays () {
if (!this.GDMap) return
this.GDMap.remove(this.drawingPolygon.polyline)
this.GDMap.remove(this.drawingPolygon.polygon)
this.GDMap.remove(this.drawingPolygon.pointsGroup)
if (this.drawingPolygon.pointOnLine) {
this.GDMap.remove(this.drawingPolygon.pointOnLine)
}
this.drawingPolygon.polyline = null
this.drawingPolygon.polygon = null
this.drawingPolygon.pointsGroup = null
this.drawingPolygon.polylinePath = []
this.drawingPolygon.isOnPolygon = false
},
// 添加多边形
addPolygon (paths) {
if (!this.GDMap) return
const option = {
...this.styles.polygon,
path: [...paths]
}
const polygon = new AMap.Polygon(option)
if (!this.polygonsGroup) {
this.polygonsGroup = new AMap.OverlayGroup()
this.GDMap.add(this.polygonsGroup)
}
this.polygonsGroup.addOverlay(polygon)
},
// 添加多边形边线上的点
addDrawingOnLinePoint (center) {
if (this.drawingPolygon.pointOnLine) {
this.drawingPolygon.pointOnLine.setCenter(center)
return
}
const option = {
map: this.GDMap,
center: center,
...this.styles.circleMarker
}
this.drawingPolygon.pointOnLine = new AMap.CircleMarker(option)
},
// 移除多边形线上的点
removeDrawingOnLinePoint () {
if (this.drawingPolygon.pointOnLine) {
this.GDMap.remove(this.drawingPolygon.pointOnLine)
this.drawingPolygon.pointOnLine = null
}
},
// 获取点所在的线
getPointLine (position) {
const resolution = this.GDMap.getResolution()// 获取指定位置的地图分辨率,单位:米/像素
const pointWidth = 6 * resolution// 线段上圆点的宽度,也就是误差
let linePath = []
this.drawingPolygon.isOnPolygon = false // 默认点不在线上
// 循环所有的多边形,取到所有的线一一比较,存在性能问题
for (let i = 0; i < this.polygons.length; i++) {
const itemPath = this.polygons[i]
let hasFind = false
for (let n = 0; n < itemPath.length; n++) {
const path = itemPath[n]
const nextPath = itemPath[n + 1]
const line = nextPath ? [path, nextPath] : [path, itemPath[0]]
// 高德地图提供的isPointOnSegment判断点是否在线段上
const isPointOnSegment = AMap.GeometryUtil.isPointOnSegment(position, line[0], line[1], pointWidth)
if (isPointOnSegment) {
linePath = line
this.drawingPolygon.isOnPolygon = true
hasFind = true
break
}
}
if (hasFind) break
}
return linePath
},
// 获取最近的点的坐标
getRecentPoint (paths, curPointPosition) {
const recentPoint = AMap.GeometryUtil.closestOnLine(curPointPosition, paths)
return recentPoint
}
},
watch: {
isDrawing (newState) {
if (newState) {
this.GDMap.setDefaultCursor('crosshair')
} else {
this.GDMap.setDefaultCursor('')
}
this.GDMap.setStatus({
doubleClickZoom: !newState
})
}
}
}
var Ctor = Vue.extend(Main)
new Ctor().$mount('#app')
<script src="https://unpkg.com/vue@2.6.10/dist/vue.js">
</script>
<div id="app">
<template>
<div class="map">
<button type="primary" @click="drawPolygon">
画多边形
</button>
<div id="GDMap">
</div>
</div>
</template>
</div>
#GDMap {
width: 1200px;
height: 500px;
position: relative;
}