Skip to content

Instantly share code, notes, and snippets.

@ulises-jeremias
Last active June 22, 2020 03:19
Show Gist options
  • Save ulises-jeremias/fc9bcb39e602b291353c400bb79a6044 to your computer and use it in GitHub Desktop.
Save ulises-jeremias/fc9bcb39e602b291353c400bb79a6044 to your computer and use it in GitHub Desktop.
Responsive Pie implementation using semantic ui react and recharts
import React from 'react'
import PropTypes from 'prop-types'
import {
Responsive,
} from 'semantic-ui-react'
import {
PieChart,
Pie,
ResponsiveContainer,
Sector,
} from 'recharts'
const renderActiveShapeMobile = ({translate}) => {
const ActiveShape = (props) => {
// eslint-disable-next-line react/prop-types
const { cx, cy, innerRadius, outerRadius, startAngle, endAngle, fill, payload, percent, value } = props
return (
<g>
<text x={cx} y={cy} dy={-8} textAnchor="middle" fill={fill}>
{translate(payload.name)}
</text>
<text x={cx} y={cy} dy={8} textAnchor="middle" fill='#333'>
{value}
</text>
<text x={cx} y={cy} dy={24} textAnchor="middle" fill='#999'>
{`${(percent * 100).toFixed(2)}%`}
</text>
<Sector
cx={cx}
cy={cy}
innerRadius={innerRadius}
outerRadius={outerRadius}
startAngle={startAngle}
endAngle={endAngle}
fill={fill}
/>
<Sector
cx={cx}
cy={cy}
startAngle={startAngle}
endAngle={endAngle}
innerRadius={outerRadius + 6}
outerRadius={outerRadius + 10}
fill={fill}
/>
</g>
)
}
return ActiveShape
}
const renderActiveShape = ({translate}) => {
const ActiveShape = (props) => {
const RADIAN = Math.PI / 180
// eslint-disable-next-line react/prop-types
const { cx, cy, midAngle, innerRadius, outerRadius, startAngle, endAngle, fill, payload, percent, value } = props
const sin = Math.sin(-RADIAN * midAngle)
const cos = Math.cos(-RADIAN * midAngle)
const sx = cx + (outerRadius + 10) * cos
const sy = cy + (outerRadius + 10) * sin
const mx = cx + (outerRadius + 45) * cos
const my = cy + (outerRadius + 45) * sin
const ex = mx + (cos >= 0 ? 1 : -1) * 22
const ey = my
const textAnchor = cos >= 0 ? 'start' : 'end'
return (
<g>
<Sector
cx={cx}
cy={cy}
innerRadius={innerRadius}
outerRadius={outerRadius}
startAngle={startAngle}
endAngle={endAngle}
fill={fill}
/>
<Sector
cx={cx}
cy={cy}
startAngle={startAngle}
endAngle={endAngle}
innerRadius={outerRadius + 6}
outerRadius={outerRadius + 10}
fill={fill}
/>
<path d={`M${sx},${sy}L${mx},${my}L${ex},${ey}`} stroke={fill} fill='none' />
<circle cx={ex} cy={ey} r={2} fill={fill} stroke='none' />
<text x={ex + (cos >= 0 ? 1 : -1) * 12} y={ey} dy={-18} textAnchor={textAnchor} fill={fill}>
{translate(payload.name)}
</text>
<text x={ex + (cos >= 0 ? 1 : -1) * 12} y={ey} textAnchor={textAnchor} fill='#333'>
{value}
</text>
<text x={ex + (cos >= 0 ? 1 : -1) * 12} y={ey} dy={18} textAnchor={textAnchor} fill='#999'>
{`${(percent * 100).toFixed(2)}%`}
</text>
</g>
)
}
return ActiveShape
}
const ResponsivePie = props => {
const {
translate,
innerRadius,
outerRadius,
view,
...rest
} = props
let shapeRenderer = {}
if (view === 'mobile') {
shapeRenderer = {
mobile: renderActiveShapeMobile({translate}),
screen: renderActiveShapeMobile({translate}),
}
} else if (view === 'screen') {
shapeRenderer = {
mobile: renderActiveShape({translate}),
screen: renderActiveShape({translate}),
}
} else {
shapeRenderer = {
mobile: renderActiveShapeMobile({translate}),
screen: renderActiveShape({translate}),
}
}
return (
<>
<Responsive
maxWidth={575}
style={{height: '100%'}}
>
<ResponsiveContainer>
<PieChart>
<Pie
{...rest}
innerRadius={innerRadius - 40}
outerRadius={outerRadius - 40}
activeShape={shapeRenderer.mobile}
/>
</PieChart>
</ResponsiveContainer>
</Responsive>
<Responsive
minWidth={576}
maxWidth={750}
style={{height: '100%'}}
>
<ResponsiveContainer>
<PieChart>
<Pie
{...rest}
innerRadius={innerRadius - 40}
outerRadius={outerRadius - 40}
activeShape={shapeRenderer.screen}
/>
</PieChart>
</ResponsiveContainer>
</Responsive>
<Responsive
minWidth={751}
maxWidth={1300}
style={{height: '100%'}}
>
<ResponsiveContainer>
<PieChart>
<Pie
{...rest}
innerRadius={innerRadius}
outerRadius={outerRadius}
activeShape={shapeRenderer.mobile}
/>
</PieChart>
</ResponsiveContainer>
</Responsive>
<Responsive
minWidth={1301}
style={{height: '100%'}}
>
<ResponsiveContainer>
<PieChart>
<Pie
{...rest}
innerRadius={innerRadius}
outerRadius={outerRadius}
activeShape={shapeRenderer.screen}
/>
</PieChart>
</ResponsiveContainer>
</Responsive>
</>
)
}
ResponsivePie.defaultProps = {
view: 'all',
}
ResponsivePie.propTypes = {
translate: PropTypes.func.isRequired,
innerRadius: PropTypes.number.isRequired,
outerRadius: PropTypes.number.isRequired,
view: PropTypes.oneOf([
'mobile',
'screen',
'all'
])
}
export default ResponsivePie
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment