I'm new to Leaflet, Javascript and GIS Stackexchange. I've been working through various tutorials to try and produce what I need but I'm missing something.
Essentially I would like to produce a leaflet map with a drop down selector that changes the styling and popups of my geoJSON based on different attributes.
Here is my code:
var map = new L.Map('map', { zoomControl:false });
map.dragging.disable();
map.touchZoom.disable();
map.doubleClickZoom.disable();
map.scrollWheelZoom.disable();
map.boxZoom.disable();
map.keyboard.disable();
// Create control for dropdown selector
var selector = L.control({
position: 'topright'
});
// Add content to the control
selector.onAdd = function(map) {
//create div container
var div = L.DomUtil.create('div', 'hazard_select');
//create select element within container (with id, so it can be referred to later
div.innerHTML = '<select id="hazard_select"><option value ="FL">River flood</option><option value ="EQ">Earthquake</option><option value ="DR">Water scarcity</option><option value ="CY">Cyclone</option><option value ="CF">Coastal flood</option><option value ="TS">Tsunami</option><option value ="VO">Volcano</option><option value ="LS">Landslide</option></select>';
return div;
};
// Add the selector to the map
selector.addTo(map);
var geojson, style_change, hazard;
// Define a style
function restylemap(feature, hazard) {
if (feature.properties.FL_SUB !== null) {
return {
weight: 1.2,
color: '#0072bc',
fillColor: '#08519c',
lineJoin: 'bevel',
opacity: 1.0,
fillOpacity: 1.0
};
}
else if (feature.properties.FL_NAT !== null) {
return {
weight: 1.2,
color: '#659ad2',
fillColor: '#3182bd',
lineJoin: 'bevel',
opacity: 1.0,
fillOpacity: 1.0
};
}
else if (feature.properties.FL_REG !== null) {
return {
weight: 1.2,
color: '#659ad2',
fillColor: '#6baed6',
lineJoin: 'bevel',
opacity: 1.0,
fillOpacity: 1.0
};
}
else {
return {
weight: 1,
color: '#afafaf',
fillColor: '#bdd7e7',
lineJoin: 'bevel',
opacity: 1.0,
fillOpacity: 1.0
};
}
}
// Get json through jquery
$.getJSON("js/dataholdings.geojson", function(data) {
geojson = L.geoJson(data, {
style: restylemap,
onEachFeature: function (feature, layer) {
layer.bindPopup("Name: " + feature.properties.ADM0_NAME);
},
});
// Add event listeners
style_change = L.DomUtil.get("hazard_select");
L.DomEvent.addListener(style_change, 'click', function(e) {
L.DomEvent.stopPropagation(e);
});
L.DomEvent.addListener(style_change, 'change', changeHandler);
function changeHandler(e) {
geojson = L.geoJson(data,
restylemap(geojson,e.target.value)
)
}
map.fitBounds(geojson.getBounds());
geojson.addTo(map);
});
This works to initially style the map, but not when the drop down is changed. I think the problem is with my changeHandler function, it passes on the Hazard ID to restylemap but then has the error "TypeError: undefined is not an object (evaluating 'feature.properties.FL_SUB')". As hazard is replacing feature?
I wanted to pass the Hazard variable into the 'Feature.properties' somehow, is this possible? i.e (feature.properties[hazard]& '_REG' !== null). Would this work?
Any advice gratefully received!
Best Answer
You guessed almost right, your
restylemap
function does not like receivinggeojson,e.target.value
as arguments, instead of its specifiedfeature, hazard
signature (where actually justfeature
is used).So your error comes from passing
geojson
full Leaflet layer group in place of the expectedfeature
plain single GeoJSON feature object. It tries to read theproperties
key of yourgeojson
argument, but finds none, so it isundefined
("not an object"). Then it tries to read theFL_SUB
key, but there is no key onundefined
.Furthermore, within your select change listener
changeHandler
, you re-assign yourgeojson
variable but do not add it to map. Therefore it would duplicate your layers, without actually adding the new ones to the map.For the above issue, you should rather use the
.setStyle()
method on yourgeojson
variable withinchangeHandler
instead of creating a new layer throughL.geoJson
.Then you are left with specifying a new
style
function that depends on your select (drop-down) chosen value. For this, you should realize that you may need an array of styling functions, or a function that works on a 2-dimensional scale, since you seem to need 2 variables (your selected value and the layers feature properties). In your currentrestylemap
, you use only the layers feature properties.