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: '© <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 © <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).
Best Answer
To dynamically change GeoJSON layer filter with
L.control.layers
control, dummy nodisplayed layers can be used. These layers are used:L.control.layers
control;overlayadd
andoverlayremove
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: