Skip to content

Instantly share code, notes, and snippets.

@jacoduplessis
Created November 24, 2018 18:42
Show Gist options
  • Save jacoduplessis/cc9aa8e910d13072a94d00aa13c87d8d to your computer and use it in GitHub Desktop.
Save jacoduplessis/cc9aa8e910d13072a94d00aa13c87d8d to your computer and use it in GitHub Desktop.
var GeoJSONFilterControl = L.Control.extend({
initialize: function (geoJsonLayer, data, fields, options = {}) {
this.layer = geoJsonLayer;
this.data = data;
this.fields = fields;
this.filteredOut = {};
L.Util.setOptions(this, options);
},
options: {
position: 'bottomright'
},
render: function () {
this.layer.getLayers().forEach(marker => {
const mustFilter = Object.entries(this.filteredOut)
.map(([group, val]) => val.has(marker.feature.properties[group]))
.some(x => x)
marker.setStyle({
opacity: mustFilter ? 0 : 1,
fill: !mustFilter
})
})
},
onAdd: function (map) {
this.holder = L.DomUtil.create('div');
if (!map.hasLayer(this.layer)) {
/* Hide the filter box if the layer is not yet visible */
this.holder.style.display = 'none';
}
/* We don't want click events to interact with the map */
L.DomEvent.disableClickPropagation(this.holder);
Object.entries(this.fields).forEach(([title, fieldId]) => {
this.filteredOut[fieldId] = new Set()
/* Define the callback to filter all data for the given field */
let callback = (e) => {
let changedField = e.target.value;
let changedTo = e.target.checked;
if (!changedTo) {
this.filteredOut[fieldId].add(changedField);
} else {
this.filteredOut[fieldId].delete(changedField);
}
this.render()
};
/* Create a fieldset with a legend for this filter group */
let fieldGroup = L.DomUtil.create('fieldset', 'checkboxgroup', this.holder);
let legend = L.DomUtil.create('legend', '', fieldGroup);
legend.innerHTML = title;
// setup clear/all buttons
let buttonHolder = L.DomUtil.create('div', '', fieldGroup)
let clearAll = L.DomUtil.create('button', '', buttonHolder)
clearAll.textContent = 'clear all'
let selectAll = L.DomUtil.create('button', '', buttonHolder)
selectAll.textContent = 'select all'
let valuesSet = this.data.features.reduce((set, f) => set.add(f.properties[fieldId]), new Set())
clearAll.onclick = () => {
fieldGroup.querySelectorAll('input[type="checkbox"]').forEach(el => el.checked = false)
this.filteredOut[fieldId] = valuesSet
this.render()
}
selectAll.onclick = () => {
fieldGroup.querySelectorAll('input[type="checkbox"]').forEach(el => el.checked = true)
this.filteredOut[fieldId] = new Set()
this.render()
}
valuesSet.forEach(val => {
let cb = L.DomUtil.create('input', '', fieldGroup);
cb.type = 'checkbox';
cb.id = fieldId + '_' + val;
cb.checked = 'checked';
cb.value = val;
cb.onchange = callback;
let cbLabel = L.DomUtil.create('label', '', fieldGroup);
cbLabel.setAttribute('for', cb.id);
cbLabel.textContent = val;
L.DomUtil.create('br', '', fieldGroup);
})
})
map.on({
layeradd: e => {
if (e.layer === this.layer) {
this.holder.style.display = ''
}
},
layerremove: e => {
if (e.layer === this.layer) {
this.holder.style.display = 'none'
}
}
});
return this.holder;
},
show: function () {
this.holder.style.display = '';
},
hide: function () {
this.holder.style.display = 'none';
},
});
@jacoduplessis
Copy link
Author

@civilelectrico
Copy link

thanks to @guygriffiths and @jacoduplessis for this great code. Everything is as I was expecting except that the "clear all" button is working only one time. For example try the following:
1.-click on "Clear all" button (this is working ok)
2.-later select the single filters one by one.(this working ok, too)
3.-later, click on Clear all button once again. (this second time is not working)
Please, could you try this behavior and fix if it's like this for you?
B.R. and Thanks in advance.

@jacoduplessis
Copy link
Author

@civilelectrico have you tried fixing it yourself?

@civilelectrico
Copy link

yes, I already tried. I have a suspicion that could be due about this line, the render is made to add and get but it`s not made to delete or remove.

clearAll.onclick = () => {
fieldGroup.querySelectorAll('input[type="checkbox"]').forEach(el => el.checked = false)
this.filteredOut[fieldId] = valuesSet
this.render()
}

ClearAll button unclick the boxes rightly but the render on the map is not changing with the unclicked boxes.

This issue is not happening with a single box and selectAll button . This is happening ONLY when the ClearAll button is used after use the single boxes.

I have not the high level view as you. Please let me know if you can support this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment