Skip to content

Instantly share code, notes, and snippets.

@ryaninvents
Created September 24, 2016 15:21
Show Gist options
  • Save ryaninvents/f7930248e3e899de8c9cf8a9c23e2d34 to your computer and use it in GitHub Desktop.
Save ryaninvents/f7930248e3e899de8c9cf8a9c23e2d34 to your computer and use it in GitHub Desktop.
Fun React component for animating a changing number
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