[GIS] .on(click) for layer groups in leaflet

javascriptleaflet

I have three layer groups. How to use .on (click) for all layer groups without repeating the code? Do I really need to use .on(click) for each layer group? It seems to be unnecessary lots of code.

When using this below I only get the on click window for the last layer group (area_skrym) and no info for the first two. Script load the same data and use the same info when you click on the map, but I can not get it to work with below JavaScript code.

var area_size = new L.layerGroup();
var area_weight = new L.layerGroup();
var area_skrym = new L.layerGroup();

$.getJSON("/geojson/area_polyg.geojson", function(json) {

var vectorGrid_size =  L.vectorGrid.slicer(json, {
                  maxZoom: 20,
                  zIndex: 5,
                  rendererFactory: L.svg.tile,
                  vectorTileLayerStyles: {
                      sliced: function(properties, zoom){
                      var avl = properties.Total
                      if (avl <= 500){
                        return{
                      weight: 1,
                      color: 'white',
                      opacity: 0,
                      fill: true,
                      fillColor: '#4575b4',
                      stroke: true,
                      fillOpacity: 0.6
                      }
                      } else if (avl >= 500 && avl <= 1500){
                        return {
                      weight: 1,
                      color: 'white',
                      opacity: 0,
                      fill: true,
                      fillColor: '#91bfdb',
                      stroke: true,
                      fillOpacity: 0.6
                      }
                      } else if (avl >= 1501 && avl <= 3000){
                        return {
                      weight: 1,
                      color: 'white',
                      opacity: 0,
                      fill: true,
                      fillColor: '#e0f3f8',
                      stroke: true,
                      fillOpacity: 0.6
                      }
                      } else if (avl >= 3001 && avl <= 4500){
                        return {
                      weight: 1,
                      color: 'white',
                      opacity: 0,
                      fill: true,
                      fillColor: '#ffffbf',
                      stroke: true,
                      fillOpacity: 0.6
                      }
                      } else if (avl >= 4501 && avl <= 6000){
                        return {
                      weight: 1,
                      color: 'white',
                      opacity: 0,
                      fill: true,
                      fillColor: '#fee090',
                      stroke: true,
                      fillOpacity: 0.6
                      }
                      } else if (avl >= 6001 && avl <= 7500){
                        return {
                      weight: 1,
                      color: 'white',
                      opacity: 0,
                      fill: true,
                      fillColor: '#fc8d59',
                      stroke: true,
                      fillOpacity: 0.6
                      }
                      } else {
                      return {
                      weight: 1,
                      color: 'white',
                      opacity: 0,
                      fill: true,
                      fillColor: '#d73027',
                      stroke: true,
                      fillOpacity: 0.6
                      }
                    }
                     }},
                     interactive: true,
                   })

var vectorGrid_weight =  L.vectorGrid.slicer(json, {
                  maxZoom: 20,
                  zIndex: 5,
                  rendererFactory: L.svg.tile,
                  vectorTileLayerStyles: {
                      sliced: function(properties, zoom){
                      var gods = properties.1_gods
                      if (gods === 'Yes'){
                        return{
                      weight: 1,
                      color: '#e41a1c',
                      opacity: 1,
                      fill: true,
                      fillColor: '#e41a1c',
                      stroke: true,
                      fillOpacity: 0.6
                      }
                      } else {
                      return {
                      weight: 0,
                      color: 'white',
                      opacity: 0,
                      fill: false,
                      fillColor: '#ffffff',
                      stroke: false,
                      fillOpacity: 0
                      }
                    }
                     }},
                     interactive: true,
                   })

    var vectorGrid_skrym =  L.vectorGrid.slicer(json, {
                  maxZoom: 20,
                  zIndex: 5,
                  rendererFactory: L.svg.tile,
                  vectorTileLayerStyles: {
                      sliced: function(properties, zoom){
                      var skrym = properties.size
                      if (skrym === 'Yes'){
                        return{
                      weight: 1,
                      color: '#377eb8',
                      opacity: 1,
                      fill: true,
                      fillColor: '#377eb8',
                      stroke: true,
                      fillOpacity: 0.6
                      }
                      } else {
                      return {
                      weight: 0,
                      color: 'white',
                      opacity: 0,
                      fill: false,
                      fillColor: '#ffffff',
                      stroke: false,
                      fillOpacity: 0
                      }
                    }
                     }},
                     interactive: true,
                   })

 .on('click', function(e) {
  var properties = e.layer.properties;
  L.popup()
    .setContent(
      "<b>Size</b>: " + properties.size +
      "<br><b>Number</b>: " + properties.code +
      "<br><b>Name</b>: " + properties.name +
      "<br><b>Total</b>: " + properties.Total + '.pieces' + 
      "<br><a href='" + 'mailto:' + properties.email + "'>Contact email</a>" + 
      "<br><b>Date</b>: " + properties.date)
    .setLatLng(e.latlng)
    .openOn(map);
                    })

vectorGrid_size.addTo(area_size)

vectorGrid_weight.addTo(area_weight)

vectorGrid_skrym.addTo(area_skrym)

            }) 

Best Answer

There are a few approaches to this. The most basic is to define an event handler and reuse that when defining events, e.g.:

function handleClickOnSomething(ev) {
  var properties = ev.target.properties;
  L.popup().setContent(properties.something).setLatLng(...).openOn(map);
}

vectorGrid_size.on('click', handleClickOnSomething);      
vectorGrid_weight.on('click', handleClickOnSomething);    
vectorGrid_skrym.on('click', handleClickOnSomething);

This kind of refactoring is applicable elsewhere - just look for places where defining a thing once and referencing it several times will make the code architecture simpler.

Another approach is to leverage Leaflet's L.FeatureGroups. From the Leaflet reference:

Extended LayerGroup that makes it easier to do the same thing to all its member layers: [...] Events are propagated to the FeatureGroup, so if the group has an event handler, it will handle events from any of the layers. This includes mouse events and custom events.

So you can do something like:

var group = L.featureGroup();

vectorGrid_size.addTo(group);
vectorGrid_weight.addTo(group);
vectorGrid_skrym.addTo(group);

group.on('click', function(ev) { /* ... */ });

group.addTo(map);

Just be aware of the difference between ev.target, ev.sourceTarget and ev.propagatedFrom in that context - check the Leaflet reference for details.