0

I have a map with multiple polygons rendered on it which can overlap eachother. I use leafletPip.pointInLayer(point, layer) from https://github.com/mapbox/leaflet-pip for determining which polygons do overlap. This happens in the processClick function. In the Vue object I create the map and my GeoJSON layer with the polygons. What I now want is following feature: if you click on a point on the map and this point is contained in multiple polygons, you have something like a selection tool, e.g. in a pop-up, to click on one of these polygons and trigger the .on('click') function only for this specific polygon. I searched all the Leaflet features but I could not find anything really useful. Right now, if you click on a point contained in multiple polygons, you only trigger the .on('click') for the polygon which spatially contains the others.

var mapVue = new Vue({
  parent: vue_broadcaster,
  el: '#map',
  data: {
    map: null,
    layer: null
  },
  created: function () {
   // Adding Leaflet map here
    var map = L.map('map').setView([51.959, 7.623], 14);
    L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
      attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
    }).addTo(map);
    this.$set('map', map);
    this.get_zones();
  },
  methods: {
    switch_zone: function (zoneid) {
      this.$dispatch('zoneSelected', zoneid)
    },
    get_zones: function () {
      this.$http.get('/api/zones/', function (data) {
      // Creation of the GeoJSON layer
        var geoZone = {
          "type": "FeatureCollection",
          "features": []
        };
        for (var i = 0; i < data['Zones'].length; i++) {
          geoZone.features.push({
            "type": "Feature",
            "geometry": {
              "type": "Polygon",
              "coordinates": [[]]
            },
            "properties": {
              "name": ""
            }
          })
          geoZone.features[i].properties.name = data['Zones'][i]['Name'];
          for (var j = 0; j < data['Zones'][i]['Geometry']['Coordinates'].length; j++) {
            geoZone.features[i].geometry.coordinates[0].push([data['Zones'][i]['Geometry']['Coordinates'][j][1], data['Zones'][i]['Geometry']['Coordinates'][j][0]])
          }
          this.layer = new L.geoJson(geoZone)
            .bindPopup(data['Zones'][i]['Name'])
            .on('click', dispatchZoneID(data['Zones'][i]['Zone-id'], this))
            .on('click', function (e) {
              processClick(e.latlng.lat, e.latlng.lng)
            })
            .addTo(this.map)
        };
      })
    }
  }
});
// function for processing the clicks on the map
function processClick(lat, lng) {
  var info = '';
  var point = [lng, lat];
  var match = leafletPip.pointInLayer(point, mapVue.layer, false);
  if (match.length) {
    for (var i = 0; i < match.length; i++) {
      info +=
      "<b>" + match[i].feature.properties.name + "<br>"
    }
  }
  if (info) {
    mapVue.map.openPopup(info, [lat, lng]);
  }
};
// not important for this one
function dispatchZoneID(id, vue) {
  return function () {
    vue.$dispatch('zoneSelected', id)
  }
};
0

I found a solution working for me, but it's maybe not the most elegant one. If the point clicked is contained in multiple polygons (match.length > 1), I generate this info string. In each iteration the for-loop creates a clickable link which then calls a function on click depending on the id. So I basically have to generate a lot of HTML in one single string and work with literals and string concatenation. Then I call the openPopup function with info as my html param.

function processClick(lat, lng) {
  var info = '';
  var point = [lng, lat];
  var match = leafletPip.pointInLayer(point, mapVue.layer, false);
  if (match.length > 1) {
    for (var i = 0; i < match.length; i++) {
      id = match[i].feature.properties.zoneid;
      name = match[i].feature.properties.name;
      info +=
      "<b><a onclick='dispatchZoneID(\"" + id + "\")();'>"+ name + "</a><br>"
    }
  }
  else dispatchZoneID(mapVue.zoneid)();

  if (info) {
    mapVue.map.openPopup(info, [lat, lng]);
  }
};

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.