[GIS] Resizing Leaflet CircleMarkers after zoom level changes

leafletmarkers

I am trying to find a way to have my CircleMarkers resize themselves after zooming in or out so that they scale properly with the map. So far, I have tried firing map.InvalidateSize() on the zoomend event but that does not seem to have any effect. Refreshing the feature layer also does not change the behavior. You can access my map at this link (sorry for the untrusted certificate).

My ultimate goal is for the circle markers to be reduced in size as the user zooms into the map, and then increase in size as the user zooms out.

Below is my code.

    var map = L.map('map',{ zoomControl:false, attributionControl: false, center: [38.980817, -98.760076], zoom: 4});
    L.tileLayer("https://cartodb-basemaps-b.global.ssl.fastly.net/dark_all/{z}/{x}/{y}.png", {maxZoom: 20, openLegendOnLoad: false, attribution:''}).addTo(map)
    var featureLayer = new L.featureGroup().addTo(map);
    function getZoomLevel() {
        map.on('zoomend', function() {
            map.invalidateSize();
        });
        return map.getZoom();
    };
    fetch('https://craftfamily.ddns.net/data')
      .then(response => {
        return response.json()
      })
      .then(data => {
        for (var key in data.recordset) {
          //console.log(key, data.recordset[key]);
          var lat = data.recordset[key].LATITUDE;
          var lon = data.recordset[key].LONGITUDE;
          var name = data.recordset[key].NAME;
          var location = data.recordset[key].LOCATION;
          var ticker = data.recordset[key].TICKER;
          var price = data.recordset[key].PRICE;
          var change = parseFloat(data.recordset[key].CHANGE).toFixed(2);
          var marker = L.circle([lat, lon], price*10000/getZoomLevel()).bindPopup("<b>"+name+" ("+ticker+")</b><br>$"+price + " (" + change +")<br>"+location+"<br>"+lat+", "+lon).addTo(map);
        }
      })
      .catch(err => {
      });

Best Answer

Circle radius is just constant number, not dynamic function. When you are setting circle radius with your formula, radius is calculated and result stored as constant, not formula.

If you want radius of markers to change dynamically with zoom change, you have to iterate through all markers at zoomend event and change their radius with setRadius method. Since marker radius is dependant on price, to have it at hand when calaculating radius, it can be stored as _price property of marker when creating marker.

Code could then look something like this:

var map = L.map('map',{ zoomControl:false, attributionControl: false, center: [38.980817, -98.760076], zoom: 4});
L.tileLayer("https://cartodb-basemaps-b.global.ssl.fastly.net/dark_all/{z}/{x}/{y}.png", {maxZoom: 20, openLegendOnLoad: false, attribution:''}).addTo(map)
var myMarkers = L.layerGroup();

function markerRadius(price) {
  return price * 10000 / map.getZoom();
}

fetch('https://craftfamily.ddns.net/data')
  .then(response => {
    return response.json()
  })
  .then(data => {
    for (var key in data.recordset) {
      //console.log(key, data.recordset[key]);
      var lat = data.recordset[key].LATITUDE;
      var lon = data.recordset[key].LONGITUDE;
      var name = data.recordset[key].NAME;
      var location = data.recordset[key].LOCATION;
      var ticker = data.recordset[key].TICKER;
      var price = data.recordset[key].PRICE;
      var change = parseFloat(data.recordset[key].CHANGE).toFixed(2);
      var marker = L.circle([lat, lon], markerRadius(price)).bindPopup("<b>"+name+" ("+ticker+")</b><br>$"+price + " (" + change +")<br>"+location+"<br>"+lat+", "+lon);
      marker._price = price;
      marker.addTo(myMarkers);
    }
  })
  .catch(err => {
  });

myMarkers.addTo(map);

map.on('zoomend', function() {
  myMarkers.eachLayer(function (marker) {
    marker.setRadius(markerRadius(marker._price));
  });
});