Joey Lawrence
Joey Lawrence

Reputation: 71

Large JSON URL loading too slowly in LeafLet JS Map

Warning: novice here

I am building a real estate website in PHP. I am now adding a map view via LeafLetJs which is all JavaScript. I have my map setup and all properties are coming in correctly. My issue is that the page takes about 17 seconds to load. It only loads around 500 properties instead of the 2000 being supplied in the json url. I believe it is timing out as the json data is pretty large (30mb).

What is the proper way to populate a map quickly? Here is my code:

var url =
  "https://api.bridgedataoutput.com/api/v2/OData/actris/Property/replication?access_token=(TokenHere)&$top=2000";
var map = L.map("map", { tap: false }).setView([30.26, -97.74], 11);
var markers = L.markerClusterGroup();
$(document).ready(function () {
  $.ajax({
    url: url,
    dataType: "json",
    error: function () {
      console.log("JSON FAILED for data");
    },
    success: function (results) {
      const numberFormatter = new Intl.NumberFormat("en-US", {
        style: "currency",
        currency: "USD",
        minimumFractionDigits: 0,
      });
      var markers = L.markerClusterGroup();
      var cartItemsList = document.getElementById("cartItemsList");
      results.value.forEach(function (element) {
        //cartItemsList.insertAdjacentHTML( 'beforeend',"<li>" + element.UnparsedAddress + " : " + element.Longitude+ " : " + element.Latitude+ " </li>");
        var marker = L.marker([element.Latitude, element.Longitude]).bindPopup(
          '<a href="property.php?id=' + element.ListingId +
            '"><div class="card"><img class="card-img-top" src="' + element.Media[0].MediaURL +
            '" style="height:160px;max-height:160px;object-fit: scale-down;"><div class="d-inline-flex p-2 justify-content-between align-items-start"><div class="rp-1 bd-highlight">' +
            element.StreetNumber + " " + element.StreetName + " " +
            element.StreetSuffix + "<br>" + element.City + ", " +
            element.StateOrProvince + " " + element.PostalCode +
            '</div><div class="lp-1 bd-highlight" style="text-align: right;">' +
            numberFormatter.format(element.ListPrice) +
            " <br> ID " + element.ListingId +
            "</div></div></div></a>"
        );
        markers.addLayer(marker);
        map.addLayer(markers);
      }); // end of forEach
    }, // end of success fn
  }); // end of Ajax call
}); // end of $(document).ready() function

L.tileLayer(
  "https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token=my_mapbox_access_token",
  {
    maxZoom: 18,
    attribution:
      'Map data &copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, ' +
      'Imagery © <a href="https://www.mapbox.com/">Mapbox</a>',
    id: "mapbox/streets-v11",
  }
).addTo(map);

markers.addLayer(marker);
map.fitBounds(markers.getBounds());

Upvotes: 1

Views: 1617

Answers (2)

Joey Lawrence
Joey Lawrence

Reputation: 71

Turns out the json URL was taking too much time to load. I was able to use a select rule and only pull back the fields I needed. Now the map loads 2000 results in just a few seconds.

Upvotes: 0

ghybs
ghybs

Reputation: 53280

Most probably there are 2 performance bottlenecks:

  1. When loading 30MB of data, I would expect it takes a few seconds on most connections. But it is strangely heavy just for 2,000 features.
  2. When adding a lot of Markers into MarkerClusterGroup, if you do so individually and the MCG is on the map, it will perform a lot of computations, delaying rendering by several seconds. Use addLayers method (note the s at the end) once with an array of all your Markers:

Bulk adding and removing Markers

addLayers and removeLayers are bulk methods for adding and removing markers and should be favoured over the single versions when doing bulk addition/removal of markers. Each takes an array of markers.

In your case it could be something like: (in your success callback)

const arrayOfMarkers = results.value.map(element => 
  L.marker([element.Latitude, element.Longitude]).bindPopup(/* etc. */)
);
const mcg = L.markerClusterGroup();
mcg.addLayers(arrayOfMarkers);
mcg.addTo(map);

As for the discrepancy between the number of displayed features, it might be due to the computation delay, but I rather suspect you may not receive as many features as you think: simply log results.value.length to make sure.

Upvotes: 1

Related Questions