interface UpdatableItem { _unmounted ? : boolean ; update : ( ) => any ; } export class RAFLoop { description private readonly targets : UpdatableItem [ ] = [ ] ; description private animationFrameID : number = 0 ; description private _isActive : boolean = false ; description public get isActive ( ) : boolean { return this . _isActive ; } description public start = ( ) : this => { if ( ! this . _isActive && this . targets . length ) { this . _isActive = true ; this . animationFrameID && cancelAnimationFrame ( this . animationFrameID ) ; this . animationFrameID = requestAnimationFrame ( this . rafCallback ) ; } return this ; } ; description public stop = ( ) : this => { if ( this . _isActive ) { this . _isActive = false ; this . animationFrameID && cancelAnimationFrame ( this . animationFrameID ) ; this . animationFrameID = 0 ; } return this ; } ; description public addTarget = ( target , silent = false ) : this => { if ( this . targets . indexOf ( target ) === - 1 ) { this . targets . push ( target ) ; this . targets . length === 1 && ! silent && this . start ( ) ; } return this ; } ; description public removeTarget = ( target ) : this => { const idx = this . targets . indexOf ( target ) ; if ( idx !== - 1 ) { this . targets . splice ( idx , 1 ) ; this . targets . length === 0 && this . stop ( ) ; } return this ; } ; description private rafCallback = ( ) : number => { if ( ! this . _isActive ) { return 0 ; } for ( let i = 0 ; i < this . targets . length ; i ++ ) { ! this . targets [ i ] . _unmounted && this . targets [ i ] . update ( ) ; } return ( this . animationFrameID = requestAnimationFrame ( this . rafCallback ) ) ; } ; } export default new RAFLoop ( ) ;