Leaflet Markers – Opening Popups of All Visible Markers with Zoom > 10

clusteringleafletmarkerspopup

I need to open all the markers that are visible on the map at Zoom > 10. I am using leaflet.markercluster plugin.

Init map:

initMap() {
  this.map = L.map('map', {
    center: [55.55, 37.61],
    zoom: 9,
    layers: this.layer
  })
  this.tileLayer = L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
    maxZoom: 18,
    attribution:
      '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>, &copy;'
  })
  this.tileLayer.addTo(this.map)

this.map.on('zoom', function(ev) {
    ???
  })

Add marker layer:

this.markerLayer = new L.LayerGroup()   // layer contain searched elements
  // this.map.addLayer(this.markerLayer)

  for (const i in data) {
...
    const marker = new L.Marker(new L.latLng(loc), { title: title, icon: icon })// se property searched
    marker.bindPopup(title)
    this.markerLayer.addLayer(marker)
  }

Use leaflet marker cluster:

this.markersLayer = L.markerClusterGroup({
    iconCreateFunction: function(cluster) { ... },
    singleMarkerMode: false
  })
  this.markersLayer.addLayer(this.markerLayer)
  this.map.addLayer(this.markersLayer)

Best Answer

I couldn't find any other method than to loop through all the markers at each view change (zoom, move) and show/hide popup for visible markers depending on zoom level.

Base of the code is taken from Leaflet.markercluster plugin example. Zoom level > 16 is set as trigger for popup display.

Important options:

  • for map: closePopupOnClick: false to prevent automativ popup close on map click
  • for popups: autoClose: false to prevent close of popup when another popup is opened, autoPan: false to prevent panning of map when popup is not entierly inside map
var tiles = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
    maxZoom: 18,
    attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, Points &copy 2012 LINZ'
  })

latlng = L.latLng(-37.82, 175.24);

var map = L.map('map', {center: latlng, zoom: 13, layers: [tiles], closePopupOnClick: false});

var markers = L.markerClusterGroup();

for (var i = 0; i < addressPoints.length; i++) {
  var a = addressPoints[i];
  var title = a[2];
  var marker = L.marker(new L.LatLng(a[0], a[1]), { title: title });
  marker.bindPopup(title, {autoClose: false, autoPan: false});
  markers.addLayer(marker);
}

map.addLayer(markers);

var bounds;
var markersDisplayed = false;

map.on('moveend zoomend', function(e) {
  bounds = map.getBounds();
  var zoom = map.getZoom();
  if (zoom > 16) {
    markers.eachLayer(function (layer) {
      if (bounds.contains(layer.getLatLng())) {
        markersDisplayed = true;
        layer.openPopup();
      }
    });
    }
  else if (markersDisplayed) {
    markersDisplayed = false;
    markers.eachLayer(function (layer) {
      if (bounds.contains(layer.getLatLng())) {
        layer.closePopup();
      }
    });
  }
});

markers.on('clusterclick', function (e) {
  bounds = map.getBounds();
  var zoom = map.getZoom();
  var childMarkers = e.layer.getAllChildMarkers();
  if (zoom > 16) {
    childMarkers.eachLayer(function (layer) {
      if (bounds.contains(layer.getLatLng())) {
        markersDisplayed = true;
        layer.openPopup();
      }
    });
  }
});

Probably not everything was taken care of here, just the basic concept.