Strategy 4: react internal state
In the previous lesson, we learned how to modify a hovered graph item using the :hover
CSS pseudo-class.
However, this approach has design limitations. To achieve a more effective highlighting effect, it's better to simultaneously dim the other graph items.
This can be accomplished using CSS alone, with the help of the CSS descendant selector.
Internal state & event listener
Add onMouseEnter event listener to all circle
Set an internal state
Trigger a redraw of all circles with conditional state.
As for the tooltip example above, everything starts with an internal state (called hoveredGroup
) that stores which circle is hovered hover.
const [hoveredGroup, setHoveredGroup] = useState<string | null>(null);
Now, this state needs to be updated when a user hovers over the circle. setHoveredGroup
can be passed as a callback to the onMouseOver
attribute of each circle.
On top of this, some specific css classes can be attributed to circles depending on the circle that is hovered hover. In the example above, a class called dimmed
is added to circles that must disappear.
To put it in a nutshell, the circles are created as follows:
const allShapes = data.map((d, i) => {
const className = // class if the circle depends on the hover state
hoveredGroup && d.group !== hoveredGroup
? styles.scatterplotCircle + " " + styles.dimmed
: styles.scatterplotCircle;
return (
<circle
key={i}
r={5}
cx={xScale(d.x)}
cy={yScale(d.y)}
className={className} // class is attributed here
stroke={colorScale(d.group)}
fill={colorScale(d.group)}
onMouseOver={() => setHoveredGroup(d.group)} // callback to update the state
onMouseLeave={() => setHoveredGroup(null)} // and to set it back to null
/>
);
});
Last but not least, some css needs to be added to customize the circle depending on if they are in default, .dimmed
or :hover
mode.
Note that the filter: saturate(0)
is a good way to dim unwanted circles. Also, playing with transition-delay
and transition-duration
adds to animate the transition is a nice touch you should consider. Check the code below the example to see the full css.
TODO.
Pros & Cons
- Allows to sync the hover effect with other UI updates. The hovered state can be used to update any other react components in the application. Like tooltip or another graph.
- Using javascript to trigger the animation can give more flexibility to customize the hover effect, using react-spring for instance.
- Performance 🚨. Here we are redrawing all the circles each time a hover effect is hovered. This can be dramatic if you have thousands of circles!
More examples
The examples below all use this strategy to implement their hover effect.