Created
September 24, 2016 15:21
-
-
Save ryaninvents/f7930248e3e899de8c9cf8a9c23e2d34 to your computer and use it in GitHub Desktop.
Fun React component for animating a changing number
This file contains hidden or 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'; | |
/** | |
* @param {number} t Number between 0 and 1 indicating the progress of the ease. | |
* @param {number} startValue | |
* @param {number} endValue | |
*/ | |
function easeOut(t, startValue, endValue) { | |
const c = endValue - startValue; | |
const p = t - 1; | |
return (-c * ((p * p * p * p) - 1)) + startValue; | |
} | |
export default class SpinCounter extends React.Component { | |
static propTypes = { | |
value: React.PropTypes.number.isRequired, | |
duration: React.PropTypes.number, | |
easing: React.PropTypes.func, | |
}; | |
constructor(props) { | |
super(props); | |
this.state = { | |
lastValue: props.value, | |
displayValue: props.value, | |
startTime: +new Date(), | |
}; | |
} | |
componentDidMount() { | |
setTimeout(() => this.setState({ | |
lastValue: this.props.value, | |
startTime: +new Date(), | |
displayValue: this.props.value, | |
}), 0); | |
this.animInterval = setInterval(() => this.updateDisplayValue(), 1000 / 32); | |
} | |
componentWillReceiveProps(newProps) { | |
const now = +new Date(); | |
this.setState({ | |
lastValue: this.state.displayValue, | |
startTime: now, | |
}); | |
this.updateDisplayValue(newProps, now); | |
} | |
componentWillUnmount() { | |
clearInterval(this.animInterval); | |
} | |
updateDisplayValue(inprops, instartTime) { | |
const now = +new Date(); | |
const props = inprops || this.props; | |
const startTime = instartTime || this.state.startTime; | |
const duration = this.props.duration || 1000; | |
const ease = this.props.easing || easeOut; | |
const t = Math.max(0, Math.min(1, (now - startTime) / duration)); | |
if (Math.abs(this.state.displayValue - props.value) < 1) { | |
this.setState({ displayValue: this.props.value }); | |
return; | |
} | |
const displayValue = ease( | |
t, | |
this.state.lastValue, | |
props.value | |
); | |
this.setState({ displayValue }); | |
} | |
render() { | |
return (<div className="counter"> | |
{Math.round(this.state.displayValue)} | |
</div>); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment