@figliolia/rn-donut-chart
Version:
An animated donut/pie chart library
97 lines (96 loc) • 3.7 kB
JavaScript
import { Component } from "react";
import { Animated } from "react-native";
import { Circle, Svg } from "react-native-svg";
import { Controller } from "./Controller.js";
import { Styles } from "./Styles.js";
const AnimatedSVG = Animated.createAnimatedComponent(Svg);
const AnimatedCircle = Animated.createAnimatedComponent(Circle);
export class Section extends Component {
draw = new Animated.Value(0);
rotate = new Animated.Value(0);
opacity = new Animated.Value(0);
state = Controller.stateFrom(this.props);
componentDidMount() {
this.animate();
}
shouldComponentUpdate(nextProps) {
if (nextProps.value !== this.props.value) {
this.incrementInterpolations(nextProps);
return false;
}
return true;
}
animate() {
const { easing } = this.props;
const { drawInterpolation, rotateInterpolation } = this.state;
const [delay, duration] = this.delay();
Animated.parallel([
Animated.timing(this.opacity, {
delay,
toValue: 1,
duration: 250,
useNativeDriver: true,
}),
Animated.timing(this.draw, {
delay,
easing,
duration,
useNativeDriver: true,
toValue: drawInterpolation.toValue,
}),
Animated.timing(this.rotate, {
delay,
easing,
duration,
useNativeDriver: true,
toValue: rotateInterpolation.toValue,
}),
]).start();
}
delay() {
const { duration } = this.props;
if (this.isPhaseUpdate) {
const updateDuration = duration / 2;
return [updateDuration + 100, updateDuration];
}
return [this.phaseDelay, duration];
}
incrementInterpolations(props) {
const { drawInterpolation, rotateInterpolation } = this.state;
const nextDraw = drawInterpolation.add(Controller.strokeDashoffset(props));
const nextRotation = rotateInterpolation.add(`${props.rotation || 0}deg`);
this.setState({
drawInterpolation: nextDraw,
rotateInterpolation: nextRotation,
}, () => {
this.animate();
});
}
get phaseDelay() {
const { renderPhase, delay = 0 } = this.props;
return renderPhase === "INITIAL" ? delay : 0;
}
get isPhaseUpdate() {
const { renderPhase } = this.props;
const { drawInterpolation } = this.state;
return (renderPhase === "UPDATE" && drawInterpolation.inputRange.length === 2);
}
render() {
const { size, style, radius, center, stroke, children, strokeWidth, strokeLinecap, circumference, } = this.props;
const { drawInterpolation, rotateInterpolation } = this.state;
return (<AnimatedSVG width={size} height={size} viewBox={`0 0 ${size} ${size}`} style={[
Styles.svg,
{
transform: [
{
rotateZ: this.rotate.interpolate(rotateInterpolation),
},
],
},
style,
]}>
<AnimatedCircle r={radius} cx={center} cy={center} stroke={stroke} originX={center} originY={center} fill="transparent" strokeWidth={strokeWidth} strokeLinecap={strokeLinecap} strokeDasharray={circumference} strokeDashoffset={this.draw.interpolate(drawInterpolation)} opacity={this.opacity.interpolate(Controller.opacityInterpolation)}/>
{children}
</AnimatedSVG>);
}
}