UNPKG

timaline

Version:

timaline is a requestAnimationFrame based tasks scheduler.

253 lines (160 loc) 3.85 kB
'use strict' // Require Ticker const Ticker = require( './ticker.js' ) // Create Scheduler const Scheduler = function( options ) { this.options = options this.infos = {} this.isProcessing = false this.tasks = { queue: [], check: [] } this.taskCount = 0 this.queueCount = 0 this.bound = null Ticker.setOptions( this.options ) } // Public /** * add() add a function to the tasks queue * * @param {Function} callback * @return {Integer} delay (time in millisecond) */ Scheduler.prototype.add = function( callback, delay ) { this.tasks.queue.push( { callback: callback, delay: delay, index: this.taskCount++ } ) if ( !this.isProcessing ) { this.bound = this._tick.bind( this ) Ticker.start( this.bound ) this.isProcessing = true } } /** * update() update with custom loop */ Scheduler.prototype.update = function( time ) { Ticker.update( time ) } /** * destroy() remove all scheduled tasks */ Scheduler.prototype.destroy = function() { this.tasks.queue = [] if ( this.isProcessing ) { Ticker.end( this.bound ) this.isProcessing = false } } // Private /** * _onComplete() is called when timeline is finished * */ Scheduler.prototype._onComplete = function() { if ( this.options.repeat !== this.queueCount ) { let i = this.tasks.check.length while ( i-- ) { const task = this.tasks.check[ i ] task.startTime = null this.tasks.queue.push( task ) } this.queueCount++ } else { this.destroy() } } /** * _tick() is the RAF Handler */ Scheduler.prototype._tick = function( currentTime ) { // Save Timing infos this._saveInfos( currentTime ) // Loop queue if ( this.infos.delta ) { this._loopQueue( currentTime ) } } /** * _saveInfos() save RAF Timing infos * * @return {Integer} currentTime (time in millisecond) */ Scheduler.prototype._saveInfos = function( currentTime ) { if ( !this.infos.last ) { this.infos.last = currentTime } else { this.infos.delta = currentTime - this.infos.last this.infos.last = currentTime this.infos.fps = 1 / ( this.infos.delta / 1000 ) } } /** * _loopQueue() loop through queue to check if task * need to be processed * * @return {Integer} currentTime (time in millisecond) */ Scheduler.prototype._loopQueue = function( currentTime ) { let i = this.tasks.queue.length while ( i-- ) { // Get current task const task = this.tasks.queue[ i ] if ( task ) { // Save task start time if not exist if ( !task.startTime ) { task.startTime = currentTime } // Predict task end time by delay task.endTime = task.startTime + task.delay // get adjusted endTime because of delta difference task.adjustedTime = ( task.endTime - ( this.infos.delta / 2 ) ) // If Delay Time is elapsed if ( currentTime >= task.adjustedTime ) { // Save Timeshift after adjustment task.timeShift = currentTime - task.endTime this._processTask( task ) } } } } /** * _prepareResponse() prepare callback response * * @return {Object} task */ Scheduler.prototype._prepareResponse = function( task ) { const response = { keyframe: { forecast: task.delay, real: task.delay + task.timeShift, shift: task.timeShift }, index: task.index } return response } /** * _processTask() process task and remove it to queue * * @return {Object} task */ Scheduler.prototype._processTask = function( task ) { const response = this._prepareResponse( task ) // Launch Callback task.callback( response ) // Add task to checked task this.tasks.check.push( task ) // Remove this processed task from tasks queue this.tasks.queue.splice( this.tasks.queue.indexOf( task ), 1 ) // No more tasks in queue ? if ( !this.tasks.queue.length ) { this._onComplete() } } // Wrap as a module module.exports = Scheduler