2

I have an issue, I have a react-leaflet map with GeoJSON layers. Also, I have added some state components like cascader with some name of countries options, like Austria, Belgium, etc... I want to have it like this. After the state from cascader is done (so after I click on a country in cascader), I want to change the color of the selected country from that cascader and display it on the map. For example, if I choose Austria, I want to have colored Austria on the map. Also cascader is from the Ant Desing library. And selectedCountries is another state that is not important.

const [currentValueCascader, setCurrentValueCascader] = React.useState([])

function onEachCountry(country, layer) {
    const countryName = country.properties.ADMIN

      if (currentValueCascader.includes(countryName)) {
        layer.setStyle({ fillColor: 'yellow', weight: 2, fillOpacity: 5 })
      } else {
        layer.setStyle({ color: "#000000", fillColor: "white", weight: 1 })
      }
}

return(
<Cascader
                showSearch
                style={{ width: 256 }}
                options={countries}
                onChange={(e) => {
                  setCurrentValueCascader(e)
                }}
                placeholder="Search country"
                value={currentValueCascader} 
                multiple
    
    
              /> 
<MapContainer
            style={{ height: "80vh", width: "auto" }}
            zoom={2.3}
            scrollWheelZoom={true}
            minZoom={2.3}
            center={[30, 0]}>
            <TileLayer url='https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png' />
            <GeoJSON data={features} onEachFeature={(a, b) => { onEachCountry(a, b, selectedCountries) }} style={(a, b) => { onEachCountry(a, b, selectedCountries) }}}  />
          </MapContainer>
    )

I think that somehow the Leaflet map is not re-rendering that chosen option or maybe that GeoJSON, but don't know how to solve it.

4
  • I'm not familiar with React, but if it's OK with you, I can post answer for plain JS and HTML.
    – TomazicM
    Mar 20 at 10:51
  • U can try it, maybe it will help.
    – loklba
    Mar 20 at 11:58
  • There some work needed for this, so unless you are sure it'll be helpful to you, I won't post it.
    – TomazicM
    Mar 20 at 14:40
  • I am sure that it will help me.
    – loklba
    Mar 20 at 20:29

1 Answer 1

2

There are several ways how to deal with this. Since I'm not familiar with React, answer will be for plain HTML/JS. Country name is being input through input HTML tag:

<label for="country">Country:</label>
<input type="text" id="country" name="country">

First possibility is to leave setting the style as you have done it. If the style is set with onEachFeature option function, then style is set only once, at the time of GeoJSON data load. To change style at the time country name input, all features/countries have to be iterated and style set again according to selected country name. Group layer method .eachLayer can be used for this.

Plaing HTML/JS code could then look something like this:

var inputElement = document.getElementById('country');

function onEachCountry(feature, layer) {
  const countryName = feature.properties.name;

    if (inputElement.value.includes(countryName)) {
      layer.setStyle({ fillColor: 'yellow', weight: 2, fillOpacity: 5 })
    } else {
      layer.setStyle({ color: "#000000", fillColor: "white", weight: 1 })
    }
}
$.getJSON( "data/countries.json")
 .done(function(data) {
   var vectorLayer = L.geoJson(data, {
     onEachFeature: onEachCountry
   });
   map.addLayer(vectorLayer);
   inputElement.addEventListener('input', function(evt) {
     vectorLayer.eachLayer(function(layer) {
       onEachCountry(layer.feature, layer);
     });
   });
 });

Second possibility is to use GeoJSON layer style option to set layer style and then GeoJSON layer .setStyle method to set style again when country name is selected.

In this case code could look something like this:

var inputElement = document.getElementById('country');

function countryStyle(feature) {
  var style;
  var countryName = feature.properties.name;
  if (inputElement.value.includes(countryName)) {
    style = { fillColor: 'yellow', weight: 2, fillOpacity: 5 };
  } else {
    style = { color: "#000000", fillColor: "white", weight: 1 };
  }
  return(style);
}

$.getJSON( "data/countries.json")
 .done(function(data) {
   var vectorLayer = L.geoJson(data, {
     style: countryStyle
   });
   map.addLayer(vectorLayer);
   inputElement.addEventListener('input', function(evt) {
     vectorLayer.setStyle(countryStyle);
   });
 });

To avoid iterating through all the layers/countries each time country name is changed, third possibility would be to build translating table/object between country name and corresponding Leaflet layer id, retrieved by .getLayerId method. This way country layer for desired country can be directly accesses with the help of .getLayer method.

In this case code could look something like this:

var inputElement = document.getElementById('country');

function countryStyle(feature) {
  return({ color: "#000000", fillColor: "white", weight: 1 });
}

var selectedCountry = null;
var countryToLayerId = {};

$.getJSON( "data/countries.json")
 .done(function(data) {
   var vectorLayer = L.geoJson(data, {
     style: countryStyle
   });
   map.addLayer(vectorLayer);
   vectorLayer.eachLayer(function(layer) {
     countryToLayerId[layer.feature.properties.name] = vectorLayer.getLayerId(layer);
   });
   inputElement.addEventListener('input', function(evt) {
     if (selectedCountry) {
       vectorLayer.resetStyle(selectedCountry);
       selectedCountry = null;
     }
     if (countryToLayerId[inputElement.value]) {
       selectedCountry = vectorLayer.getLayer(countryToLayerId[inputElement.value]);
       selectedCountry.setStyle({ fillColor: 'yellow', weight: 2, fillOpacity: 5 });
     }
   });
 });
1
  • Was it of any help?
    – TomazicM
    Mar 22 at 10:27

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.