import { Easing } from "./Easing" ; import { TweenManager } from "./TweenManager" ; import { EventEmitter } from "eventemitter3" ; import { Log } from "../log/Log" ; export class Tween extends EventEmitter { public target : { } ; public manager : TweenManager | undefined ; private countTime : number = 0 ; public active : boolean = false ; private easingProperty : Function = Easing . linear ( ) ; public expire : boolean = false ; private countRepeat : number = 0 ; private loop : boolean = false ; private delayProperty : number = 0 ; private pingPongProperty : boolean = false ; private isStarted : boolean = false ; public isEnded : boolean = false ; private isUseStartFun : boolean = false ; private toData : { } | null = null ; private fromData : { } | null = null ; private currDelayTime : number = 0 ; private currElapsedTime : number = 0 ; private currRepeat : number = 0 ; private currPingPong : boolean = false ; private chainTween : Tween | null = null ; private _updateDeltaOffsetFun ! : Function ; constructor ( target , manager ? ) { super ( ) ; this . target = target ; if ( manager ) this . addTo ( manager ) ; this . clear ( ) ; } private addTo ( manager ) { this . manager = manager ; this . manager . addTween ( this ) ; return this ; } param time public time ( time ) { this . countTime = time ; return this ; } param easingProperty public easing ( easingProperty ) { this . easingProperty = easingProperty ; return this ; } param pingPong public pingPong ( pingPong ) { this . pingPongProperty = pingPong ; return this ; } param delay public delay ( delay ) { this . delayProperty = delay ; return this ; } param repeat public repeat ( repeat ) { if ( repeat < 0 ) { this . loop = true ; } else { this . loop = false ; } this . countRepeat = repeat ; return this ; } param tween public chain ( tween ) { if ( ! tween ) tween = new Tween ( this . target ) ; this . chainTween = tween ; return tween ; } /**
     * 开始动画
     */ public start ( ) { this . active = true ; this . isUseStartFun = true ; if ( this . delayProperty <= 0 && this . countTime <= 0 ) { this . setAllVal ( ) ; } return this ; } /**
     * 结束动画
     */ public stop ( ) { this . active = false ; this . emit ( "stop" ) ; return this ; } param data public to ( data ) { this . toData = data ; return this ; } param data public from ( data ) { this . fromData = data ; return this ; } /**
     * 从任务队列里删除
     */ public remove ( ) { if ( ! this . manager ) return this ; this . manager . removeTween ( this ) ; return this ; } param expire public setExpire ( expire ) { this . expire = expire ; return this ; } /**
     * 把Tween清空到初始化的地步，如果没有重新设置参数，start无法开启
     */ public clear ( ) { this . countTime = 0 ; this . active = false ; this . easingProperty = Easing . linear ( ) ; this . expire = false ; this . countRepeat = 0 ; this . loop = false ; this . delayProperty = 0 ; this . pingPongProperty = false ; this . isStarted = false ; this . isEnded = false ; this . toData = null ; this . fromData = null ; this . currDelayTime = 0 ; this . currElapsedTime = 0 ; this . currRepeat = 0 ; this . currPingPong = false ; this . chainTween = null ; return this ; } /**
     * 重置Tween，保留参数可以重新执行动画
     */ public reset ( ) { this . currElapsedTime = 0 ; this . currRepeat = 0 ; this . currDelayTime = 0 ; this . isStarted = false ; this . isEnded = false ; if ( this . pingPongProperty && this . currPingPong ) { let toData = this . toData ; let fromData = this . fromData ; this . toData = fromData ; this . fromData = toData ; this . currPingPong = false ; } return this ; } private parseData ( ) { if ( this . isStarted ) return ; if ( ! this . fromData ) this . fromData = { } ; _parseRecursiveData ( this . toData , this . fromData , this . target ) ; } private apply ( time ) { _recursiveApplyTween ( this . toData , this . fromData , this . target , time , this . currElapsedTime , this . easingProperty ) ; } private canUpdate ( ) { return this . countTime && this . active && this . target ; } private canDeltaUpdate ( ) { return this . countTime <= 0 && this . delayProperty > 0 && this . active && this . target ; } setAllVal ( ) { if ( ! this . isStarted ) { this . parseData ( ) ; this . isStarted = true ; this . emit ( "start" ) ; } else { if ( this . isUseStartFun ) { this . emit ( "restart" ) ; } } this . isUseStartFun = false ; this . emit ( "update" , 0 ) ; if ( this . pingPongProperty ) { this . emit ( "pingpong" ) ; this . emit ( "update" , 0 ) ; } this . isEnded = true ; this . active = false ; if ( ! this . pingPongProperty ) { this . currElapsedTime = 1 ; this . apply ( 1 ) ; if ( this . chainTween && this . manager ) { this . chainTween . addTo ( this . manager ) ; this . chainTween . start ( ) ; } } this . emit ( "end" ) ; } setUpdateDeltaOffsetFun ( updateDeltaOffsetFun ) { this . _updateDeltaOffsetFun = updateDeltaOffsetFun ; return this ; } update ( deltaMS ) { if ( this . canDeltaUpdate ( ) ) { if ( this . delayProperty > this . currDelayTime ) { this . currDelayTime += deltaMS ; return ; } this . setAllVal ( ) ; return ; } if ( ! this . canUpdate ( ) && this . toData ) return ; let toData , fromData ; if ( this . _updateDeltaOffsetFun ) { deltaMS += this . _updateDeltaOffsetFun ( deltaMS ) ; } if ( this . delayProperty > this . currDelayTime ) { this . currDelayTime += deltaMS ; return ; } if ( ! this . isStarted ) { this . parseData ( ) ; this . isStarted = true ; this . emit ( "start" ) ; } else { if ( this . isUseStartFun ) { this . emit ( "restart" ) ; } } this . isUseStartFun = false ; let time = this . pingPongProperty ? this . countTime / 2 : this . countTime ; if ( time > this . currElapsedTime ) { let t = this . currElapsedTime + deltaMS ; let ended = t >= time ; this . currElapsedTime = ended ? time : t ; this . apply ( time ) ; let realElapsed = this . currPingPong ? time + this . currElapsedTime : this . currElapsedTime ; this . emit ( "update" , realElapsed ) ; if ( ended ) { if ( this . pingPongProperty && ! this . currPingPong ) { this . currPingPong = true ; toData = this . toData ; fromData = this . fromData ; this . fromData = toData ; this . toData = fromData ; this . emit ( "pingpong" ) ; this . currElapsedTime = 0 ; return ; } if ( this . loop || this . countRepeat > this . currRepeat ) { this . currRepeat ++ ; this . emit ( "repeat" , this . currRepeat ) ; this . currElapsedTime = 0 ; if ( this . pingPongProperty && this . currPingPong ) { toData = this . toData ; fromData = this . fromData ; this . toData = fromData ; this . fromData = toData ; this . currPingPong = false ; } return ; } this . isEnded = true ; this . active = false ; this . emit ( "end" ) ; if ( this . chainTween && this . manager ) { this . chainTween . addTo ( this . manager ) ; this . chainTween . start ( ) ; } } return ; } } } function _recursiveApplyTween ( to , from , target , time , elapsed , easing ) { for ( let k in to ) { if ( ! _isObject ( to [ k ] ) ) { let b = from [ k ] ; let c = to [ k ] - from [ k ] ; let d = time ; let t = elapsed / d ; target [ k ] = b + c * easing ( t ) ; } else { _recursiveApplyTween ( to [ k ] , from [ k ] , target [ k ] , time , elapsed , easing ) ; } } } function _parseRecursiveData ( to , from , target ) { for ( let k in to ) { if ( from [ k ] !== 0 && ! from [ k ] ) { if ( _isObject ( target [ k ] ) ) { if ( from [ k ] == undefined ) { let obj = { } ; for ( let key in to [ k ] ) { obj [ key ] = target [ k ] [ key ] ; } from [ k ] = obj ; } _parseRecursiveData ( to [ k ] , from [ k ] , target [ k ] ) ; } else { from [ k ] = target [ k ] ; } } } } function _isObject ( obj ) { return Object . prototype . toString . call ( obj ) === "[object Object]" ; }