Last active
January 11, 2017 18:36
-
-
Save Eldelshell/40d10c3e343dec98e704a42f50ce815e to your computer and use it in GitHub Desktop.
React Native Pie Chart
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, { PropTypes } from 'react'; | |
import { View, Platform } from 'react-native'; | |
import { Surface, Shape, Path, Group } from 'ReactNativeART'; | |
/** | |
* Custom implementation of the react-native-circular-progress that allows to | |
* render ART donut charts. Instead of accepting a single set of fill & color values, | |
* this components takes an array of objects. | |
* https://github.com/bgryszko/react-native-circular-progress | |
* @example | |
* <Donut | |
* rotation={0} | |
* size={80} | |
* width={8} | |
* data={[{fill: 80, color: 'red'},{fill: 20, color: 'green'}]} | |
* backgroundColor='orange'></Donut> | |
*/ | |
export default class Donut extends React.Component { | |
static propTypes = { | |
style: View.propTypes.style, | |
size: PropTypes.number.isRequired, | |
width: PropTypes.number.isRequired, | |
backgroundColor: PropTypes.string, | |
rotation: PropTypes.number, | |
linecap: PropTypes.string, | |
children: PropTypes.func, | |
data: PropTypes.array.isRequired | |
} | |
static defaultProps = { | |
backgroundColor: '#e4e4e4', | |
rotation: 90, | |
linecap: 'butt', | |
data: [] | |
} | |
componentWillMount() { | |
// Check we reach 100 | |
const sum = this.props.data.map((d) => d.fill).reduce((i, j) => i + j); | |
if(sum > 100){ | |
console.warn(`[Donut] Total values (${sum}) are higher than 100`); | |
}else if(sum < 100){ | |
console.warn(`[Donut] Total values (${sum}) are less than 100`); | |
} | |
} | |
circlePath(cx, cy, r, startDegree, endDegree) { | |
const p = Path(); | |
if (Platform.OS === 'ios') { | |
p.path.push(0, cx + r, cy); | |
p.path.push(4, cx, cy, r, startDegree * Math.PI / 180, endDegree * Math.PI / 180, 1); | |
} else { | |
// For Android we have to resort to drawing low-level Path primitives, as ART does not support | |
// arbitrary circle segments. It also does not support strokeDash. | |
// Furthermore, the ART implementation seems to be buggy/different than the iOS one. | |
// MoveTo is not needed on Android | |
p.path.push(4, cx, cy, r, startDegree * Math.PI / 180, (startDegree - endDegree) * Math.PI / 180, 0); | |
} | |
return p; | |
} | |
extractFill(fill) { | |
if (fill < 0.01) { | |
return 0; | |
} else if (fill > 100) { | |
return 100; | |
} | |
return fill; | |
} | |
renderCircle(fill, color, width, linecap, size) { | |
const f = this.extractFill(fill); | |
const circlePath = this.circlePath(size / 2, size / 2, size / 2 - width / 2, 0, 360 * f / 100); | |
return ( | |
<Shape d={circlePath} stroke={color} strokeWidth={width} strokeCap={linecap}/> | |
); | |
} | |
renderCircles() { | |
const { size, width, backgroundColor, rotation, linecap } = this.props; | |
const backgroundPath = this.circlePath(size / 2, size / 2, size / 2 - width / 2, 0, 360); | |
let prevFill = 0; | |
const circles = []; | |
circles.push(( | |
<Group key='donut-bg' rotation={rotation - 90} originX={size/2} originY={size/2}> | |
<Shape d={backgroundPath} stroke={backgroundColor} strokeWidth={width}/> | |
</Group> | |
)); | |
for (let i = 0; i < this.props.data.length; i++) { | |
const d = this.props.data[i]; | |
circles.push(( | |
<Group key={`d-${i}`} rotation={(rotation - 90) + prevFill} originX={size/2} originY={size/2}> | |
{ this.renderCircle(d.fill, d.color, width, linecap, size) } | |
</Group> | |
)); | |
prevFill = ((360 * d.fill) / 100) + prevFill; | |
} | |
return circles; | |
} | |
render() { | |
const { size, style, children } = this.props; | |
return ( | |
<View style={style}> | |
<Surface width={size} height={size}> | |
{ this.renderCircles() } | |
</Surface> | |
{ children } | |
</View> | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is how it looks:
It's based on the great work of @bgryszko on https://github.com/bgryszko/react-native-circular-progress