I am using Recharts to create a simple pie chart. My issue likely stems from the fact the entire thing is SVG-based. I would like to have a selected pie slice change color (both fill and stroke). So I do the following:
import { useState } from 'react'; import { Sector, Pie, PieChart, ResponsiveContainer } from 'recharts'; export function SinglePie({ data }) { const [selectedCellLabel, setHighlightedCell] = useState(undefined); const onMouseEnter = (event) => setHighlightedCell(event.payload.payload.label); const onMouseLeave = () => setHighlightedCell(undefined); function renderActiveShape(props) { return <Sector {...props} fill="#CFBCF7" stroke="#7C53E4" />; } return ( <ResponsiveContainer width="100%" height="100%"> <PieChart> <Pie data={data} activeIndex={data.findIndex((datum) => datum.label === selectedCellLabel)} activeShape={renderActiveShape} dataKey={ChartDataKeys.VALUE} nameKey={ChartDataKeys.LABEL} fill="#CEF1EE" stroke="#64E0D5" onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave} /> </PieChart> </ResponsiveContainer> ); }
Then render with:
<div style={{ width: 250, height: 250 }}> <SinglePie data={[ { label: 'First Slice', value: 4, }, { label: 'Second Slice', value: 6, }, { label: 'Third Slice', value: 2, }, ]} /> </div>
And unfortunately, on hovering the First Slice, what I see is this:
However, hovering the Third Slice looks ok:
You can see the difference between stroke width in the two cases. this is because the SVG slices overlap each other.
I know that SVG rendering is based on order, and adding a z
prop won’t help. But what will?
I would like to be able to see all slices with their strokes, as is required by my UI designer:
Advertisement
Answer
You can use .raise()
function of d3 library.
First, you need to add <script src="https://d3js.org/d3.v7.min.js"></script>
tag to your index.html
.
And then you can move the selected slice to last in your onMouseEnter
function like this:
const onMouseEnter = (event) => { setHighlightedCell(event.payload.payload.label); const selectedIndex = data.findIndex( (datum) => datum.label === event.payload.payload.label ); if (selectedIndex > -1) { const gListItem = d3.select( `.recharts-pie-sector:has(path[name="${event.payload.payload.label}"])` ); gListItem.raise(); } };
You can take a look at this stackblitz for a live working example of this solution.