解决Leaflet.draw中polyline绘制无法结束的问题

简介: 通过本文,可以了解如何自定义Draw.PolyLine对象,以及在扩展时需要注意的一些坑,知道如何调试函数并定位问题,最终完成需求。

     阅读过之前的文章基于Leaflet.draw的gis图形标绘实战和干货!基于Leaflet.draw的自定义绘制,也许你大致知道了如何扩展自己的基本绘制以及在无draw按钮的情况下激活绘制组件。但是你有没有自己扩展过polyline,比如需要额外增加一个数据编辑图层,用于保存一条线或者一个面。那此时我们该怎么做呢?

    解决思路如下:

       1、扩展polyline对象。

       2、扩展map的创建函数,将draw组件注册的对象类型和自定义对象的type分开,并可以单独处理。

       3、针对需求创建自定义处理函数。

第一步、创建扩展对象类,

在Draw.Polyline.js平级目录下新增Draw.Diy.js类,代码如下:

/** * @class L.Draw.Polyline4Diy * @aka Draw.Polyline4Diy * @inherits L.Draw.Polyline */L.Draw.Polyline4Diy=L.Draw.Polyline.extend({
statics: {
TYPE: 'polyline4diy'  },
options: {
allowIntersection: true,
repeatMode: false,
drawError: {
color: '#b00b00',
timeout: 2500    },
icon: newL.DivIcon({
iconSize: newL.Point(8, 8),
className: 'leaflet-div-icon leaflet-editing-icon'    }),
touchIcon: newL.DivIcon({
iconSize: newL.Point(20, 20),
className: 'leaflet-div-icon leaflet-editing-icon leaflet-touch-icon'    }),
guidelineDistance: 20,
maxGuideLineLength: 4000,
shapeOptions: {
stroke: true,
color: '#3388ff',
weight: 4,
opacity: 0.5,
fill: false,
clickable: true    },
metric: true, // Whether to use the metric measurement system or imperialfeet: true, // When not metric, to use feet instead of yards for display.nautic: false, // When not metric, not feet use nautic mile for displayshowLength: true, // Whether to display distance in the tooltipzIndexOffset: 2000, // This should be > than the highest z-index any map layersfactor: 1, // To change distance calculationmaxPoints: 0// Once this number of points are placed, finish shape  },
// @method initialize(): voidinitialize: function (map, options) {
// if touch, switch to touch iconif (L.Browser.touch) {
this.options.icon=this.options.touchIcon;
    }
// Need to set this here to ensure the correct message is used.this.options.drawError.message=L.drawLocal.draw.handlers.polyline.error;
// Merge default drawError options with custom optionsif (options&&options.drawError) {
options.drawError=L.Util.extend({}, this.options.drawError, options.drawError);
    }
// Save the type so super can fire, need to do this as cannot do this.TYPE :(this.type=L.Draw.Polyline4Diy.TYPE;
L.Draw.Feature.prototype.initialize.call(this, map, options);
  },
// calculate if we are currently within close enough distance// of the closing point (first point for shapes, last point for lines)// this is semi-ugly code but the only reliable way i found to get the job done// note: calculating point.distanceTo between mouseDownOrigin and last marker did NOT work_calculateFinishDistance: function (potentialLatLng) {
varlastPtDistance;
if (this._markers.length>0) {
varfinishMarker;
if (this.type===L.Draw.Polyline.TYPE) {
finishMarker=this._markers[this._markers.length-1];
      } elseif (this.type===L.Draw.Polygon.TYPE) {
finishMarker=this._markers[0];
      } else {
returnInfinity;
      }
varlastMarkerPoint=this._map.latLngToContainerPoint(finishMarker.getLatLng()),
potentialMarker=newL.Marker(potentialLatLng, {
icon: this.options.icon,
zIndexOffset: this.options.zIndexOffset*2        });
varpotentialMarkerPint=this._map.latLngToContainerPoint(potentialMarker.getLatLng());
lastPtDistance=lastMarkerPoint.distanceTo(potentialMarkerPint);
    } else {
lastPtDistance=Infinity;
    }
returnlastPtDistance;
  }
});

上述代码可以从Draw.PolyLine.js中复制而来,只需要将不同的代码修改即可。比如声明不同的类型(必须要,相当于给当前类进行一个类型申明)。

