Skip to content

Instantly share code, notes, and snippets.

@cevek
Last active July 25, 2016 12:37
Show Gist options
  • Save cevek/148bcee6b11e1a221e2fe1518aecc142 to your computer and use it in GitHub Desktop.
Save cevek/148bcee6b11e1a221e2fe1518aecc142 to your computer and use it in GitHub Desktop.
import './AnimatedNumber.scss';
export class AnimatedNumber extends zx.react.Component {
isAnimation = false;
duration = 1000;
oldValue = this.props.value;
oldRawValue = +this.props.rawValue || +this.props.value;
currentValue = this.props.value;
currentRawValue = +this.props.rawValue || +this.props.value;
nextValue;
nextRawValue;
findProp(style, props) {
for (let i = 0; i < props.length; i++) {
if (style[props[i]] !== undefined) {
return props[i];
}
}
throw new Error('prop not found');
}
_animate(value, rawValue) {
const {vendorTransform, vendorTransition, vendorTransformText} = AnimatedNumber;
this.currentValue = value;
this.currentRawValue = rawValue;
if (this.isAnimation) {
this.nextValue = value;
this.nextRawValue = rawValue;
return;
}
this.isAnimation = true;
const numberLayout = this.refs.numberLayout;
if (numberLayout) {
const oldValue = this.oldValue;
const oldRawValue = this.oldRawValue;
let fromUp = true;
if (Number.isFinite(rawValue) && Number.isFinite(oldRawValue)) {
fromUp = rawValue > oldRawValue;
}
numberLayout.textContent = fromUp ? value + '\n' + oldValue : oldValue + '\n' + value;
numberLayout.style[vendorTransform] = `translateY(${fromUp ? '-1em' : '0'})`;
//noinspection BadExpressionStatementJS
numberLayout.offsetHeight;
numberLayout.style[vendorTransition] = `${vendorTransformText} ease-in-out ${Math.floor(this.duration * 10 / 1000) / 10}s`;
numberLayout.style[vendorTransform] = `translateY(${fromUp ? '0' : '-1em'})`;
setTimeout(() => {
numberLayout.textContent = value;
this.oldValue = value;
this.oldRawValue = rawValue;
numberLayout.style[vendorTransform] = '';
numberLayout.style[vendorTransition] = '';
this.isAnimation = false;
if (this.nextValue) {
//force pause animation before update animation behavior
//noinspection BadExpressionStatementJS
numberLayout.offsetHeight;
this._animate(this.nextValue, this.nextRawValue);
this.nextValue = null;
this.nextRawValue = null;
}
}, this.duration + 1000);
}
}
componentWillReceiveProps(nextProps) {
const value = nextProps.value;
const duration = this.props.duration;
if (Number.isFinite(duration) && !Number.isNaN(duration)) {
this.duration = duration;
}
if (value !== this.currentValue) {
this._animate(value, nextProps.rawValue);
}
}
shouldComponentUpdate() {
return false;
}
componentWillMount() {
if (!AnimatedNumber.vendorTransform) {
AnimatedNumber.vendorTransform = this.findProp(document.body.style, ['transform', 'webkitTransform', 'mozTransform', 'msTransform']);
AnimatedNumber.vendorTransformText = {
transform: 'transform',
webkitTransform: '-webkit-transform',
mozTransform: '-moz-transform',
msTransform: '-ms-transform'
}[AnimatedNumber.vendorTransform];
AnimatedNumber.vendorTransition = this.findProp(document.body.style, ['transition', 'webkitTransition', 'mozTransition', 'msTransition']);
}
}
render() {
return <div className="animated-number-wrapper">
<div ref="numberLayout" className="animated-number">{this.props.value}</div>
</div>
}
}
.animated-number-wrapper{
white-space: pre;
overflow: hidden;
height: 1em;
line-height: 1em;
display: inline-block;
vertical-align: middle;
}
.animated-number {
will-change: transform;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment