What can be done to prevent Leaflet from processing markers that fall outside of its bounding box?

I recently set up a Leaflet map with GeoDjango and rest_framework_gis, but I am facing issues with limited results and pagination. The map seems to process every marker it receives cumulatively, leading to lagging and browser crashes. I was advised in a comment to address this issue with JavaScript. While it makes sense to handle this on the front end, I am unsure how to proceed.

I found a tutorial that includes the following JavaScript code:

async function render_markers() {
const markers = await load_markers();
L.geoJSON(markers)
    .bindPopup((layer) => layer.feature.properties.name)
    .addTo(map);
}

Is there a way to write a function that will remove markers from view if there are too many entries outside of the bounding box? I suspect that the key lies in the line .addTo(map);. Is there an equivalent method like .removeFrom() in JavaScript?

Answer №1

Each move will result in the continuous addition of markers within the boundaries, potentially leading to map overload and browser crashing.

To prevent this, consider the following steps:

  1. Implement a check for optimal zoom levels, advising against loading entries below 12 to avoid exceeding request size limits (optional).
  2. Load only new markers that are not already within the current bounds.
  3. Terminate any ongoing requests immediately.
  4. Create a request with extended bounds (10% increase) to optimize marker loading frequency.
  5. Upon completing the request, transfer existing layers to an array, filtering out those present in the request results. The remaining layers in the array need removal while the new ones must be added to the map.

Note: This code has not been tested. It is recommended to replace Ajax/jQuery requests with vanilla fetch requests.

var runningRequests = [];
var allLayers = [];

function initLoad() {
    // Add event listeners to load new layers
    map.on('moveend',mapMove);
    map.on('zoomend',mapMove);

    // Load initial layers
    if (map.getZoom() > 12) {
        loadLayers(map);
    }
}

function mapMove() {
    if (map.getZoom() > 12) {
        if (areaBounds.contains(map.getBounds()) === false) {
            loadLayers()
        }
    }
}

function loadLayers() {
    areaBounds = map.getBounds().pad(0.15);

    if(runningRequests.length > 0){
        for (var i in runningRequests) {
            runningRequests[i].abort(); 
            delete runningRequests[i];
        }
    }

    var req = $.ajax(options).done(function(json) {  
        var layersToRemove = allLayers; 
        
        len = json.length;
        
        var layersToAdd = [];

        json.forEach((obj) => {
            var coords = obj.coordinates;
            var filteredLayers = layersToRemove.filter(function (layer) { return !layer.getLatLng().equals([coords[1], coords[0]]) });
            
            if(filteredLayers.length === layersToRemove.length){
                layersToAdd.push(obj);
            }
            
            layersToRemove = filteredLayers;
        });
        
        layersToRemove.forEach((layer) => {
            map.removeLayer(layer);
        });
        
        addLayer(layersToAdd);

    });

    runningRequests.push(req);
}

function addLayer(geoJsonLayers){
    
    var featureCollection = {
      "type": "FeatureCollection",
      "features": []
    };
    featureCollection.features = geoJsonLayers;
    
    var geoJson = L.geoJSON(featureCollection)
        .bindPopup((layer) => layer.feature.properties.name)
        .addTo(map);
    
    geoJson.getLayers().forEach((layer) => {
        allLayers.push(layer);
    });

}

Answer №2

To determine if a marker falls within the current bbox, we can run a simple test and then take appropriate action.

function checkBoundaries(coord){
  let bound = map.getBounds(),
  bbox = [bound._southWest.lat, bound._southWest.lng, bound._northEast.lat, bound._northEast.lng]
  return (coord[0] > bbox[0] && coord[0] < bbox[2] && coord[1] > bbox[1] && coord[1] < bbox[3]) ? true : false
}
checkBoundaries([ 50.15, 0.1]) // Is London visible on the screen?   

Answer №3

After gaining a deeper understanding of my requirements, I successfully addressed this issue. It is advisable to clear all existing markers before adding new ones from a fresh response by incorporating the clearMarkers() function or something similar:

async function load_markers() {
const markers_data = `/api/markers/?in_bbox=${map.getBounds().toBBoxString()}`
const result = await fetch(markers_data)
const geojson_data = await result.json()
clearMarkers();
return geojson_data
}

function clearMarkers() {
  layerGroup.clearLayers();
}

Additionally, it might be beneficial to set a limit on the number of entries per response at the backend.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Babeljs encountered an error: TypeError - The super expression should be a function or null, not undefined

Currently, my project involves implementing multiple-files inheritance in ES6 using Node.js and Babel. Babel is used to convert the ES6 code to ES5 since Node does not fully support ES6 yet. Import/export statements are used to connect the different files ...

Best practices for aligning the widths of input-group-addon elements

Hey there, I'm working with an HTML file that has 3 input options. Here's a snippet: <script type="text/ng-template" id="dashboard_assigngroup_popup.html"> <div class="modal-header modal-header2"> <h3 class="modal-tit ...

