Recently set up Leaflet map with GeoDjango / rest_framework_gis and have limited results with Pagination, but the result still seems to have Leaflet cumulatively processing every marker it receives, not just what's in view, which lags and eventually crashes browsers. In the comment I was advised to address this with JS. This makes sense as it's front end, but how can we do this?
The JS from this tutorial:
async function render_markers() {
const markers = await load_markers();
L.geoJSON(markers)
    .bindPopup((layer) => layer.feature.properties.name)
    .addTo(map);
}
Can we write some kind of function that'll do something along the lines of if there are over n entries drop the furthest from bbox view?
The specific line seems to be .addTo(map);. Is there some kind of .removeFrom() or similar in JS?
on every move you will add same markers again and again as long as they are in the bounds. At some point there will be to much markers on the map and the browser will crash.
You need to do following:
This code is not tested! I use a different version in my project and this one works. also I think you need to replace the ajax / jquery request with vanilla requests like fetch
var runningRequests = [];
var allLayers = [];
function initLoad() {
    // add event listeners to load the new layers
    map.on('moveend',mapMove);
    map.on('zoomend',mapMove);
    // load initial the layers
    if (map.getZoom() > 12) {
        loadLayers(map);
    }
}
function mapMove() {
    // only load new layers if higher then zoom level 12
    if (map.getZoom() > 12) {
        // only load new layers if the map bounds are not in the loaded bounds anymore
        if (areaBounds.contains(map.getBounds()) === false) {
            loadLayers()
        }
    }
}
function loadLayers() {
    // current bounds extending by 15%
    areaBounds = map.getBounds().pad(0.15);
    // abort all running requests
    if(runningRequests.length > 0){
        for (var i in runningRequests) {
            runningRequests[i].abort(); // jquery request abort -> not working for vanilla requests
            delete runningRequests[i];
        }
    }
    var req = $.ajax(options).done(function(json){  // jquery load request -> not working for vanilla requests
        var layersToRemove = allLayers; // maybe this doesn't break the reference then you need to destroy them
        
        len = json.length;
        
        var layersToAdd = [];
        json.forEach((obj)=> {
            var coords = obj.coordinates;
            // filter all layers out, which has the same coordinates as in the json
            var filteredLayers = layersToRemove.filter(function (layer) { return !layer.getLatLng().equals([coords[1], coords[0]]) });
            
            if(filteredLayers.length === layersToRemove.length){
                // no layer was removed, so we know that it is a new layer
                layersToAdd.push(obj);
            }
            
            layersToRemove = filteredLayers;
        });
        
        // remove all layers that are not in the result anymore
        layersToRemove.forEach((layer)=>{;
            map.removeLayer(layer);
        }
        
        addLayer(layersToAdd);
    });
    runningRequests.push(req);
}
function addLayer(geoJsonLayers){
    
    // the data are in geojson format, so we add them to a featureCollection, so we can load it with L.geoJSON(featureCollection)
    var featureCollection = {
      "type": "FeatureCollection",
      "features": []
    };
    featureCollection.features = geoJsonLayers;
    
    // add layers to the map
    var geoJson = L.geoJSON(featureCollection)
        .bindPopup((layer) => layer.feature.properties.name)
        .addTo(map);
    
    // add the new layers to the allLayers array
    geoJson.getLayers().forEach((layer)=>{
        allLayers.push(layer);
    });
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With