Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get all features of all layers clicked in leaflet

Tags:

leaflet

I am using leaflet. Does anybody have a suggestion for a function that would return all of the features from all layers that a user clicks?

For example, I have a point layer, and a polygon layer. When a user clicks a point, I would like to display the attributes of the point and the polygon underneath that point. If the user only clicks the polygon, then it should only show attributes of the polygon.

Thank you in advance for any help provided.

like image 201
Sid Kwakkel Avatar asked Jul 26 '16 21:07

Sid Kwakkel


2 Answers

  1. Capture point clicked from event passed to click handler
  2. Create bounding box for the point (L.latLngBounds)
  3. Loop through each visible layer in map._layers
  4. Find feature layers: if layer is a feature layer it has a _layers property; one layer for each feature
  5. Loop through each feature in each feature layer, and get or create bounding box for each feature
  6. Test for intersection of feature bounding box with the click bounding box created in step 1, and add to array
  7. Display array contents to user to show all features behind point clicked.

(note: it is easier and more reliable if you keep track of your own features in a separate array. If you do this, you can skip steps 3 and 4.)

// Create the map
var map = L.map('map').setView([39.5, -0.5], 5);

// Set up the OSM layer
var baseLayer1 = L.tileLayer(
  'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
    maxZoom: 18,
    name: "Base layer 1"
  }).addTo(map);

function clickHandler(e) {
  var clickBounds = L.latLngBounds(e.latlng, e.latlng);

  var intersectingFeatures = [];
  for (var l in map._layers) {
    var overlay = map._layers[l];
    if (overlay._layers) {
      for (var f in overlay._layers) {
        var feature = overlay._layers[f];
        var bounds;
        if (feature.getBounds) bounds = feature.getBounds();
        else if (feature._latlng) {
          bounds = L.latLngBounds(feature._latlng, feature._latlng);
        }
        if (bounds && clickBounds.intersects(bounds)) {
          intersectingFeatures.push(feature);
        }
      }
    }
  }
  // if at least one feature found, show it
  if (intersectingFeatures.length) {
    var html = "Found features: " + intersectingFeatures.length + "<br/>" + intersectingFeatures.map(function(o) {
      return o.properties.type
    }).join('<br/>');

    map.openPopup(html, e.latlng, {
      offset: L.point(0, -24)
    });
  }
}

map.on("click", clickHandler);

// add some markers
function createMarker(lat, lng) {
  var marker = L.marker([lat, lng]);
  marker.on("click", clickHandler);
  marker.properties = {
    type: "point"
  }; // add some dummy properties; usually would be geojson
  return marker;
}
var markers = [createMarker(36.9, -2.45), createMarker(36.9, -2.659), createMarker(36.83711, -2.464459)];

// create group to hold markers, it will be added as an overlay
var overlay = L.featureGroup(markers).addTo(map);

// show features
map.fitBounds(overlay.getBounds(), {
  maxZoom: 11
});

// create another layer for shapes or whatever
var circle = L.circle([36.9, -2.45], 2250, {
  color: 'red',
  fillColor: '#f03',
  fillOpacity: 0.5
});
circle.on('click', clickHandler);
circle.properties = {
  type: "circle"
};
var overlay2 = L.featureGroup([circle]).addTo(map);
#map {
  height: 400px;
}
<script src="https://npmcdn.com/[email protected]/dist/leaflet.js"></script>
<link href="https://npmcdn.com/[email protected]/dist/leaflet.css" rel="stylesheet" />
<div id="map"></div>

JS Fiddle in case you want to, you know, fiddle: http://jsfiddle.net/xn8opdjq/

like image 199
nothingisnecessary Avatar answered Nov 08 '22 04:11

nothingisnecessary


In addition to @nothingisnecessary response, see pip (point in polygon) for leaflet

like image 38
Toni BCN Avatar answered Nov 08 '22 05:11

Toni BCN