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