17

Well the title says it all but here is some code so you see what i mean.

function eachFeature(feature, layer) {
     layer.on({
         mouseover: highlightFeature,
         mouseout: resetHighlight,
     });
}
geojson = L.geoJson(geojson_raw, { style: style, onEachFeature: eachFeature });
geojson.addTo(map);

geojson_raw is the geojson object which is held in a javascript variable. style is just the function that returns an object with some style attributes. highlightFeature / resetHighlight are functions to change these styles according to mousein/out events.

So this code works and I already know how to change styles by reacting on user events. But how can I set an actual css-classname on the paths that are created from my geojson data? Later in my code I would like to select paths by a specific classname.

UPDATE

2 years later I stumbled over this issue once again. And it took me 2 hours to solve the mystery. The accepted answer below does work, BUT there is a catch. It only works if you set the cssClass before you call addTo(map) on the layer. After finally digging it up in the source code it became clear that leaflet only sets the cssClass when each path gets initialised.

mwallisch
  • 1,751
  • 2
  • 21
  • 29

7 Answers7

13

The code below will allow you to add a class after the paths are created by the geoJosn method with D3.

var svg = d3.select(map.getPanes().overlayPane).append("svg"),
g = svg.append("g").attr("class", "your_class");

However, if you want to add them on creation using only leaflet, try returning them in the style(feature) method like this:

function style(feature) {
        return {
          weight: 1,
          opacity: .5,
          fillOpacity: 0.7,
          className: feature.properties.name_of_node
        };
}

That worked really well for me.

Mr. Concolato
  • 2,224
  • 5
  • 24
  • 44
  • 6
    the question is about setting a css class with leaflet - not d3. – mwallisch Feb 08 '14 at 10:43
  • Understood, but if there is some limitation with leaflet that obstructs this approach. Can one use another library like D3 to do so? I am currently trying to do something similar and using leaflet and D3. Seems to do what you are asking. But, if only want to work with leaflet to set a class, then what i am suggestion is useless. Let me know, and i will remove my post. Just trying to help and learn. – Mr. Concolato Feb 08 '14 at 15:21
  • Are you layering a choropleth onto your map and trying to add a class to the g:path elements? like this example? http://leafletjs.com/examples/choropleth.html – Mr. Concolato Feb 08 '14 at 15:25
  • actually I don't remember what I wanted to do with the css class, the question is 6 months old now... But it is always my intention to separate styling and logic as good as possible. So instead of declaring the styles directly inside my javascript/application-logic I only want to set a css class on a line/rect/circle/path and leave the correct styling of that element to the stylesheet. – mwallisch Feb 09 '14 at 10:52
  • 8
    `className: SOME_CLASS` answers the question. – s2t2 Jan 06 '15 at 22:11
4

You can either add a "className" attribute to your style object, or add the class later like this:

function eachFeature(feature, layer) {
     layer.on({
         mouseover: highlightFeature,
         mouseout: resetHighlight,
     });
}
geojson = L.geoJson(geojson_raw, { style: style, onEachFeature: eachFeature });
geojson.setStyle({'className': 'map-path'}); //will add the required class
geojson.addTo(map);
the_web
  • 406
  • 1
  • 4
  • 11
0

Using Leaflet 1.x, here is a slightly different way to do this - in my case the map was already initialized, so the className styling mentioned above did not work.

function eachFeature(feature, layer) {
     layer.on({
         mouseover: function(e) {$(e.target.getElement()).addClass("active");},
         mouseout: function(e) {$(e.target.getElement()).removeClass("active");}
     });
}

You can also set the class attribute directly using setAttribute on e.target.getElement() if you're not using jQuery.

jean-baptiste
  • 674
  • 7
  • 18
0

Something like this should do the trick. feature._container exposes the underlying DOM element, so you can use regular DOM operations on it (e.g. classList on modern browsers, or setAttribute('class', 'someClass') in older browsers).

function eachFeature(feature, layer) {
     // Need to use setTimeout hack so the DOM container will be
     // available.  WARNING: may cause race condition issues,
     // maybe tie into some other timing event?
     window.setTimeout(function() {
         feature._container && feature._container.classList.add('someClass');
     }, 0);
}
geojson = L.geoJson(geojson_raw, { onEachFeature: eachFeature });
geojson.addTo(map);
David Calhoun
  • 8,315
  • 4
  • 30
  • 23
0

If the GeoJSON layer has already been added to the map then the following solution worked for me:

leafletGeoJSONLayer.eachLayer(function (layer) {
  let container = layer._path;
  container.classList.add("your-css-class");    
});

If the css identifier is already used by leaflet (e.g. cursor) you should add !important to the css key value pair.

René K
  • 337
  • 5
  • 14
-1

If you use SVG, then you can get container as this._container and update it class.

If you use Canvas, then there are will be problems, because canvas drowning don't support DOM styles and drawing with content.

So you can't use styles with different implementations and better use styles.

tbicr
  • 24,790
  • 12
  • 81
  • 106
  • 2
    Yes but how exactly? I also am trying to do the same thing and since this question has already been asked - i will not repeat it. – Mr. Concolato Feb 07 '14 at 21:18
-1

Expanding on @tbicr s answer, you should be able to do something like this:

function onEachFeature(feature, path) {
  path.on('click', addClass);
}

function addClass(e){
    var path = e.target;
    var container = path._container;
    $(container).attr('class', 'test');
}

geojson = L.geoJson(geojson_raw, { style: style, onEachFeature: eachFeature });
geojson.addTo(map);

EDIT: As always, I would be glad flor an explanation, if you decide to downvote, so I can improve it. This is the only answer so far, which describes how to add a class dynamically in detail and I can't see whats wrong with it.

hugo der hungrige
  • 12,382
  • 9
  • 57
  • 84
  • `path` needs to be called like `path.on('click', addClass)`, right? – maackle Nov 19 '14 at 18:42
  • @maackle: Looks cleaner, but it should also work with the object notation. See: http://stackoverflow.com/questions/8608145/jquery-on-method-with-multiple-event-handlers-to-one-selector – hugo der hungrige Nov 19 '14 at 22:00
  • thanks I didn't realize. I'll remove my downvote if your answer includes calling `onEachFeature` like in the OP's code. – maackle Nov 20 '14 at 21:15
  • This was the answer that worked for me! Just a minor change since 2014: The class has to be added to `e.sourceTarget._path` – René K Feb 16 '22 at 06:53