123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175 |
- /**
- * @author wkh237
- * @version 0.1.1
- */
-
- // @flow
-
- import React, { Component } from 'react';
- import {
- Text,
- View
- } from 'react-native';
- import Timer from 'react-timer-mixin';
-
- const HALF_RAD = Math.PI/2
-
- export default class AnimateNumber extends Component {
-
- props : {
- countBy? : ?number,
- interval? : ?number,
- steps? : ?number,
- value : number,
- timing : 'linear' | 'easeOut' | 'easeIn' | () => number,
- formatter : () => {},
- onProgress : () => {},
- onFinish : () => {}
- };
-
- static defaultProps = {
- interval : 14,
- timing : 'linear',
- steps : 45,
- value : 0,
- formatter : (val) => val,
- onFinish : () => {}
- };
-
- static TimingFunctions = {
-
- linear : (interval:number, progress:number):number => {
- return interval
- },
-
- easeOut : (interval:number, progress:number):number => {
- return interval * Math.sin(HALF_RAD*progress) * 5
- },
-
- easeIn : (interval:number, progress:number):number => {
- return interval * Math.sin((HALF_RAD - HALF_RAD*progress)) * 5
- },
-
- };
-
- state : {
- value? : ?number,
- displayValue? : ?number
- };
-
- /**
- * Animation direction, true means positive, false means negative.
- * @type {bool}
- */
- direction : bool;
- /**
- * Start value of last animation.
- * @type {number}
- */
- startFrom : number;
- /**
- * End value of last animation.
- * @type {number}
- */
- endWith : number;
-
- constructor(props:any) {
- super(props);
- // default values of state and non-state variables
- this.state = {
- value : 0,
- displayValue : 0
- }
- this.dirty = false;
- this.startFrom = 0;
- this.endWith = 0;
- }
-
- componentDidMount() {
- this.startFrom = this.state.value
- this.endWith = this.props.value
- this.dirty = true
- this.startAnimate()
- }
-
- componentWillUpdate(nextProps, nextState) {
-
- // check if start an animation
- if(this.props.value !== nextProps.value) {
- this.startFrom = this.props.value
- this.endWith = nextProps.value
- this.dirty = true
- this.startAnimate()
- return
- }
- // Check if iterate animation frame
- if(!this.dirty) {
- return
- }
- if (this.direction === true) {
- if(parseFloat(this.state.value) <= parseFloat(this.props.value)) {
- this.startAnimate();
- }
- }
- else if(this.direction === false){
- if (parseFloat(this.state.value) >= parseFloat(this.props.value)) {
- this.startAnimate();
- }
- }
-
- }
-
- render() {
- return (
- <Text {...this.props}>
- {this.state.displayValue}
- </Text>)
- }
-
- startAnimate() {
-
- let progress = this.getAnimationProgress()
-
- Timer.setTimeout(() => {
-
- let value = (this.endWith - this.startFrom)/this.props.steps
- if(this.props.countBy)
- value = Math.sign(value)*Math.abs(this.props.countBy)
- let total = parseFloat(this.state.value) + parseFloat(value)
-
- this.direction = (value > 0)
- // animation terminate conditions
- if (((this.direction) ^ (total <= this.endWith)) === 1) {
- this.dirty = false
- total = this.endWith
- this.props.onFinish(total, this.props.formatter(total))
- }
-
- if(this.props.onProgress)
- this.props.onProgress(this.state.value, total)
-
- this.setState({
- value : total,
- displayValue : this.props.formatter(total)
- })
-
- }, this.getTimingFunction(this.props.interval, progress))
-
- }
-
- getAnimationProgress():number {
- return (this.state.value - this.startFrom) / (this.endWith - this.startFrom)
- }
-
- getTimingFunction(interval:number, progress:number) {
- if(typeof this.props.timing === 'string') {
- let fn = AnimateNumber.TimingFunctions[this.props.timing]
- return fn(interval, progress)
- } else if(typeof this.props.timing === 'function')
- return this.props.timing(interval, progress)
- else
- return AnimateNumber.TimingFunctions['linear'](interval, progress)
- }
-
- }
|