31

Ok, since I already asked a very long question about this, but since it didn't get any new replies for a while, and not to get confused in details, I will keep this one simple the best way I can.

If I'm not mistaken, a setStyle function for a named, particular feature would be as follows:

var bounds = [[54.559322, -5.767822], [56.1210604, -3.021240]];
var rect = L.rectangle(bounds, {color: "#ff7800", weight: 1}).addTo(map);

rect.setStyle({color: "#4B1BDE"});

...which would change the color from orange to blue. I'm also aware of the resetStyle() function that will revert the style to the original.

This is how I style my GeoJSON:

var everything = L.geoJson(myfile, {
    onEachFeature: function(feature){
        array_of_layers.addLayer(feature);
    },
    style: function(feature){
            switch(feature.properties.name){
            case "belgium": return belgium_style; break;
            case "bosnia": return bosnia_style; break;
            case "denmark": return denmark_style; break;
            case "great_britain": return britain_style; break;
            case "greece": return greece_style; break;
            case "italy": return italy_style; break;
            case "serbia": return serbia_style; break;
            case "spain": return spain_style; break;
            }
    }

});

What I want to do is to make just one country blue and the others gray, later in the code. It's a two-step thing, to paint all countries to gray, and then make one blue.

The first thing is, I need such a loop that would iterate over each feature and setStyle() for all countries to gray. Does it work if I just everything.setStyle({color: "#4B1BDE"}) or something?

The second thing is, (that's giving me sleepless nights) how do I select just one feature out of a group of GeoJSON polygons to work with? Just the country that I need to paint to blue.

If it was a matter of mouse hovering, I could place an event listener as are done in Leaflet tutorials. But regardless of user interaction, I want to set and reset the style by calling it with its name, as I did with the rectangle above.

mgri
  • 16,159
  • 6
  • 47
  • 80
Doruk Karınca
  • 815
  • 1
  • 9
  • 21

3 Answers3

38

This works without needing to remove the layer and recreate a new one as described above:

geojson_layer.eachLayer(function (layer) {  
  if(layer.feature.properties.NAME == 'feature 1') {    
    layer.setStyle({fillColor :'blue'}) 
  }
});

It seems to be quite a bit more efficient than removing and recreating the geoJson layer. From the docs, a GeoJSON layer extends FeatureGroup which in turn extends LayerGroup.
Additionally, it seems that each geoJson feature has its own layer in the FeatureGroup!

user2441511
  • 284
  • 3
  • 11
Davem M
  • 516
  • 5
  • 5
21

I have written down a small code to style specific geojson feature using leaflet. you can try it on JSFiddle (Original, non-functional), Functional JSFiddle 2018-02-17, or use the following code test locally.

For this example i am using us-states.json files but it can be used for any geojson file.

I hope it will help.

Here is the code:

<!DOCTYPE html>
<html>
<head>
<title>Leaflet Coloring Geojson Features</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="http://leafletjs.com/dist/leaflet.css" />
<!--[if lte IE 8]><link rel="stylesheet" href="../dist/leaflet.ie.css" /><![endif]-->
<style>
#map {
    width: 800px;
    height: 500px;
}
.info {
    padding: 6px 8px;
    font: 14px/16px Arial, Helvetica, sans-serif;
    background: white;
    background: rgba(255, 255, 255, 0.8);
    box-shadow: 0 0 15px rgba(0, 0, 0, 0.2);
    border-radius: 5px;
}
.info h4 {
    margin: 0 0 5px;
    color: #777;
}
.legend {
    text-align: left;
    line-height: 18px;
    color: #555;
}
.legend i {
    width: 18px;
    height: 18px;
    float: left;
    margin-right: 8px;
    opacity: 0.7;
}
</style>
</head>
<body>
<div id="map"></div>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script> 
<script src="http://leafletjs.com/dist/leaflet.js"></script> 
<script type="text/javascript" src="http://leafletjs.com/examples/us-states.js"></script> 
<script type="text/javascript">
    $(document).ready(function () {
        init_map();
        init_geojson();
        $("#btn").on('click', function () {
            var stateName = $('#statename').val();
            console.log(stateName);
            init_geojson(stateName);
        });
    });
    var map, geojson, sn;

    function init_map() {
        map = L.map('map').setView([37.8, -96], 4);
        L.tileLayer('http://{s}.tile.cloudmade.com/{key}/22677/256/{z}/{x}/{y}.png', {
            attribution: 'Map data &copy; 2011 OpenStreetMap contributors, Imagery &copy; 2012 CloudMade',
            key: 'BC9A493B41014CAABB98F0471D759707'
        }).addTo(map);
        geojson = L.geoJson(statesData, {
            style: style
            //onEachFeature: onEachFeature,
        }).addTo(map);
    }

    function init_geojson(n) {
        console.log(geojson.options);
        map.removeLayer(geojson);
        if (n != "") {
            sn = n;
            console.log(sn);
            geojson = L.geoJson(statesData, {
                style: style
            }).addTo(map);
        }
    }

    function style(feature) {
        console.log(sn);
        if (sn == feature.properties.name) {
            return {
                weight: 2,
                opacity: 1,
                color: 'white',
                dashArray: '3',
                fillOpacity: 0.3,
                fillColor: '#ff0000'
            };
        } else {
            return {
                weight: 2,
                opacity: 1,
                color: 'white',
                dashArray: '3',
                fillOpacity: 0.3,
                fillColor: '#666666'
            };
        }
    }
</script>
<input type="text" id="statename" value="Alaska">
<input type="button" id="btn" value="Set Color"/>
</body>
</html>
albert
  • 171
  • 2
  • 10
Farhat Abbas
  • 2,727
  • 1
  • 16
  • 14
0

I'm adding this as a secondary answer because this question kept coming up while trying to articulate my problem into a Google search.

Basically I had an L.LayerGroup composed of several L.Layer objects which were made form GeoJSONs. The features in these layers were visualized as L.CircleMarker objects already. I wanted to make it so that I could modify the properties of the underlying features in the layer in a sidebar and have those changes reflected in the layer immediately by changing their colour.

Since everything was a bunch of L.Layer objects inside an L.LayerGroup objects however, I could not set the style on the L.LayerGroup directly, and so I had to go one level deeper:

var buildingCircleMarkerStyle = function(propertyName) {
    switch (propertyName) {
        case 'A':
            return {radius: 8, fillColor: "#cc9200", color: "#000000", weight: 1, opacity: 1, fillOpacity: 1}
        case 'B':
            return {radius: 8, fillColor: "#a0f545", color: "#000000", weight: 1, opacity: 1, fillOpacity: 1}
        default:
            return {radius: 4, fillColor: "#888888", color: "#000000", weight: 1, opacity: 1, fillOpacity: 1}
    }
}

var buildingMarker = function (feature, latlng) {
    return L.circleMarker(latlng, buildingCircleMarkerStyle(feature.properties["buildingProperty"]))
}
buildingLayerGroup.eachLayer(function (layer) {
    layer.eachLayer(function (subLayer) {
        console.log(subLayer);
        subLayer.setStyle(buildingCircleMarkerStyle(subLayer.feature.properties["buildingProperty"]));
})

I don't know if this is the correct way to do it but it seems to work for my purposes.

wfgeo
  • 3,538
  • 2
  • 24
  • 47