1

Working with leaflet.js. I'm trying to incorporate multiple filters in L.control.layers. I have a working layer control for changing basemaps and layers of markers with different years, but I would like to add an extra filter, namely wether or not the marker is active. Ideally, it would look like this:

Basemaps:
[radiobutton] Map 1
[radiobutton] Map 2

Year:
[checkbox] 2018
[checkbox] 2019

Status:
[checkbox] Active
[checkbox] Inactive

This means that it is not as simple as projecting certain layers on the map, but every time the values of the checkboxes change, all the properties must be checked and only those who fit the filters are projected. So, when for example Active and Inactive are checked, but 2018 and 2019 are unchecked, no markers would be projected on the map. If only Active and 2018 are checked, the map shows only those markers which are active and have the year 2018.

You can find my code below, or a working script here https://jsfiddle.net/m7wvnbjq/1/. I basically create separate layers which I can control with L.control.layers, but I'm looking for a way of joining all the features in one layer and having this layer be filtered according to the checkboxes.

<!DOCTYPE html>
<!-- import leaflet.css -->
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css" integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ==" crossorigin="" />

<!-- import leaflet.js -->
<script src="https://unpkg.com/leaflet@1.6.0/dist/leaflet.js" integrity="sha512-gZwIG9x3wUXg2hdXF6+rVkLF/0Vi9U8D2Ntg4Ga5I5BZpVkVxlJWbSQtXPSiUTtC0TjtGOmxa1AJPuV0CPthew==" crossorigin=""></script>

<div id="map"></div>
#map {
  height: 500px;
}
// initialize basemaps
var OpenStreetMap_Mapnik = L.tileLayer(
  "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
    maxZoom: 19,
    attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
  }
);

var NL_basemap = L.tileLayer(
  "https://geodata.nationaalgeoregister.nl/tiles/service/wmts/brtachtergrondkaart/EPSG:3857/{z}/{x}/{y}.png", {
    minZoom: 6,
    maxZoom: 19,
    bounds: [
      [50.5, 3.25],
      [54, 7.6]
    ],
    attribution: 'Kaartgegevens &copy; <a href="kadaster.nl">Kadaster</a>'
  }
);

// collect basemaps in dict
var basemaps = {
  Map1: OpenStreetMap_Mapnik,
  Map2: NL_basemap
};

// initialize map
var mymap = L.map("map", {
  layers: OpenStreetMap_Mapnik
}).setView([52.35274, 4.894784], 10);

// create data in two separate layers
var geoJSON_data_2018 = [{
    type: "Feature",
    properties: {
      title: "Marker1",
      year: 2018,
      activity: "Inactive"
    },
    geometry: {
      type: "Point",
      coordinates: [4.7, 52.3]
    }
  },
  {
    type: "Feature",
    properties: {
      title: "Marker2",
      year: 2018,
      activity: "Active"
    },
    geometry: {
      type: "Point",
      coordinates: [5, 52.4]
    }
  },
  {
    type: "Feature",
    properties: {
      title: "Marker3",
      year: 2018,
      activity: "Inactive"
    },
    geometry: {
      type: "Point",
      coordinates: [4.8, 52.3]
    }
  },
  {
    type: "Feature",
    properties: {
      title: "Marker4",
      year: 2018,
      activity: "Active"
    },
    geometry: {
      type: "Point",
      coordinates: [4.9, 52.2]
    }
  },
  {
    type: "Feature",
    properties: {
      title: "Marker5",
      year: 2018,
      activity: "Inactive"
    },
    geometry: {
      type: "Point",
      coordinates: [5, 52.25]
    }
  }
];

