2

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!

1

You guessed almost right, your restylemap function does not like receiving geojson,e.target.value as arguments, instead of its specified feature, hazard signature (where actually just feature is used).

So your error comes from passing geojson full Leaflet layer group in place of the expected feature plain single GeoJSON feature object. It tries to read the properties key of your geojson argument, but finds none, so it is undefined ("not an object"). Then it tries to read the FL_SUB key, but there is no key on undefined.

Furthermore, within your select change listener changeHandler, you re-assign your geojson 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 your geojson variable within changeHandler instead of creating a new layer through L.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 current restylemap, you use only the layers feature properties.

  • Thank you so much for the above, it's really helped me to understand where I've got it wrong. I know there are some bits in my code that weren't actually being used, I was going a bit crazy chopping and changing bits around to try and make things work. All part of the learning process I guess! – norris Aug 4 '16 at 14:54
  • For the latter part, where you mention an array of styles, are you suggesting that I have Style1, Style2, Style3 etc defined somewhere and .setStyle calls a particular style based on the dropdown value? Would that work? Also, I know it's not in the original question but I want the popups to change too, is it possible to use OnEachFeature again in the ChangeHandler for this? Thanks again. – norris Aug 4 '16 at 15:02
  • For your styles, it all depends on the color schemes you want to use depending on your 2 variables (feature.properties.FL_XXX and selected option). As for changing the popups, onEachFeature works only for added data. You should rather consider .eachLayer() method. Feel free to open a new question should you need further help. – ghybs Aug 4 '16 at 16:14
  • Thank you so much for your help, I think I've got it all working though it's not the most efficient solution I'm using! – norris Aug 5 '16 at 15:49

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.