高德绘图工具缺点
- 没有友好鼠标跟随文字提示功能
- 不支持撤销,回退功能
- 触发的事件只有draw事件,不能精确到每个节点的事件
- 绘制完的图形保存方式太单一,只能加入到自己的覆盖物组,没有封装
研发的高德工具
基于高德提供的地图事件和键盘事件,来满足更为复杂的业务需求,精确到对每一个节点操作进行监听,参考代码在下面,目前只支持绘制点,线,矩形,多边形,圆目前还没有需求,所以还没开始做,但基于这个代码扩展起来很方便,以下是相对于高德绘图工具的优点:(源码在下面)
- 绘制不同类型图形,鼠标不同的友好文字提示
- 支持撤销,回退功能
- 触发的事件支持更多,绘制完成事件,右键事件,绘制一个点事件,移动事件,开始事件
- 绘制完图形保存方式支持,不保存,只保存当前,保存所有
- 绘图次数支持绘制一次,和绘制多次
注意 :
- AMap._rightMenu这个属性,因为不仅封装了绘图工具,同时封装了右键菜单工具,所以单击鼠标右键的时候会有冲突,所以启用绘图工具的时候会禁用右键菜单,完成释放右键菜单,封装的右键菜单包含地图放大,缩小,复位,移动,点击查询,后面有时间会给大家讲封装的右键菜单
- 依赖于AMapTool文件,这个文件是生成默认的overlay,也可以自己编写生成overlay,那样就不依赖于其他文件。
- 下面是绘图工具部分截图
绘制多条线段
绘制多个矩形
绘制单个点
绘制单个多边形
define([
'product/webgisPanda/AMapTool/AMapTool',
], function (AMapTool) {
class AMapDrawTool {
static geometrySymbol = {
CircleMarker: {
},
Polyline: {
strokeColor: '#80d8ff',
bubble : true
},
Polygon: {
fillColor: '#00b0ff',
strokeColor: '#80d8ff'
},
Rectangle: {
fillColor: '#00b0ff',
strokeColor: '#80d8ff',
fillOpacity: .7
},
Circle: {
fillColor: '#00b0ff',
strokeColor: '#80d8ff'
}
}
static defaultTooltips = {
CircleMarker: "单击鼠标左键选取,右键取消",
Polyline: "单击鼠标左键开始绘制,ESC撤销,右键取消",
Polygon: "单击鼠标左键开始绘制,ESC撤销,右键取消",
Rectangle: "按下鼠标左键拖动开始绘制,右键取消",
StepByStep: "单击鼠标左键开始绘制",
Circle: "鼠标单击选取圆心,右键取消",
Circleing: "再次点击鼠标左键确认圆,右键取消",
}
constructor(options) {
this.type = options.type || 'CircleMarker'
this.map = options.map
this.geometrySymbol = options.geometrySymbol || AMapDrawTool.geometrySymbol[this.type]
this.drawHandles = []
this.toolTip = options.toolTip || AMapDrawTool.defaultTooltips[this.type]
this.cursor = this.defaultCursor || 'default'
this.drawMethod = options.drawMethod || 'once' //绘图次数, 1次或者多次 value : once or repeat
this.saveOverlayStatus = options.saveOverlayStatus || 'saveNot' //绘制的图形是否保存 自动清除 : saveNot , 保持1次 : saveOnce , 保持无限次 : saveMore
this.rightMenuHandleOverlays = options.rightMenuHandleOverlays || 'clear' // 默认右键菜单是清除,也可以保存 value =>clear save
this.addToolTip()
this.addOverlayGroup()
}
addToolTip() {
let $container = $(this.map.getContainer())
if ($container.find('#AMap-toolTip').length < 1) $container.append(`<div id="AMap-toolTip" style="position: absolute;left: -9999px;background-color: #fff;color: #333;padding: 2px;font-size: 12px;border: 1px solid red;border-radius: 3px;pointer-events: none;">${this.toolTip}</div>`)
this.$tipContainer = $container.find('#AMap-toolTip')
return this.$tipContainer
}
addOverlayGroup() {
this.overlayGroup = new AMap.OverlayGroup()
this.overlayGroup.setMap(this.map)
}
destoryOverlayGroup() {
if(this.overlayGroup){
this.overlayGroup.setMap(null)
this.overlayGroup = null
}
}
destory() {
this.destoryTip()
this.destoryEvents()
this.destoryOverlayGroup()
this.relaseMapDrag()
}
destoryEvents(){
this.drawHandles.map(function (drawHandle) {
AMap.event.removeListener(drawHandle)
})
this.drawHandles = []
}
destoryTip(){
if(this.$tipContainer){
this.$tipContainer.remove()
this.$tipContainer = null
}
}
hideTip(){
if(this.$tipContainer) this.$tipContainer.hide()
}
showTip(){
if(this.$tipContainer) this.$tipContainer.show()
}
pause(){
this.relaseMapDbClick()
this.relaseMapDrag()
this.$tipContainer.hide()
this.isDrawing = false
}
resume(){
this.$tipContainer.show()
this.isDrawing = true
this.stopMapDbClick()
this.stopMapDrag()
}
cancelDraw(clearOverlay) {
this.hideTip()
this.destoryEvents()
this.relaseMapDrag()
this.relaseMapDbClick()
if(clearOverlay) this.overlayGroup.clearOverlays()
}
drawBeforeEvent() {
this.addToolTip().show()
this.relaseMapDrag()
this.overlayGroup.clearOverlays()
this.destoryEvents()
this.isDrawing = true
if(AMap._rightMenu) AMap._rightMenu.enable = false
}
drawAfterEvent(){
setTimeout(function(){
if(AMap._rightMenu) AMap._rightMenu.enable = true
}.bind(this), 20)
this.relaseMapDrag()
}
draw(options) {
let drawEnd = options.drawEnd || function () {}
let rightClick = options.rightClick || function () {}
let drawPoint = options.drawPoint || function () {}
let drawing = options.drawing || function() {}
let drawStart = options.drawStart || function () {}
this.drawBeforeEvent()
switch (this.type) {
case "CircleMarker":
this.drawHandles.push(AMap.event.addListener(this.map, 'click', this.pointMouseDrawEndHandler.bind(this, drawEnd), this))
this.drawHandles.push(AMap.event.addListener(this.map, 'mousemove', this.pointMouseMoveHandler, this))
this.drawHandles.push(AMap.event.addListener(this.map, 'rightclick', this.pointMouseRightClickHandler.bind(this, rightClick), this))
break
case "Polyline":
this.repaintDrawpolyline = true
this.drawHandles.push(AMap.event.addListener(this.map, 'dblclick', this.polylineMouseDbClickHandler.bind(this, drawEnd), this))
this.drawHandles.push(AMap.event.addListener(this.map, 'mousemove', this.polylineMouseMoveHandler.bind(this, drawing), this))
this.drawHandles.push(AMap.event.addListener(this.map, 'click', this.polylineMouseClickHandler.bind(this, drawPoint, drawStart), this))
this.drawHandles.push(AMap.event.addListener(this.map, 'rightclick', this.polylineMouseRightClickHandler.bind(this, rightClick), this))
this.drawHandles.push(AMap.event.addDomListener($('body').get(0), 'keyup',this.polylineKeyupHandler.bind(this),this))
break
case "Rectangle":
this.drawHandles.push(AMap.event.addListener(this.map, 'mousedown', this.rectangleMouseDownHandler.bind(this,drawStart), this))
this.drawHandles.push(AMap.event.addListener(this.map, 'mousemove', this.rectangleMouseMoveHandler.bind(this, drawing), this))
this.drawHandles.push(AMap.event.addListener(this.map, 'mouseup', this.rectangleMouseUpHandler.bind(this, drawEnd), this))
this.drawHandles.push(AMap.event.addListener(this.map, 'rightclick', this.rectangleMouseRightClickHandler.bind(this, rightClick), this))
break
case "Polygon" :
this.repaintDrawpolygon = true
this.drawHandles.push(AMap.event.addListener(this.map, 'dblclick', this.polygonMouseDbClickHandler.bind(this, drawEnd), this))
this.drawHandles.push(AMap.event.addListener(this.map, 'mousemove', this.polygonMouseMoveHandler.bind(this, drawing), this))
this.drawHandles.push(AMap.event.addListener(this.map, 'click', this.polygonMouseClickHandler.bind(this, drawPoint, drawStart), this))
this.drawHandles.push(AMap.event.addListener(this.map, 'rightclick', this.polygonMouseRightClickHandler.bind(this, rightClick), this))
this.drawHandles.push(AMap.event.addDomListener($('body').get(0), 'keyup',this.polygonKeyupHandler.bind(this),this))
default:
break
}
this.map.setDefaultCursor(this.cursor)
}
/*****绘制点 ********/
pointMouseMoveHandler(e){
if(this.mouseEventStopAction()) return
this.mouseMoveTipHandler(e)
}
pointMouseRightClickHandler(rightClick, e){
if(this.mouseEventStopAction()) return
this.rightClickCommon(rightClick)
}
pointMouseDrawEndHandler(drawEnd, e){
if(this.mouseEventStopAction()) return
if(this.drawMethod == 'once'){
if(this.saveOverlayStatus != 'saveNot'){
this.addOverlay({
type : 'CircleMarker',
coordinate : [e.lnglat.lng, e.lnglat.lat],
settings : this.geometrySymbol
})
}
this.cancelDraw()
this.drawAfterEvent()
}else if(this.drawMethod == 'repeat'){
switch(this.saveOverlayStatus){
case "saveNot" :
break
case "saveOnce" :
this.overlayGroup.clearOverlays()
this.addOverlay({
coordinate : [e.lnglat.lng, e.lnglat.lat],
settings : this.geometrySymbol
})
break
case "saveMore" :
this.addOverlay({
coordinate : [e.lnglat.lng, e.lnglat.lat],
settings : this.geometrySymbol
})
break
default :
break
}
}
drawEnd(e)
}
/*****绘制点 ********/
/*****绘制线 ********/
polylineMouseClickHandler(drawPoint, drawStart, e){
if(this.mouseEventStopAction()) return
this.commonMouseClickHander(this.repaintDrawpolyline, e)
let polylines = this.overlayGroup.getOverlays()
if(this.repaintDrawpolyline){
this.repaintDrawpolyline = false
let path = [
[e.lnglat.lng, e.lnglat.lat],
[e.lnglat.lng, e.lnglat.lat],
]
let settings = _.extend(this.geometrySymbol, {
path,
extData : {
lng : e.lnglat.lng,
lat : e.lnglat.lat,
},
bubble : true
})
let polyline = this.addOverlay({
coordinate : [[e.lnglat.lng, e.lnglat.lat]],
settings
})
drawStart(polyline, polylines.length + 1)
drawPoint(polyline)
}else{
let polyline = polylines[polylines.length - 1]
let path = polyline.getPath()
path.push(e.lnglat)
polyline.setPath(path)
drawPoint(polyline)
}
}
polylineMouseMoveHandler(drawing, e){
if(this.mouseEventStopAction()) return
this.mouseMoveTipHandler(e)
let polylines = this.overlayGroup.getOverlays()
if(polylines && polylines[polylines.length - 1] && !this.repaintDrawpolyline){
let polyline = polylines[polylines.length - 1]
let path = polyline.getPath()
path.pop()
path.push(e.lnglat)
polyline.setPath(path)
drawing(polyline)
}
}
polylineMouseDbClickHandler(drawEnd, e){
if(this.mouseEventStopAction()) return
this.relaseMapDrag()
let polylines = this.overlayGroup.getOverlays()
let polyline = polylines[polylines.length - 1]
this.handleRepeatPath(polyline)
if(this.drawMethod == 'once'){
if(this.saveOverlayStatus == 'saveNot'){
this.overlayGroup.clearOverlays()
}
this.cancelDraw()
this.drawAfterEvent()
}else if(this.drawMethod == 'repeat'){
switch(this.saveOverlayStatus){
case "saveNot" :
this.overlayGroup.clearOverlays()
break
case "saveOnce" :
break
case "saveMore" :
break
default :
break
}
this.repaintDrawpolyline = true
}
drawEnd(polyline)
}
handleRepeatPath(polyline){
if(this.mouseEventStopAction()) return
let path = polyline.getPath()
let flag = true
while(flag && path.length > 2){
let pathlast = path[path.length - 1]
let pathLastSecond = path[path.length - 2]
if(pathlast.lng == pathLastSecond.lng && pathlast.lat == pathLastSecond.lat){
path.pop()
}else{
flag = false
}
}
polyline.setPath(path)
}
polylineMouseRightClickHandler(rightClick){
if(this.mouseEventStopAction()) return
this.rightClickCommon(rightClick)
}
polylineKeyupHandler(e){
if(this.mouseEventStopAction()) return
if(e.key == 'Escape' || e.keyCode == 27){
let polylines = this.overlayGroup.getOverlays()
if(polylines.length == 0) return
this.repaintDrawpolyline = false
let polyline = polylines[polylines.length - 1]
let path = polyline.getPath()
if(path.length == 0 && polylines.length >= 2) return this.overlayGroup.removeOverlay(polyline)
if(path.length >= 3){
let pathLast = path[path.length - 1]
let pathTwo = path[path.length - 2]
if(pathLast.lng == pathTwo.lng && pathLast.lat == pathTwo.lat) path.pop()
}
path.pop()
if(path.length == 1 && this.drawMethod == 'repeat'){
if(polylines.length > 1) {
this.overlayGroup.removeOverlay(polyline)
polyline = []
}
return
}
polyline.setPath(path)
}
}
/*****绘制线 ********/
/*****绘制矩形 ********/
rectangleMouseDownHandler(drawStart, e){
if(this.mouseEventStopAction()) return
if(e.originEvent.button != 0) return
this.stopMapDrag()
this.mouseMoveTipHandler(e)
if(this.drawMethod == 'repeat') {
switch(this.saveOverlayStatus){
case "saveNot" :
break
case "saveOnce" :
this.overlayGroup.clearOverlays()
break
case "saveMore" :
break
default :
break
}
}
let bounds = new AMap.Bounds(new AMap.LngLat(e.lnglat.lng, e.lnglat.lat), new AMap.LngLat(e.lnglat.lng, e.lnglat.lat))
let settings = _.extend(this.geometrySymbol, {
bounds,
extData : {
lng : e.lnglat.lng,
lat : e.lnglat.lat,
},
bubble : true
})
let overlay = this.addOverlay({
type : 'Rectangle',
coordinate : [e.lnglat.lng, e.lnglat.lat,e.lnglat.lng, e.lnglat.lat],
settings
})
drawStart(overlay)
}
rectangleMouseMoveHandler(drawing, e){
if(this.mouseEventStopAction()) return
this.mouseMoveTipHandler(e)
let rectangles = this.overlayGroup.getOverlays()
if(rectangles && rectangles[rectangles.length - 1] && !this.getMapDragStatus()){
let rectangle = rectangles[rectangles.length - 1]
let bounds = rectangle.getBounds()
let origin = rectangle.getExtData()
bounds = new AMap.Bounds(new AMap.LngLat(origin.lng, origin.lat), new AMap.LngLat(e.lnglat.R, e.lnglat.Q))
rectangle.setBounds(bounds)
drawing(rectangle)
}
}
rectangleMouseUpHandler(drawEnd, e){
if(this.mouseEventStopAction()) return
if(e.originEvent.button != 0) return
this.relaseMapDrag()
let overlays = this.overlayGroup.getOverlays()
let overlay = overlays[overlays.length - 1]
if(this.drawMethod == 'once'){
if(this.saveOverlayStatus == 'saveNot'){
this.overlayGroup.clearOverlays()
}
this.cancelDraw()
this.drawAfterEvent()
}else if(this.drawMethod == 'repeat') {
switch(this.saveOverlayStatus){
case "saveNot" :
this.overlayGroup.clearOverlays()
break
case "saveOnce" :
break
case "saveMore" :
break
default :
break
}
}
drawEnd(overlay)
}
rectangleMouseRightClickHandler(rightClick){
if(this.mouseEventStopAction()) return
this.rightClickCommon(rightClick)
}
/*****绘制矩形 ********/
/*****绘制矩多边形 ********/
polygonMouseClickHandler(drawPoint, drawStart, e){
if(this.mouseEventStopAction()) return
this.commonMouseClickHander(this.repaintDrawpolygon, e)
let polygons = this.overlayGroup.getOverlays()
if(this.repaintDrawpolygon){
this.repaintDrawpolygon = false
let path = [
[e.lnglat.lng, e.lnglat.lat],
[e.lnglat.lng, e.lnglat.lat],
]
let settings = _.extend(this.geometrySymbol, {
path,
extData : {
lng : e.lnglat.lng,
lat : e.lnglat.lat,
},
bubble : true
})
let polygon = this.addOverlay({
coordinate : path,
settings
})
drawStart(polygon,polygons.length+1)
drawPoint(polygon)
}else{
let polygon = polygons[polygons.length - 1]
let path = polygon.getPath()
path.push(e.lnglat)
polygon.setPath(path)
drawPoint(polygon)
}
}
polygonMouseMoveHandler(drawing, e){
if(this.mouseEventStopAction()) return
this.mouseMoveTipHandler(e)
let polygons = this.overlayGroup.getOverlays()
if(polygons && polygons[polygons.length - 1] && !this.repaintDrawpolygon){
let polygon = polygons[polygons.length - 1]
let path = polygon.getPath()
path.pop()
path.push(e.lnglat)
polygon.setPath(path)
drawing(polygon)
}
}
polygonMouseDbClickHandler(drawEnd, e){
if(this.mouseEventStopAction()) return
this.relaseMapDrag()
let polygons = this.overlayGroup.getOverlays()
let polygon = polygons[polygons.length - 1]
this.handleRepeatPath(polygon)
if(this.drawMethod == 'once'){
if(this.saveOverlayStatus == 'saveNot'){
this.overlayGroup.clearOverlays()
}
this.cancelDraw()
this.drawAfterEvent()
}else if(this.drawMethod == 'repeat'){
switch(this.saveOverlayStatus){
case "saveNot" :
this.overlayGroup.clearOverlays()
break
case "saveOnce" :
break
case "saveMore" :
break
default :
break
}
this.repaintDrawpolygon = true
}
drawEnd(polygon)
}
polygonMouseRightClickHandler(rightClick){
if(this.mouseEventStopAction()) return
this.rightClickCommon(rightClick)
}
polygonKeyupHandler(e){
if(this.mouseEventStopAction()) return
if(e.key == 'Escape' || e.keyCode == 27){
let polygons = this.overlayGroup.getOverlays()
if(polygons.length == 0) return
this.repaintDrawpolygon = false
let polygon = polygons[polygons.length - 1]
let path = polygon.getPath()
if(path.length == 0 && polygons.length >= 2) return this.overlayGroup.removeOverlay(polygon)
if(path.length >= 3){
let pathLast = path[path.length - 1]
let pathTwo = path[path.length - 2]
if(pathLast.lng == pathTwo.lng && pathLast.lat == pathTwo.lat) path.pop()
}
path.pop()
if(path.length == 1 && this.drawMethod == 'repeat'){
if(polygons.length > 1) {
this.overlayGroup.removeOverlay(polygon)
polygon = []
}
return
}
polygon.setPath(path)
}
}
/*****绘制多边形 ********/
/*****绘制圆 ********/
/*****绘制圆 ********/
/*****公共模块 ********/
mouseEventStopAction(){
if(!this.getIsDrawing()) return true
return false
}
getIsDrawing(){
return !!this.isDrawing
}
mouseMoveTipHandler(e){
let x = e.pixel.x + 8
let y = e.pixel.y - 8
this.$tipContainer.css({
left: x + 'px',
top: y + 'px'
})
}
stopMapDrag() {
this.map.setStatus({
dragEnable: false
})
}
relaseMapDrag() {
this.map.setStatus({
dragEnable: true
})
}
getMapDragStatus(){
return this.map.getStatus()['dragEnable']
}
addOverlay({type , coordinate, settings}){
let overlay = AMapTool.getDefaultOverlay({
type : type || this.type,
coordinate : coordinate,
settings : settings
})['overlay']
this.overlayGroup.addOverlay(overlay)
return overlay
}
rightClickCommon(rightClick){
this.drawAfterEvent()
if(this.rightMenuHandleOverlays == 'clear'){
this.cancelDraw(true)
}else {
this.cancelDraw()
}
rightClick()
}
stopMapDbClick(){
this.map.setStatus({
doubleClickZoom : false
})
}
relaseMapDbClick(){
this.map.setStatus({
doubleClickZoom : true
})
}
commonMouseClickHander(repeatDraw, e){
this.stopMapDrag()
this.stopMapDbClick()
this.mouseMoveTipHandler(e)
if(this.drawMethod == 'repeat') {
switch(this.saveOverlayStatus){
case "saveNot" :
break
case "saveOnce" :
if(repeatDraw){
this.overlayGroup.clearOverlays()
}
break
case "saveMore" :
break
default :
break
}
}
}
/*****公共模块 ********/
}
return AMapDrawTool
});