statics: {
TYPE: 'polyline4diy'  },
// @method initialize(): voidinitialize: function (map, options) {
// if touch, switch to touch iconif (L.Browser.touch) {
this.options.icon=this.options.touchIcon;
    }
// Need to set this here to ensure the correct message is used.this.options.drawError.message=L.drawLocal.draw.handlers.polyline.error;
// Merge default drawError options with custom optionsif (options&&options.drawError) {
options.drawError=L.Util.extend({}, this.options.drawError, options.drawError);
    }
// Save the type so super can fire, need to do this as cannot do this.TYPE :(this.type=L.Draw.Polyline4Diy.TYPE;
L.Draw.Feature.prototype.initialize.call(this, map, options);
  },

第二步、绘制激活

functiondrawLine(){
diyDrawLayers.clearLayers();
newL.Draw.Polyline4Diy(map).enable();
}

第三步、自定义对象和默认对象分开定义

// Object created - bind popup to layer, add to feature groupmap.on(L.Draw.Event.CREATED, function(event) {
varlayer=event.layer;
varlayerType=event.layerType;
varcontent=getPopupContent(layer);
if (content!==null) {
layer.bindPopup(content);
      }
if(layerType==L.Draw.Rectangle4Diy.TYPE||layerType==L.Draw.Polyline4Diy.TYPE){
diyDrawLayers.addLayer(layer);
      }else{
drawnItems.addLayer(layer);
      }
  });

通过以上步骤可完成自定义polyline扩展,功能如下图:

image.png

实际操作时,你会发现,当点击最后一个绘制的点,绘制动作并未停下,而polyline绘制时却可以停下。是哪里出现了问题呢?

       在Draw.Diy.js文件中,我们去查找绘制结束的计算方法,并debug看下发生了什么?

image.png

debug发现,其lastPtDistance是INfinity,继续往前看,

image.png

仔细观察发现,我们在计算时,忘记了将type修改成为我们自己定义的类型,因此会导致计算失误,无法绘制结束,只需要将type修改为如下即可

if (this.type === L.Draw.Polyline4Diy.TYPE)

       清空缓存,在此进行绘制就会发现,点击线的最后一个点可以正常结束。

       总结:通过本文,可以了解如何自定义Draw.PolyLine对象,以及在扩展时需要注意的一些坑,知道如何调试函数并定位问题,最终完成我们的需求

目录
相关文章
|
7月前
|
前端开发
canvas绘制圆环
canvas绘制圆环
|
定位技术 API
基于Leaflet.draw的自定义绘制实战
本文介绍了如何基于leaflet.draw进行自定义绘制,同时获取对象的bbox和geojson信息。
837 0
基于Leaflet.draw的自定义绘制实战
|
前端开发 关系型数据库 容器
利用Canvas进行绘制XY坐标系
原文:利用Canvas进行绘制XY坐标系 首先来一发图 绘制XY的坐标主要是利用Canvas setLeft和setBottom功能(Canvas内置坐标的功能) 1.首先WPF中的坐标系都是从左到右,从上到下的 即左上角位置(0,0)点,所以XY的Canvas要以(RenderTransf...
1742 0
|
2月前
|
JSON 数据格式
Cesium绘制一个正方体
这篇文章详细说明了如何在Cesium中创建并精确控制一个厘米级精度的立方体模型。
46 2
Cesium绘制一个正方体
|
5月前
|
前端开发
已知数组 [{ x, y, radius }, ...], 在canvas中绘制出对应图形
已知数组 [{ x, y, radius }, ...], 在canvas中绘制出对应图形
|
7月前
|
缓存 前端开发 JavaScript
canvas详解01-绘制基本图形
canvas详解01-绘制基本图形
132 2
246Echarts - 3D 曲面(Image Surface Sushuang)
246Echarts - 3D 曲面(Image Surface Sushuang)
61 0
250Echarts - 3D 曲面(Sphere Parametric Surface)
250Echarts - 3D 曲面(Sphere Parametric Surface)
39 0
256Echarts - 3D 曲面(Surface Wave)
256Echarts - 3D 曲面(Surface Wave)
95 0
|
前端开发
canvas绘制五角星
canvas绘制五角星
191 0