Screening strings and arrays based on multiple criteria

My code is below and I am trying to have the bot check for two specific conditions in the user's message. The message must contain "how" plus either "doing" or "bread". It works perfectly when using only "doing" but not when adding the "bread" conditi ...

Pulling information from a database query to store it within a JavaScript variable

Using Ajax/JQuery, I successfully send the variable ($name) from page1.php to page2.php without refreshing the page. When the submit button is clicked, it sends me the var $name effectively. Additionally, in my JavaScript library for charts (AmCharts), the ...

What is the reason objects cannot be compared in JavaScript?

I have a straightforward code snippet here. Its purpose is to authenticate the user against the author of the post and grant the authenticated user access to edit the post. exports.edit = function(req, res){ Post.findById(req.params.post_id, function ...

Failure to post in jQuery and PHP

I'm facing a slightly complex issue involving jQuery and PHP on my index.php file. The page makes a call to a javascript function called getCalls(). function getCalls() { $('#transportDiv').load('getCalls.php'); } The getCall ...

Issue in Jquery: Unable to load the corresponding pages when toggling the checkbox on and off

I am facing an issue with a checkbox and calling different php pages based on the status of the checkbox. Currently, the code works only for checked checkboxes. I'm not sure why it's not working for unchecked checkboxes as well. <script type ...

RadScheduler refresh rate

Currently I am incorporating RadScheduler into my project. The scheduler requires a regular update, so I have implemented a JavaScript function with an interval to call rebind() on the RadScheduler every 60 seconds. However, an issue arises when the user o ...

Guide to successfully implement a POST action using jquery/ajax Colorbox! Check out the demo here

I stumbled upon a colorbox tutorial and attempted to replicate it with a POST action, but unfortunately, it just continues to load. Check out this fiddle The button represents the problematic POST action, while the text link is the original example that ...

Indeed, conditional validation is essential

I have encountered an issue with my schema validation where I am trying to validate one field based on another. For example, if the carType is "SUV", then the maximum number of passengers should be 6; otherwise, it should be 4. However, despite setting u ...

Discover a scenario in which an identification number is contained within an array

For my Node.js + MongoDB project, I am utilizing sails.js and am currently faced with the challenge of loading all the groups associated with a particular user. Each Group object contains an array of user IDs as follows: Group { users: array } I' ...

When utilizing res.redirect in Express, an error is triggered stating "Uncaught SyntaxError: Unexpected token <""

Utilizing Node.js, Express, Socket.io, firebase admin+auth, and Handlebars. An error Uncaught SyntaxError: Unexpected token < keeps popping up. Whenever I use res.redirect('/login');, I encounter the error. It disappears when I remove res.re ...

Retrieving Information with the Fetch API in Node.js and Storing it in a MongoDB Database

I'm a newcomer to mongooseDB and am currently experimenting with inserting data from an API into the database. It successfully creates the Collection, but unfortunately it is not generating the documents. Any suggestions on what I might be doing incor ...

Navigate a user upon completion of an update

My webpage requires users to click an update link, which triggers a process of fetching data from an API that takes a few minutes. I don't want users to have to constantly refresh the page to know when the process is complete and they can continue. Is ...

Error: The property 'case sensitive routing' cannot be accessed because it is undefined

Task at hand: Running ExpressJS port using Node.js, nodemon, and lib. Operating System: Windows 10 Home x64 Node.JS Version: Lts The Challenge: Getting the ExpressJS port to run successfully. Current Issue: Encountering an internal file error, potentiall ...

Use Google script to input drop down options directly into a Google spreadsheet

After gathering coding advice from various StackOverflow examples, I've hit a roadblock while attempting to take my script to the next level. The task seems simple enough, but for some reason, I just can't figure it out. Here's the situati ...

Build a brand new root component in Vue JS

I am facing a challenge with destroying and re-creating the root application component. Below is my template structure: <div id="app"> {{ num }} </div> Here is the code I have implemented: if (app) { app.$destroy(); } else { ...

The error message "TypeError Cannot read properties of undefined (reading 'backdrop') - bootstrap v5.2.1 modal" is indicating that there is an

While working with the bootstrap modal, an error has been encountered ( TypeError Cannot read properties of undefined (reading 'backdrop') ), which has been logged in our bug tracker. However, attempts to replicate this error have been unsuccessf ...

HTML and JavaScript - Facing issues rendering HTML content during the conversion process from Markdown format

In this particular scenario, my goal is to transform the content inside #fileDisplayArea into markdown format. However, I am encountering an issue where the HTML code within the div element is not being rendered. <div id="fileDisplayArea"># Title ...

Adding JSON data to an array in Angular JS using the push method

I am encountering difficulties with adding data to an existing array. Currently, I have set up a table to display the data, but I want to also include the data in the table when a user enters an 8-digit barcode. Factory angular.module('app.pickU ...