var geoJSON_data_2019 = [{
    type: "Feature",
    properties: {
      title: "Marker6",
      year: 2019,
      activity: "Inactive"
    },
    geometry: {
      type: "Point",
      coordinates: [4.8, 52.4]
    }
  },
  {
    type: "Feature",
    properties: {
      title: "Marker7",
      year: 2019,
      activity: "Active"
    },
    geometry: {
      type: "Point",
      coordinates: [5.1, 52.5]
    }
  },
  {
    type: "Feature",
    properties: {
      title: "Marker8",
      year: 2019,
      activity: "Inactive"
    },
    geometry: {
      type: "Point",
      coordinates: [4.9, 52.4]
    }
  },
  {
    type: "Feature",
    properties: {
      title: "Marker9",
      year: 2019,
      activity: "Active"
    },
    geometry: {
      type: "Point",
      coordinates: [5, 52.3]
    }
  },
  {
    type: "Feature",
    properties: {
      title: "Marker10",
      year: 2019,
      activity: "Inactive"
    },
    geometry: {
      type: "Point",
      coordinates: [5.1, 52.35]
    }
  }
];

// collect the two layers in dict
var yearLayers = {
  2018: L.geoJson(geoJSON_data_2018),
  2019: L.geoJson(geoJSON_data_2019)
};

// add filter control
L.control.layers(basemaps, yearLayers, {
  collapsed: false
}).addTo(mymap);

In this post (Multiple on-the-fly filtering based on markers' features on leaflet) a solution is offered for filtering on multiple features, but here the checkboxes are outside the map.

My question is if it would be possible to have it incorporated in L.control.layers, so that it is nicely concealed in the map and I don't have to manually add all the available checkboxes (in my real script I have a for-loop who adds checkboxes for all the values in my data).

  • One of the basic policies of GIS SE site is that coding question should include relevant existing code (as you can see in the question you are referring to), otherwise question is most likely to be closed. – TomazicM Jun 22 at 16:23
  • Sorry about that. Please see my edit and JSfiddle for the relevant existing code. – Peter Jun 22 at 19:33
  • JSFiddle is of course welcome, but the relevant code should be part of the question. Outside links tend to get lost in time. Please edit your question and add relevant part of your code in the body of the question. – TomazicM Jun 22 at 19:35
  • I understand. Hope this helps. – Peter Jun 22 at 21:09
0

To dynamically change GeoJSON layer filter with L.control.layers control, dummy nodisplayed layers can be used. These layers are used:

  • to have desired entries in L.control.layers control;
  • to filter GeoJSON layer features depending on dummy layer beeing included in the map (layer checked in the control) or not;
  • to trigger map's overlayadd and overlayremove events and reload GeoJSON layer with current filter.

If your two data sources are joined into single geoJSON_data source, your code could then look something like this:

var selectLayer = [];    
for (var i = 0; i < 4; i++) {
  selectLayer[i] = L.polyline([[0, 0], [0, 0]], {stroke: false, interactive: false});
}

var selectLayers = {
  '2018': selectLayer[0],
  '2019': selectLayer[1],
  'Active': selectLayer[2],
  'Inactive': selectLayer[3]
};

var geojsonLayer = L.geoJson(geoJSON_data, {
  filter: function (feature) {
    var cond1 = mymap.hasLayer(selectLayers[feature.properties.year]);
    var cond2 = mymap.hasLayer(selectLayers[feature.properties.activity]);
          
    return (cond1 && cond2);
  }
}).addTo(mymap);

L.control.layers(basemaps, selectLayers, {
  collapsed: false
}).addTo(mymap);

mymap.on('overlayadd overlayremove', function(evt) {
  geojsonLayer.clearLayers()
  geojsonLayer.addData(geoJSON_data)
});
| improve this answer | |
  • That is true, but my problem would be that the geoJSON_data needs to be filtered by year (let's say "2018" and "2019") and activity ("Active" and "Inactive"). In the link above it is shown, but only with checkboxes as separate div's. My question is can we use the built in checkboxes of L.control.layers for this, so that we have radiobuttons for the basemaps and checkboxes for year and checkboxes for activity? – Peter Jun 23 at 14:44
  • Ups, I missed that point completely. Yes, it's possible, I'll update answer later. How would you name this checkbox? Only one or two (separate for actove and inactive)? What would be the logic if checked/unchecked? Please edit your question and add this info. – TomazicM Jun 23 at 18:33
  • Thanks for your help! Please see my edit, I hope this clarifies it. – Peter Jun 24 at 10:17
  • See modified answer. – TomazicM Jun 24 at 10:48

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.