1

update: I've got most of what I want working… clicking on a marker changes its icon and also opens a popup showing that marker's properties (from GeoJSON feature.properties). Clicking on the basemap resets the icon back to the original. But, what I haven't figured out is how to select all the members of a multipoint feature when any of its points is clicked. What I want is exactly as is happening in this map on geojson.tools. If I copy my example GeoJSON feature on that webpage, I can click on a point and all the points in that multipoint are highlighted. I can't figure out how to do that with LeafLet.

I have the following code that highlights a clicked marker by changing its icon. However, I would like to select all the markers of the same multipoint (for example, if I click on a marker with fid: 0, I want to "highlight" all the other points with fid: 0. And there should be a way to revert back to the original icon, perhaps after a set time period (I could use setTimeout) or if the user clicks on the map baselayer.

var geojsonFeature = {
    "type": "FeatureCollection",
    "features": [
        {
            "type": "Feature",
            "geometry": {
                "type": "MultiPoint",
                "coordinates": [[14.50, 46.04], [14.53, 45.86]]
            },
            "properties": { "fid": 0 }
        },
        {
            "type": "Feature",
            "geometry": {
                "type": "MultiPoint",
                "coordinates": [[15.50, 44.04], [15.53, 43.86]]
            },
            "properties": { "fid": 1 }
        }
    ]
};

const iconNormal = L.icon({
    iconUrl     : '/img/treatment.svg',
    iconSize: [24, 24],
    iconAnchor: [12, 12],
});

const iconHighlighted = L.icon({
    iconUrl     : '/img/treatment-highlighted.svg',
    iconSize: [24, 24],
    iconAnchor: [12, 12],
});

L.geoJSON(geojsonFeature, {
    pointToLayer: function(gp, latlng) {
        const marker = L.marker(latlng, { icon: iconNormal });
        const click = {
            'click': (e) => e.target.setIcon(iconHighlighted)
        };

        return marker.on(click);
    }
}).addTo(map);

My code feels very amateurish. Is there a better way? And how do I select other markers with the same fid and change their icons?

4
  • Seems duplicate of the following question: How to GeoJSON-encode a feature with many points where some properties of the member points are different. If you wan to add new/changed info, please edit the original question
    – TomazicM
    Jan 21 at 18:10
  • no, the other question is the previous step to what I am asking in this one. The other question is about actually generating MultiPoint GeoJSON from a database table of latlng points where some properties may be different. This one is about interaction on the map given a GeoJSON (I am just using the same pseudo-fragment of GeoJSON for both questions)
    – punkish
    Jan 21 at 18:26
  • But this question seem to be dependent on the result/answer to the previous question. Please ask one similar question at a time, so it will be clear what your current problem/question is.
    – TomazicM
    Jan 21 at 19:16
  • no, they are related in that I am trying to solve them both, but they are separate problems. To reiterate: the other question is about generating GeoJSON on the server from data in a db table. This question is about interacting with a GeoJSON, specifically about selecting the different points of a multipoint feature
    – punkish
    Jan 21 at 19:33

1 Answer 1

2

One possible solution (see better one below) for this would be to create an array markersByFid, where each element is again and array of markers that have the same fid property and this is also the index of the array in the markersByFid array.

Each marker is at the creation given custom property fid with the value of fid property from feature. This value is then used at the marker click to get corresponding array of markers with the same fid value from markersByFid array. Icons can then be set for these markers.

At the same time value of fid is saved in the global lastClickedFid, so then on the map click outside markers, icons for the last clicked markers can be reset.

Code could then look something like this:

var markersByFid = [];
var lastClickedFid = null;

function clearLastClicked() {
  if (lastClickedFid != null) {
    markersByFid[lastClickedFid].forEach(function(marker) {
      marker.setIcon(iconNormal);
    });
    lastClickedFid = null;
  }
}

L.geoJSON(geojsonFeature, {
  pointToLayer: function(gp, latlng) {
    const marker = L.marker(latlng, { icon: iconNormal });
    marker.fid = gp.properties.fid;
    if (!markersByFid[gp.properties.fid]) {
      markersByFid[gp.properties.fid] = [];
    }
    markersByFid[gp.properties.fid].push(marker);
    const click = {
      'click': (e) => {
        var fid = e.target.fid;
        if (fid == lastClickedFid) return;
        clearLastClicked();
        markersByFid[fid].forEach(function(marker) {
          marker.setIcon(iconHighlighted);
        });
        lastClickedFid = fid;
      }
    }; 
    return marker.on(click);
  }
}).addTo(map);

map.on('click', function(evt) {
  clearLastClicked();
});

EDIT: After some thought there is a simpler solution by using onEachFeature option function, where layer parameter is actually a group layer, containing all the markers that come from one multipoint feature.

Code could then look something like this:

var lastClickedFeature = null;

function clearLastClicked() {
  if (lastClickedFeature != null) {
    lastClickedFeature.eachLayer(function(marker) {
      marker.setIcon(iconNormal);
    });
    lastClickedFeature = null;
  }
}

L.geoJSON(geojsonFeature, {
  pointToLayer: function(gp, latlng) {
    const marker = L.marker(latlng, { icon: iconNormal });
    return marker;
  },
  onEachFeature: function(feature, layer) {
    layer.on('click', function(evt) {
      if (evt.target == lastClickedFeature) return;
      clearLastClicked();
      evt.target.eachLayer(function(marker) {
        marker.setIcon(iconHighlighted);
      });
      lastClickedFeature = evt.target;
    });
  }
}).addTo(map);

map.on('click', function(evt) {
  clearLastClicked();
});

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.