缩放时的性能问题(Leaflet 0.7.3)

时间:2015-05-06 10:04:18

标签: performance leaflet openstreetmap zooming

我正面临Leaflet的性能问题(版本0.7.3)。我正在使用OSM地图,我用它来显示由装饰的折线连接的一堆CircleMarkers(每25px带箭头图案)。加载需要一点时间,但主要问题是,当我缩放地图时,我开始面临严重滞后(从缩放级别16),并且超出一定限制(比如大多数时间为18),浏览器只是冻结并最终崩溃(用chrome和firefox测试)。我尝试了一堆1000个链接标记,然后我下降到100左右,但仍然是同样的问题...当然,有10个或更少的标记我没有任何问题。

您是否已经遇到过类似的问题?如何优化Leaflet性能,以便我可以使用超过100个链接的CircleMarkers进行精确缩放(超过16级)?我也想知道为什么在缩放时表演会下降得那么糟糕,而标记量保持不变......

提前感谢您的回答,

Lenalys。

无法让PolylineDecorator插件在jsfiddle上运行。 但是这里是生成标记的代码:

地图初始化:

var map;

function initializeMap(){
  "use strict";

  var layer;
  var layer2;

  function layerUrl(key, layer) {
      return "http://wxs.ign.fr/" + key
          + "/geoportail/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&"
          + "LAYER=" + layer + "&STYLE=normal&TILEMATRIXSET=PM&"
          + "TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&FORMAT=image%2Fjpeg";
  }

  layer = L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', 
  {
    attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors',
    maxZoom: 18
  });

  layer2 = L.tileLayer(
    layerUrl(IGN_AMBIENTE_KEY, "GEOGRAPHICALGRIDSYSTEMS.MAPS"),
    {attribution: '&copy; <a href="http://www.ign.fr/">IGN</a>'}
  );

    var baseMaps = {
      "Terrestre": layer,
      "Bathymetrique": layer2
    };

    map = L.map('map', {
        layers: [layer],
        zoom: 8,
        center: [42.152796, 9.139150],
        zoomControl: false  
    });

   L.control.layers(baseMaps).addTo(map);

    //add zoom control with your options
    L.control.zoom({
         position:'topright' //topleft
    }).addTo(map);

    L.control.scale({
      position:'bottomleft',
      imperial : false
    }).addTo(map);


}

数据样本:

