3

I got this Leaflet sample from the Leaflet documentation for testing how the filter option works. Then I've created the following code (jsfiddle sample here):

var freeBus = {/*check the jsfiddle sample*/}
var map = L.map('map').setView([39.74739, -105], 13);

L.tileLayer('https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw', {
    maxZoom: 18,
    attribution: 'Map data &copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors, ' +
    'Imagery © <a href="https://www.mapbox.com/">Mapbox</a>',
    id: 'mapbox/light-v9',
    tileSize: 512,
    zoomOffset: -1
}).addTo(map);

function filter(feature, layer) {
    if (feature.properties) {
        if ( feature.properties.underConstruction === undefined || feature.properties.underConstruction === false ) {
            return false
        } else {
            return true
        }
    }
}

const layer = L.geoJSON(freeBus, {
    filter: filter,
}).addTo(map);

freeBus.features[2].properties.underConstruction = true
layer.options.filter

Basically, there's a GeoJSON with three polyline features on this code, and I'm using the filter option to select which polylines I want to show on my map, if underConstruction equals to true, then it appears on the map, otherwise, it doesn't. This code works as I expect until the following lines:

freeBus.features[2].properties.underConstruction = true
layer.options.filter

With those lines I tried to change a false value from my geoJSON to true, and then I tried to rerun the filter on my layer to update the polylines that are being showed on the map. However, that didn't happen in practice... I know that running map.removeLayer(layer) and then drawing the polylines again with L.geoJSON(freeBus, {filter: filter, onEachFeature: onEachFeature }).addTo(map) would solve the problem. But I think that this is not the best way of doing it since I'm erasing everything and drawing all the values again (if my GeoJSON was big with a lot of features that wouldn't be an efficient way of doing it). What am I missing? Is it possible to run the filter option again to update the feature values after I've already drawn my features once?

1 Answer 1

6

If you look at the Leaflet docs for GeoJSON layer at https://leafletjs.com/reference-1.7.1.html#geojson, you'll notice the following note for filter option:

Note: dynamically changing the filter option will have effect only on newly added data. It will not re-evaluate already included features.

This means you have to reload data if you change the filter. This can be done with the .clearLayers and .addData methods.

Code could then look something like this:

var includeUnderConstruction = false;
function filter(feature, layer) {
  if (feature.properties) {
    if (feature.properties.underConstruction === undefined || feature.properties.underConstruction === includeUnderConstruction) {
      return false;
    } else {
      return true;
    }
  }
  return true;
}

const layer = L.geoJSON(freeBus, {
  filter: filter,
}).addTo(map);

// Change filter
includeUnderConstruction = true;
layer.clearLayers();
layer.addData(freeBus);

You can avoid reloading data with the use of GeoJSON layer style option. In the style function you simply set undesired lines not to be displayed. When you change your filter, you just have to set style again with the .setStyle method.

In this case code could look something like this:

var includeUnderConstruction = false;   

function filter(feature, layer) {
  if (feature.properties) {
    if (feature.properties.underConstruction === undefined || feature.properties.underConstruction === includeUnderConstruction) {
      return false;
    } else {
      return true;
    }
  }
  return true;
}

function busStyle(feature) {
  return {
    stroke: filter(feature)
  };
}

const layer = L.geoJSON(freeBus, {
  style: busStyle
}).addTo(map);

// Change style
includeUnderConstruction = true;
layer.setStyle(busStyle);
2
  • Thanks, I've created a jsfiddle of your second approach here: jsfiddle.net/raylight/7g5nbvxw ... As curiosity, do you know if the difference of performace from the first to the second approach is huge when I have a huge number of data on my map?
    – raylight
    Commented Sep 27, 2021 at 18:38
  • 2
    Since filtering is done on the client side, load of data always requires fetch of all the data, regardless of the filter. Although data is most probably in the browser cache, I would still prefer the second approach, since it doesn't require reload of data.
    – TomazicM
    Commented Sep 27, 2021 at 20:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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