Reputation: 612
I have a map created with React-Leaflet that displays Ellipses created with Leaflet.ellipse and React-Leaflet Core API.
I'm passing a mouse event handler to the ellipse's eventHandlers prop. When I hover the mouse over the ellipse, the fillOpacity
is changed from 0.0 to 0.5, then changed from 0.5 to 0.0 on mouse out.
The problem is that when the event is triggered, the fillOpacity
for every ellipse changes rather than just the ellipse that is being hovered over. How can I make it so that only the specific ellipse being hovered over has its fillOpacity
changed?
const Map = () => {
const [map, setMap] = useState(null);
const [fillOpacity, setFillOpacity] = useState(0)
const onMouseEvent = (event, type) => {
switch (type) {
case 'over':
setFillOpacity(0.5)
break
case 'out':
setFillOpacity(0.0)
break
default:
break
}
}
return (
<>
<MapContainer
center={[38, -82]}
zoom={4}
zoomControl={false}
style={{ height: "100vh", width: "100%", padding: 0 }}
whenCreated={map => setMap(map)}
>
<LayersControl position="topright">
<LayersControl.BaseLayer checked name="Map">
<TileLayer
attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url={maps.base}
/>
</LayersControl.BaseLayer>
<LayersControl.Overlay checked name="Ellipses">
<FeatureGroup>
<>{CITIES.map((city, index) => {
return (
<Ellipse
key={index}
center={city.center}
radii={city.radii}
tilt={city.tilt}
pathOptions={{
fillOpacity,
opacity: 1,
weight: 2,
}}
eventHandlers={{
mouseover: (event, type) => onMouseEvent(event, 'over'),
mouseout: (event, type) => onMouseEvent(event, 'out'),
}}
>
<Popup>
<Typography variant='subtitle1'>{city.city}</Typography>
</Popup>
</Ellipse>
)
})}</>
</FeatureGroup>
</LayersControl.Overlay>
</LayersControl>
</MapContainer>
</>
);
};
import { createPathComponent } from '@react-leaflet/core'
import L from 'leaflet'
import 'leaflet-ellipse'
const Ellipse = createPathComponent(createEllipse, updateEllipse)
function createEllipse(props, context) {
const { center, radii, tilt, options } = props
const instance = new L.Ellipse(center, radii, tilt, options)
return {
instance,
context: { ...context, overlayContainer: instance },
}
}
function updateEllipse(instance, props, prevProps) {
if (
props.center !== prevProps.center ||
props.radii !== prevProps.radii ||
props.tilt !== prevProps.tilt ||
props.options !== prevProps.options
) {
instance.setStyle(props.options)
instance.setLatLng(props.center)
instance.setRadius(props.radii)
instance.setTilt(props.tilt)
}
}
export default Ellipse
Upvotes: 0
Views: 487
Reputation: 10676
The problem is that you are using the same state variable for all the elipses. Here:
{CITIES.map((city, index) => {
return (
<Ellipse
key={index}
pathOptions={{
fillOpacity. // <---- problem here
}}
>
...
</Ellipse>
)
})}
So all ellipses are getting their opacity from the fillOpacity
state variable. When you mouse over any of them, the state variable changes, and all of them respond. You'd be better off not handling opacity as a state variable. Just set it to a constant 0, and within the event handler, dig into the target
of the mouseover, and call setStyle
:
const onMouseEvent = (event, type) => {
switch (type) {
case 'over':
event.target.setStyle({ fillOpacity: 0.5 })
break
case 'out':
event.target.setStyle({ fillOpacity: 0.0 })
break
default:
break
}
}
So now each ellipse manages its own opacity directly through leaflet methods, rather than all inheriting their opacity through a too-broadly-applied react state variable.
Upvotes: 2