Last active
February 13, 2024 14:30
-
-
Save emiloberg/ee549049ea0f6b83e25f1a1110947086 to your computer and use it in GitHub Desktop.
Gauge Chart with React Recharts (http://recharts.org)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react'; | |
import { Sector, Cell, PieChart, Pie } from 'recharts'; | |
const GaugeChart = () => { | |
const width = 500; | |
const chartValue = 180; | |
const colorData = [{ | |
value: 40, // Meaning span is 0 to 40 | |
color: '#663399' | |
}, { | |
value: 100, // span 40 to 140 | |
color: '#e91e63' | |
}, { | |
value: 50, // span 140 to 190 | |
color: '#ff9800' | |
}, { | |
value: 20, | |
color: '#4caf50' | |
} | |
]; | |
const activeSectorIndex = colorData.map((cur, index, arr) => { | |
const curMax = [...arr] | |
.splice(0, index + 1) | |
.reduce((a, b) => ({ value: a.value + b.value })) | |
.value; | |
return (chartValue > (curMax - cur.value)) && (chartValue <= curMax); | |
}) | |
.findIndex(cur => cur); | |
const sumValues = colorData | |
.map(cur => cur.value) | |
.reduce((a, b) => a + b); | |
const arrowData = [ | |
{ value: chartValue }, | |
{ value: 0 }, | |
{ value: sumValues - chartValue } | |
]; | |
const pieProps = { | |
startAngle: 180, | |
endAngle: 0, | |
cx: width / 2, | |
cy: width / 2 | |
}; | |
const pieRadius = { | |
innerRadius: (width / 2) * 0.35, | |
outerRadius: (width / 2) * 0.4 | |
}; | |
const Arrow = ({ cx, cy, midAngle, outerRadius }) => { //eslint-disable-line react/no-multi-comp | |
const RADIAN = Math.PI / 180; | |
const sin = Math.sin(-RADIAN * midAngle); | |
const cos = Math.cos(-RADIAN * midAngle); | |
const mx = cx + (outerRadius + width * 0.03) * cos; | |
const my = cy + (outerRadius + width * 0.03) * sin; | |
return ( | |
<g> | |
<circle cx={cx} cy={cy} r={width * 0.05} fill="#666" stroke="none"/> | |
<path d={`M${cx},${cy}L${mx},${my}`} strokeWidth="6" stroke="#666" fill="none" strokeLinecap="round"/> | |
</g> | |
); | |
}; | |
const ActiveSectorMark = ({ cx, cy, innerRadius, outerRadius, startAngle, endAngle, fill }) => { //eslint-disable-line react/no-multi-comp | |
return ( | |
<g> | |
<Sector | |
cx={cx} | |
cy={cy} | |
innerRadius={innerRadius} | |
outerRadius={outerRadius * 1.2} | |
startAngle={startAngle} | |
endAngle={endAngle} | |
fill={fill} | |
/> | |
</g> | |
); | |
}; | |
return ( | |
<PieChart width={width} height={(width / 2) + 30}> | |
<Pie | |
activeIndex={activeSectorIndex} | |
activeShape={ActiveSectorMark} | |
data={colorData} | |
fill="#8884d8" | |
{ ...pieRadius } | |
{ ...pieProps } | |
> | |
{ | |
colorData.map((entry, index) => ( | |
<Cell key={`cell-${index}`} fill={colorData[index].color} /> | |
)) | |
} | |
</Pie> | |
<Pie | |
stroke="none" | |
activeIndex={1} | |
activeShape={ Arrow } | |
data={ arrowData } | |
outerRadius={ pieRadius.innerRadius } | |
fill="none" | |
{ ...pieProps } | |
/> | |
</PieChart> | |
); | |
}; | |
export default GaugeChart; |
Hello, do you have a demo page available?
Great work emiloberg!
Here's a quick demo of the chart component: https://react-gaugechart-emiloberg.stackblitz.io Nice work on this component!
Possible to make it responsive?
Great example, thank you for posting this!
I've absolutely no recollection of me creating this (but there are some tells in the code that it's indeed written by me 😄), or what I used it for, but I'm happy it's helping you! And thanks @chambleton for creating that demo!
You're welcome! I had forgotten all about it!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Nice job emiloberg. Any suggestion for placing the labels too in the sectors?