6

I am working on a Leaflet app which will be displaying five layers with about 1k points each.

For our purpose (basically in order to locate most of the points near to a road) we don't want to use clustering; instead, we want to filter the amount of points on each zoom level, so there are never too many points on the map at any given time (say no more than a few hundred).

I have tried two different approaches on this issue. First, filtering the points on each zoom level according to a field on the GeoJSON data (Z_level).

Second has been creating different GeoJSON files, one for every possible zoom level we'll be using.

I've found that filtering is a little bit (10-20%) faster than layer reloading, but am finding a big hit in performance when zooming in after zoom level 13 or 14 when there are a few thousands of points loaded (not rendered). Even more surprising for me, the biggest performance hit is when zooming out from level 14 to 13 (about 8 seconds) and even more when zooming from 13 to 12 (almost 12 seconds!!).

The rest of zoom transitions are taking some 2 to 3 seconds, which is acceptable.

Here is the basis of the code I'm using for each case:

1) Filtering:

    // Filtering points for each Layer 

var towns = L.geoJson(null, {

   filter: function(feature) {
        if(feature.properties.Z_Level <= mapZoom)
            return true;  
      },
  pointToLayer: function (feature, latlng) {
    return L.circleMarker(latlng, {
      title: feature.properties.Name
       })
  }
});

map.on("zoomend", function(e) {
            map.removeLayer(towns);
            towns = L.geoJson(data, {
               filter: function(feature) {
                    if(feature.properties.Z_Level <= mapZoom)
                        return true;  
                  },
               pointToLayer: function (feature, latlng) {
                    return L.circleMarker(latlng, {
                        title: feature.properties.Name
                        });
                    }
                }

            map.addLayer(towns);    
            });

And here is the second one (layers):

// Different layers for each Zoom Level

for(i=minZoom; i<=maxZoom;i++){

  towns[i] = L.geoJson(null, {

  pointToLayer: function (feature, latlng) {
    return L.circleMarker(latlng, {
      title: feature.properties.Name
       })
  }
});
}

map.on("zoomstart", function(e) {
    mapOldZoom = map.getZoom();
 });

map.on("zoomend", function(e) {

    mapZoom = map.getZoom();

       if (map.hasLayer(towns)) {

                map.removeLayer(towns[mapOldZoom]);
                map.addLayer(towns[mapZoom]);
                } 
 });

Can anyone send any ideas on which would be the best approach? Am I losing other ways to improve speed on a case like this?

  • 1
    It sounds like you are seeking a Code Review. – PolyGeo Jun 26 '17 at 22:11
  • Thanks mate, I didn't know that part of the site! – O' Bieito Jun 26 '17 at 22:26
  • Do you have to use Leaflet? I find Mapbox GL JS handles this very well (tens of thousands of points, coming from GeoJSON, clustered with the native style spec so that more points are revealed on each zoom). Very fluid. – Richard Law Jul 1 '17 at 22:50
  • I could try mapbox though we don't want to use a technology that could be closed, removed or have its policy changed at any moment so we prefer leaflet. Also I don't want to use clustering in this one. I found another solution for this one. – O' Bieito Jul 3 '17 at 9:42
1

I finally solved this by adding in the filter a check to see if points are inside the map's view box, so only points in the current view are rendered.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.