【问题标题】:Performance issue when zooming (Leaflet 0.7.3)缩放时的性能问题(传单 0.7.3)
【发布时间】:2015-05-06 10:04:18
【问题描述】:

我遇到了 Leaflet(0.7.3 版)的性能问题。我正在使用一个 OSM 地图,我用它来显示一堆由装饰折线链接的 CircleMarkers(每 25 像素带有箭头图案)。加载需要一点时间,但主要问题是,当我缩放地图时,我开始面临严重滞后(从缩放级别 16 开始),并且超过一定限制(大部分时间说 18),浏览器只是冻结并最终崩溃(用chrome和firefox测试)。我尝试了一堆 1,000 个链接标记,然后我下降到一组大约 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 ={"12":[{"id_stm_device":"7","individual_name":"cerf3","latitude":"42.657283333333","longitude":"9.42362","temperature":null ,"脉冲":null,"电池":"20","date_time":"2015-03-17 15:37:12"}, {"id_stm_device":"7","individual_name":"cerf3","latitude":"42.657381666667","longitude":"9.42365","temperature":null,"pulse":null,"battery":" 20","date_time":"2015-03-17 16:42:16"}, {"id_stm_device":"7","individual_name":"cerf3","latitude":"42.657381666667","longitude":"9.4236933333333","temperature":null,"pulse":null,"battery":" 20","date_time":"2015-03-17 17:47:21"}, {"id_stm_device":"7","individual_name":"cerf3","latitude":"42.657283333333","longitude":"9.4237383333333","temperature":null,"pulse":null,"battery":" 20","date_time":"2015-03-17 19:57:23"}], "13":[{"id_stm_device":"8","individual_name":"cerf5","latitude":"42.61683","longitude":"9.4804633333333","temperature":"17.45","pulse":空,"电池":"80","date_time":"2015-04-08 07:45:20"}, {"id_stm_device":"8","individual_name":"cerf5","latitude":"42.538858333333","longitude":"9.48169","temperature":"14.37","pulse":null,"battery" :"80","date_time":"2015-04-08 08:00:29"}, {"id_stm_device":"8","individual_name":"cerf5","latitude":"42.458748333333","longitude":"9.500225","temperature":"14.46","pulse":null,"battery" :"80","date_time":"2015-04-08 08:15:49"}, {"id_stm_device":"8","individual_name":"cerf5","latitude":"42.3302","longitude":"9.5374583333333","temperature":"15.19","pulse":null,"battery" :"80","date_time":"2015-04-08 08:31:05"}, {"id_stm_device":"8","individual_name":"cerf5","latitude":"42.170133333333","longitude":"9.5272116666667","temperature":"15.48","pulse":null,"battery" :"80","date_time":"2015-04-08 08:46:20"}, {"id_stm_device":"8","individual_name":"cerf5","latitude":"42.07959","longitude":"9.47688","temperature":"15.97","pulse":null,"battery" :"80","date_time":"2015-04-08 09:01:31"}, {"id_stm_device":"8","individual_name":"cerf5","latitude":"42.076163333333","longitude":"9.4828633333333","temperature":"20.42","pulse":null,"battery" :"80","date_time":"2015-04-08 09:16:59"}, {"id_stm_device":"8","individual_name":"cerf5","latitude":"42.07194","longitude":"9.4908866666667","temperature":"17.36","pulse":null,"battery" :"80","date_time":"2015-04-08 09:32:17"}, {"id_stm_device":"8","individual_name":"cerf5","latitude":"42.072583333333","longitude":"9.4901516666667","temperature":"17.36","pulse":null,"battery" :"80","date_time":"2015-04-08 09:47:32"}, {"id_stm_device":"8","individual_name":"cerf5","latitude":"42.07238","longitude":"9.4904266666667","temperature":"19.38","pulse":null,"battery" :"80","date_time":"2015-04-08 10:02:42"}, {"id_stm_device":"8","individual_name":"cerf5","latitude":"42.072298333333","longitude":"9.4904983333333","temperature":"17.46","pulse":null,"battery" :"80","date_time":"2015-04-08 10:17:55"}, {"id_stm_device":"8","individual_name":"cerf5","latitude":"42.095093333333","longitude":"9.5148383333333","temperature":"17.47","pulse":null,"battery" :"80","date_time":"2015-04-08 10:33:12"}, {"id_stm_device":"8","individual_name":"cerf5","latitude":"42.112881666667","longitude":"9.5133133333333","temperature":"19.3","pulse":null,"battery" :"80","date_time":"2015-04-08 10:48:23"}, {"id_stm_device":"8","individual_name":"cerf5","latitude":"42.112875","longitude":"9.513285","temperature":"22.71","pulse":null,"battery" :"80","date_time":"2015-04-08 11:03:57"}, {"id_stm_device":"8","individual_name":"cerf5","latitude":"42.141096666667","longitude":"9.5078216666667","temperature":"23.73","pulse":null,"battery" :"80","date_time":"2015-04-08 11:19:12"}, {"id_stm_device":"8","individual_name":"cerf5","latitude":"42.282186666667","longitude":"9.5505183333333","temperature":"18.97","pulse":null,"battery" :"80","date_time":"2015-04-08 11:34:28"}, {"id_stm_device":"8","individual_name":"cerf5","latitude":"42.405126666667","longitude":"9.531145","temperature":"20.71","pulse":null,"battery" :"80","date_time":"2015-04-08 11:49:42"}, {"id_stm_device":"8","individual_name":"cerf5","latitude":"42.482063333333","longitude":"9.480665","temperature":"21.7","pulse":null,"battery" :"80","date_time":"2015-04-08 12:05:07"}]}

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;

标记实例化:

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;
  }
});

【问题讨论】:

  • 这听起来更像是相关代码的问题,而不是一般的传单问题。您是否可以发布一些代码,最好是在 jsfiddle 或类似网站上?
  • 我用生成标记的代码编辑我的帖子 :)

标签: performance leaflet openstreetmap zooming


【解决方案1】:

您是否评估过canvas mode 的性能? 在初始化您的传单地图容器之前使用L_PREFER_CANVAS = true。也许可以帮助您。

【讨论】:

  • 我已经尝试过这个 sn-p,尽管性能提升很小,但地图在一些缩放后仍然滞后和冻结。我使用自定义标记而不是 circleMarker,也许问题可能来自它?
  • 我在帖子中添加了“MyCustomMarker”对象的代码。
  • 您是否尝试过在标记之间使用未装饰的香草折线而不是您现在正在做的事情?尝试了解瓶颈在哪里。
  • 应该早点尝试...不错的猜测,删除装饰器解决了问题,现在无论缩放级别如何,地图都是平滑的。这是一个插件,所以我应该本能地先去看看它。无论如何,感谢您的贡献,您知道如何在不牺牲性能的情况下在两个标记之间添加箭头链接吗?
  • 最终我发现了这个:github.com/makinacorpus/Leaflet.TextPath 并且它工作得很好!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-06-23
  • 1970-01-01
  • 2015-07-21
  • 2017-06-14
  • 2021-11-16
相关资源
最近更新 更多