var jsonData = {&#34; 12&#34;:[{&#34; id_stm_device&#34;:&#34; 7&#34;,&#34; individual_name&#34;:&#34; cerf3& #34;&#34;纬度&#34;:&#34; 42.657283333333&#34;&#34;经度&#34;:&#34; 9.42362&#34;&#34;温度&#34; :空,&#34;脉冲&#34;:空,&#34;电池&#34;:&#34; 20&#34;&#34; DATE_TIME&#34;:&#34; 2015年3月17日15:37:12&#34;},     {&#34; id_stm_device&#34;:&#34; 7&#34;&#34; individual_name&#34;:&#34; cerf3&#34;&#34;纬度&#34;:&#34; 42.657381666667&#34;&#34;经度&#34;:&#34; 9.42365&#34;&#34;温度&#34;:空,&#34;脉冲&#34;:空,&#34 ;电池&#34;:&#34; 20&#34;,&#34; date_time&#34;:&#34; 2015-03-17 16:42:16&#34;},     {&#34; id_stm_device&#34;:&#34; 7&#34;&#34; individual_name&#34;:&#34; cerf3&#34;&#34;纬度&#34;:&#34; 42.657381666667&#34;&#34;经度&#34;:&#34; 9.4236933333333&#34;&#34;温度&#34;:空,&#34;脉冲&#34;:空,&#34 ;电池&#34;:&#34; 20&#34;,&#34; date_time&#34;:&#34; 2015-03-17 17:47:21&#34;},     {&#34; id_stm_device&#34;:&#34; 7&#34;&#34; individual_name&#34;:&#34; cerf3&#34;&#34;纬度&#34;:&#34; 42.657283333333&#34;&#34;经度&#34;:&#34; 9.4237383333333&#34;&#34;温度&#34;:空,&#34;脉冲&#34;:空,&#34 ;电池&#34;:&#34; 20&#34;,&#34; date_time&#34;:&#34; 2015-03-17 19:57:23&#34;}],     &#34; 13&#34;:[{&#34; id_stm_device&#34;:&#34; 8&#34;&#34; individual_name&#34;:&#34; cerf5&#34;&#34 ;纬度&#34;:&#34; 42.61683&#34;&#34;经度&#34;:&#34; 9.4804633333333&#34;&#34;温度&#34;:&#34; 17.45& #34;&#34;脉冲&#34;:空,&#34;电池&#34;:&#34; 80&#34;&#34; DATE_TIME&#34;:&#34; 2015-04- 08 07:45:20&#34;},     {&#34; id_stm_device&#34;:&#34; 8&#34;&#34; individual_name&#34;:&#34; cerf5&#34;&#34;纬度&#34;:&#34; 42.538858333333&#34;&#34;经度&#34;:&#34; 9.48169&#34;&#34;温度&#34;:&#34; 14.37&#34;&#34;脉冲&# 34;:null,&#34; battery&#34;:&#34; 80&#34;,&#34; date_time&#34;:&#34; 2015-04-08 08:00:29&#34;} ,     {&#34; id_stm_device&#34;:&#34; 8&#34;&#34; individual_name&#34;:&#34; cerf5&#34;&#34;纬度&#34;:&#34; 42.458748333333&#34;&#34;经度&#34;:&#34; 9.500225&#34;&#34;温度&#34;:&#34; 14.46&#34;&#34;脉冲&# 34;:null,&#34; battery&#34;:&#34; 80&#34;,&#34; date_time&#34;:&#34; 2015-04-08 08:15:49&#34;} ,     {&#34; id_stm_device&#34;:&#34; 8&#34;&#34; individual_name&#34;:&#34; cerf5&#34;&#34;纬度&#34;:&#34; 42.3302&#34;&#34;经度&#34;:&#34; 9.5374583333333&#34;&#34;温度&#34;:&#34; 15.19&#34;&#34;脉冲&# 34;:null,&#34; battery&#34;:&#34; 80&#34;,&#34; date_time&#34;:&#34; 2015-04-08 08:31:05&#34;} ,     {&#34; id_stm_device&#34;:&#34; 8&#34;&#34; individual_name&#34;:&#34; cerf5&#34;&#34;纬度&#34;:&#34; 42.170133333333&#34;&#34;经度&#34;:&#34; 9.5272116666667&#34;&#34;温度&#34;:&#34; 15.48&#34;&#34;脉冲&# 34;:null,&#34; battery&#34;:&#34; 80&#34;,&#34; date_time&#34;:&#34; 2015-04-08 08:46:20&#34;} ,     {&#34; id_stm_device&#34;:&#34; 8&#34;&#34; individual_name&#34;:&#34; cerf5&#34;&#34;纬度&#34;:&#34; 42.07959&#34;&#34;经度&#34;:&#34; 9.47688&#34;&#34;温度&#34;:&#34; 15.97&#34;&#34;脉冲&# 34;:null,&#34; battery&#34;:&#34; 80&#34;,&#34; date_time&#34;:&#34; 2015-04-08 09:01:31&#34;} ,     {&#34; id_stm_device&#34;:&#34; 8&#34;&#34; individual_name&#34;:&#34; cerf5&#34;&#34;纬度&#34;:&#34; 42.076163333333&#34;&#34;经度&#34;:&#34; 9.4828633333333&#34;&#34;温度&#34;:&#34; 20.42&#34;&#34;脉冲&# 34;:null,&#34; battery&#34;:&#34; 80&#34;,&#34; date_time&#34;:&#34; 2015-04-08 09:16:59&#34;} ,     {&#34; id_stm_device&#34;:&#34; 8&#34;&#34; individual_name&#34;:&#34; cerf5&#34;&#34;纬度&#34;:&#34; 42.07194&#34;&#34;经度&#34;:&#34; 9.4908866666667&#34;&#34;温度&#34;:&#34; 17.36&#34;&#34;脉冲&# 34;:null,&#34; battery&#34;:&#34; 80&#34;,&#34; date_time&#34;:&#34; 2015-04-08 09:32:17&#34;} ,     {&#34; id_stm_device&#34;:&#34; 8&#34;&#34; individual_name&#34;:&#34; cerf5&#34;&#34;纬度&#34;:&#34; 42.072583333333&#34;&#34;经度&#34;:&#34; 9.4901516666667&#34;&#34;温度&#34;:&#34; 17.36&#34;&#34;脉冲&# 34;:null,&#34; battery&#34;:&#34; 80&#34;,&#34; date_time&#34;:&#34; 2015-04-08 09:47:32&#34;} ,     {&#34; id_stm_device&#34;:&#34; 8&#34;&#34; individual_name&#34;:&#34; cerf5&#34;&#34;纬度&#34;:&#34; 42.07238&#34;&#34;经度&#34;:&#34; 9.4904266666667&#34;&#34;温度&#34;:&#34; 19.38&#34;&#34;脉冲&# 34;:null,&#34; battery&#34;:&#34; 80&#34;,&#34; date_time&#34;:&#34; 2015-04-08 10:02:42&#34;} ,     {&#34; id_stm_device&#34;:&#34; 8&#34;&#34; individual_name&#34;:&#34; cerf5&#34;&#34;纬度&#34;:&#34; 42.072298333333&#34;&#34;经度&#34;:&#34; 9.4904983333333&#34;&#34;温度&#34;:&#34; 17.46&#34;&#34;脉冲&# 34;:null,&#34; battery&#34;:&#34; 80&#34;,&#34; date_time&#34;:&#34; 2015-04-08 10:17:55&#34;} ,     {&#34; id_stm_device&#34;:&#34; 8&#34;&#34; individual_name&#34;:&#34; cerf5&#34;&#34;纬度&#34;:&#34; 42.095093333333&#34;&#34;经度&#34;:&#34; 9.5148383333333&#34;&#34;温度&#34;:&#34; 17.47&#34;&#34;脉冲&# 34;:null,&#34; battery&#34;:&#34; 80&#34;,&#34; date_time&#34;:&#34; 2015-04-08 10:33:12&#34;} ,     {&#34; id_stm_device&#34;:&#34; 8&#34;&#34; individual_name&#34;:&#34; cerf5&#34;&#34;纬度&#34;:&#34; 42.112881666667&#34;&#34;经度&#34;:&#34; 9.5133133333333&#34;&#34;温度&#34;:&#34; 19.3&#34;&#34;脉冲&# 34;:null,&#34; battery&#34;:&#34; 80&#34;,&#34; date_time&#34;:&#34; 2015-04-08 10:48:23&#34;} ,     {&#34; id_stm_device&#34;:&#34; 8&#34;&#34; individual_name&#34;:&#34; cerf5&#34;&#34;纬度&#34;:&#34; 42.112875&#34;&#34;经度&#34;:&#34; 9.513285&#34;&#34;温度&#34;:&#34; 22.71&#34;&#34;脉冲&# 34;:null,&#34; battery&#34;:&#34; 80&#34;,&#34; date_time&#34;:&#34; 2015-04-08 11:03:57&#34;} ,     {&#34; id_stm_device&#34;:&#34; 8&#34;&#34; individual_name&#34;:&#34; cerf5&#34;&#34;纬度&#34;:&#34; 42.141096666667&#34;&#34;经度&#34;:&#34; 9.5078216666667&#34;&#34;温度&#34;:&#34; 23.73&#34;&#34;脉冲&# 34;:null,&#34; battery&#34;:&#34; 80&#34;,&#34; date_time&#34;:&#34; 2015-04-08 11:19:12&#34;} ,     {&#34; id_stm_device&#34;:&#34; 8&#34;&#34; individual_name&#34;:&#34; cerf5&#34;&#34;纬度&#34;:&#34; 42.282186666667&#34;&#34;经度&#34;:&#34; 9.5505183333333&#34;&#34;温度&#34;:&#34; 18.97&#34;&#34;脉冲&# 34;:null,&#34; battery&#34;:&#34; 80&#34;,&#34; date_time&#34;:&#34; 2015-04-08 11:34:28&#34;} ,     {&#34; id_stm_device&#34;:&#34; 8&#34;&#34; individual_name&#34;:&#34; cerf5&#34;&#34;纬度&#34;:&#34; 42.405126666667&#34;&#34;经度&#34;:&#34; 9.531145&#34;&#34;温度&#34;:&#34; 20.71&#34;&#34;脉冲&# 34;:null,&#34; battery&#34;:&#34; 80&#34;,&#34; date_time&#34;:&#34; 2015-04-08 11:49:42&#34;} ,     {&#34; id_stm_device&#34;:&#34; 8&#34;&#34; individual_name&#34;:&#34; cerf5&#34;&#34;纬度&#34;:&#34; 42.482063333333&#34;&#34;经度&#34;:&#34; 9.480665&#34;&#34;温度&#34;:&#34; 21.7&#34;&#34;脉冲&# 34;:null,&#34; battery&#34;:&#34; 80&#34;,&#34; date_time&#34;:&#34; 2015-04-08 12:05:07&#34;} ]}

var oJSON = JSON.parse(jsonData);



var colors = [
    "#400080",
    "#008000",
    "#EC7600",
    "#E40341",
    "#0D5E5E",
    "#919191",
    "#FF3C9D",
    "#A70A0E",
    "#00BFBF",
    "#7171FF"
  ];

var classes  = [
    "color1",
    "color2",
    "color3",
    "color4",
    "color5",
    "color6",
    "color7",
    "color8",
    "color9",
    "color10"
]; 


var lastMarkers = [];
var layers = new Array();
var polyline; 
var decorator;

window.graphicsDevices = [];
var offsetLatitude = 0.003333;
var offsetLongitude = 0.011666;

Marker instanciation:

function printGPSOnMap(oJSON){
  var nbKeys = 0;

  for (var key in oJSON) {
    nbKeys++;

    var classe = classes[(key-1)%classes.length]; 
    var color = colors[(key-1)%colors.length];

    var positionInfo = [];

    if (oJSON.hasOwnProperty(key)) {

          var aInfo = oJSON[key];
          var marker;
          var latlngs = Array();

          var startMarker = lastMarkers[key];
          if(startMarker !== undefined && startMarker != null) {

            var myIcon = L.divIcon({className:  "myCircle "+classe, iconSize : [ 20, 20 ] });
            startMarker.setIcon(myIcon);
            latlngs.push(startMarker.getLatLng());
          }
          for(var i = 0; i < aInfo.length; i++) {
               var oInfos = aInfo[i];
               var sIdIndividual = oInfos["id_individual"];
               var sLongitude = oInfos["longitude"];
               var sLatitude = oInfos["latitude"];
               var sTemperature = oInfos["temperature"];
               var sPulse = oInfos["pulse"];
               var sBattery = oInfos["battery"];
               var sDatetime = oInfos["date_time"];
               var sIndividualName = oInfos["individual_name"];
               var id_device = oInfos["id_stm_device"];

               var popupMsg = "...";

               latlngs.push(L.marker([sLatitude,sLongitude]).getLatLng());

               marker = new MyCustomMarker([sLatitude,sLongitude], {
                                        icon : L.divIcon({ 
                                           className : "myCircle "+classe + ((i == aInfo.length-1) ? ' myCircleEnd' : ''),
                                           iconSize : [ 20, 20 ]
                                        })
                                        });
                                        marker.bindPopup(popupMsg, {
                                               showOnMouseOver: true 
                                        });
                                        marker.bindLabel(key, {
                                               noHide: true,
                                               direction: 'middle',
                                               offset: [offset[0], offset[1]]
                                        });
              positionInfo.push(marker);
         }

         lastMarkers[key] = marker; 
      }

      if(latlngs.length > 1)
      {

      polyline = L.polyline(latlngs, {className: classe, weight: 2,opacity: 0.4}).addTo(map);
      decorator = L.polylineDecorator(polyline, {
        patterns: [
            // define a pattern of 10px-wide arrows, repeated every 20px on the line 
            {offset: 0, repeat: '25px', symbol: new L.Symbol.arrowHead({pixelSize: 10, pathOptions: {fillOpacity:        
                 0.76, color: color, weight: 1}})}
        ]}).addTo(map);
     }

     if(!window.graphicsDevices.hasOwnProperty(key))
        window.graphicsDevices[key] = [];
     for(var i = 0; i < positionInfo.length; i++) {
        window.graphicsDevices[key].push(positionInfo[i]); 
        positionInfo[i].addTo(map);
        if(latlngs.length > 1){
          window.graphicsDevices[key].push(polyline);
          polyline.addTo(map);
          window.graphicsDevices[key].push(decorator);
          decorator.addTo(map);
        }
      } 
  }//foreach key

}

自定义标记的代码:

var MyCustomMarker = L.Marker.extend({

    bindPopup: function(htmlContent, options) {
    if (options && options.showOnMouseOver) {
      // call the super method
      L.Marker.prototype.bindPopup.apply(this, [htmlContent, options]);
      // unbind the click event
      this.off("click", this.openPopup, this);
      // bind to mouse over
      this.on("mouseover", function(e) {
        // get the element that the mouse hovered onto
        var target = e.originalEvent.fromElement || e.originalEvent.relatedTarget;
        var parent = this._getParent(target, "leaflet-popup");
        // check to see if the element is a popup, and if it is this marker's popup
        if (parent == this._popup._container)
          return true;
        // show the popup
        this.openPopup();
      }, this);
      // and mouse out
      this.on("mouseout", function(e) {
        // get the element that the mouse hovered onto
        var target = e.originalEvent.toElement || e.originalEvent.relatedTarget;
        // check to see if the element is a popup
        if (this._getParent(target, "leaflet-popup")) {
          L.DomEvent.on(this._popup._container, "mouseout", this._popupMouseOut, this);
          return true;
        }
        // hide the popup
        this.closePopup();
      }, this);
    }
  },
  _popupMouseOut: function(e) {

    // detach the event
    L.DomEvent.off(this._popup, "mouseout", this._popupMouseOut, this);
    // get the element that the mouse hovered onto
    var target = e.toElement || e.relatedTarget;
    // check to see if the element is a popup
    if (this._getParent(target, "leaflet-popup"))
      return true;
    // check to see if the marker was hovered back onto
    if (target == this._icon)
      return true;
    // hide the popup
    this.closePopup();
  },

  _getParent: function(element, className) {

    var parent = null;

    if(element != null) parent = element.parentNode;

    while (parent != null) {
      if (parent.className && L.DomUtil.hasClass(parent, className))
        return parent;
      parent = parent.parentNode;
    }
    return false;
  }
});

1 个答案:

答案 0 :(得分:0)

您是否在canvas mode评估了效果? 在初始化传单地图容器之前使用cur。可能会帮助您。