Hey,
Trying to implement this example:
https://www.mapbox.com/mapbox-gl-js/example/hover-styles
It uses the map method setFeatureState:
https://www.mapbox.com/mapbox-gl-js/api/#map#setfeaturestate
which states:
This method requires the
feature.idattribute on data sets.
I can see from the event object that this library is automatically setting a feature.properties.id, but unfortunately that doesn't appear compatible with map.setFeatureState which needs feature.id.
For example this code has no effect:
handleLineMouseEnter = (e) => {
const {map, feature} = e
const {properties: {id}, source} = feature
map.setFeatureState({id, source}, {hover: true})
}
// ...
<Layer
type="line"
paint={{
'line-color': [
'case', ['boolean', ['feature-state', 'hover'], false],
'#ff0000',
'#ff8f33'
]
}}>
{lines.map((line, idx) => (
<Feature
key={idx}
coordinates={line}
onMouseEnter={this.handleLineMouseEnter}
/>
))}
</Layer>
My naeve suggestion would be that if a user explicitly sets an id prop on the feature, then it could be added to the dataset, ie:
handleLineMouseEnter = (e) => {
console.log(e.feature.id) // line-a
}
<Feature
id="line-a"
coordinates={line}
onMouseEnter={this.handleLineMouseEnter}
/>
@daviestar I opened a PR to fix this.
You can patch the plugin while this is not merge. Your code should now work as expected (ofc, I tested it before submitting the PR).
Here is another example that will be able to achieve what you wanted to do when the PR will be merged (see #603)
Function called onStyleLoad event:
onMapLoaded = (map) => {
this.map = map;
// This is a copy paste of mapbox code
this.map.on("mousemove", "tm-countries", (e) => {
if (e.features.length > 0) {
if (this.hoveredCountry) {
this.map.setFeatureState({source: 'countries-source', id: this.hoveredCountry}, { hover: false});
}
this.hoveredCountry = e.features[0].id;
this.map.setFeatureState({source: 'countries-source', id: this.hoveredCountry}, { hover: true});
}
});
this.map.on("mouseleave", "tm-countries", () => {
if (this.hoveredCountry) {
this.map.setFeatureState({source: 'countries-source', id: this.hoveredCountry}, { hover: false});
}
this.hoveredCountry = null;
});
};
render() {
const multiPolygonPaint = {
'fill-color': '#3bb2d0',
'fill-opacity': ["case",
["boolean", ["feature-state", "hover"], false],
1,
0.5
]
};
const {countriesDataGeoJson} = this.state;
return (
<Map
style={...}
zoom={zoom}
center={center}
onStyleLoad={this.onMapLoaded}
>
<GeoJSONLayer
data={countriesDataGeoJson}
fillPaint={multiPolygonPaint}
layerOptions={{
id: 'tm-countries',
type: 'fill',
}}
id="countries-source"
/>
</Map>
);
Any chance we can get this merged??
Most helpful comment
Any chance we can get this merged??