Skip to content

Instantly share code, notes, and snippets.

@emiloberg
Last active February 13, 2024 14:30
Show Gist options
  • Save emiloberg/ee549049ea0f6b83e25f1a1110947086 to your computer and use it in GitHub Desktop.
Save emiloberg/ee549049ea0f6b83e25f1a1110947086 to your computer and use it in GitHub Desktop.
Gauge Chart with React Recharts (http://recharts.org)
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;
@meetajhu
Copy link

Possible to make it responsive?

@cyjeff
Copy link

cyjeff commented Jun 16, 2021

Great example, thank you for posting this!

@emiloberg
Copy link
Author

emiloberg commented Jun 16, 2021

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!

@chambleton
Copy link

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