Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to improve performance on inserting a lot of features into a map with leaflet.js

With the prototype code below I'm adding a lot of features in steps into an osm. I'm loading about 8500 multipolygon features into it. Some of them have a lot of coordinates so that's round about 150MB of textual data in total. Loading them one by one leads to a crash of the browser. Loading it in chunks works but it is not fast either. Especially if you want to scroll or zoom after the loading has finished. I'm a bit shy about loading it all in one go as that's 150MB of data.

What options do I have to improve the experience? To be clear: I'm not talking about the loading itself. I'm talking about the rendering of the map with the features.

Here is the code stub:

addToMap = function (id, totalCount) {
    var idTo = id+99;
    jQuery.get('getData.php', {id: id, idTo: idTo}, function (result) {
        var geojson;

        function onEachFeature(feature, layer) {
            layer.on({
                mouseover: highlightFeature,
                mouseout: resetHighlight,
                click: zoomToFeature
            });
        }

        function resetHighlight(e) {
            geojson.resetStyle(e.target);
            info.update();
        }

        geojson = L.geoJson(result, {
            style: getStyle,
            onEachFeature: onEachFeature
        }).addTo(map);

        if (id < totalCount) {
            jQuery('#count').html(idTo+' of '+totalCount);
            addToMap(idTo+1, totalCount);
        } else {
            jQuery('#loader').remove();
        }
    }, 'json');
}
like image 991
steros Avatar asked Mar 11 '23 09:03

steros


2 Answers

The secret to render a lot of stuff very very fast is... to not render a lot of stuff.

This might seem contradictory, but in reality it's very simple. You don't need to render everything, you just need to render:

  • Stuff which is inside the screen (plus a bit of an out-of-the-screen margin)
  • Stuff which measures less than one pixel (because nobody will ever notice subpixel artifacts)

By default, Leaflet does in fact simplify the vector geometries to save some time (douglas-peucker up to a couple of pixels), but it simplifies all the geometries (which is computationally expensive) and renders based only in the geometries' bounding boxes (which renders big geometries which are not visible, and renders all the points of big geometries for which only a tiny bit is visible).

Fortunately a couple of recent developments help with that: vector tiles and geojson-vt. Do read https://www.mapbox.com/blog/introducing-geojson-vt/

The general idea is that the dataset is subject to a precomputation step (which takes a non-trivial amount of time but can be done off-thread), slicing the data up into tiles. Slicing in tiles means that only the visible part of big geometries will be shown, saving huge amounts of time. It will also run some line simplification, depending on the level of the tile pyramid.

These map tiles follow the same standard than raster tiles, so the visibility algorithms can be shared around.

To the best of my knowledge, there is only one working implementation of geojson-vt and Leaflet: Leaflet.VectorGrid (or you can check the plugins list, which might contain more related plugins in the future). I suggest you have a look at it.

like image 111
IvanSanchez Avatar answered Apr 24 '23 20:04

IvanSanchez


In addition to the other answers:

  • Convert your GeoJson to TopoJson to reduce the size of it. Here is one utility to do it - https://github.com/topojson/topojson

  • Based on your zoom level, display only parts of the features that are important or large enough. (as IvanSanchez wrote)

like image 22
Alex Parij Avatar answered Apr 24 '23 20:04

Alex Parij