src/rAFAnimate.js
// the animate function via rAF, either with or without updating options
the animate function via rAF, either with or without updating options
the animate function via rAF either with or without updating options
function innerAnimateRAFed( optionsUpdates ) {
      var immediates = { };
      if ( optionsUpdates ) {
        Object.keys( optionsUpdates ).forEach( function( key ) {
          if ( !( key in options ) ) {
            throw new RangeError( key + ' is not a valid option' );
          }
          if ( optionsUpdates[ key ] === 'toggle' ) {
            options[ key ] = options[ key ] === Infinity ? 0 : Infinity;
          } else if ( optionsUpdates [ key ] === 'immediate' ) {
            immediates[ key ] = options[ key ];
            options[ key ] = optionsUpdates[ key ];
          } else {
            options[ key ] = optionsUpdates[ key ];
          }
        });
      }
      if ( id !== null ) {
        window.cancelAnimationFrame(id);
        id = null;
      }
      id = window.requestAnimationFrame( function rAFCallee( timestamp ) {
        var outOptions = { };
        var temp;
        outOptions.render = options.render;
        options.render = false;
        if ( startTime < 0 ) {
          startTime = timestamp;
          prevTimestamp = timestamp;
          ticksLeftovers = 0;
        }
        outOptions.startTime = startTime;
        outOptions.timestamp = timestamp;
        outOptions.deltaTime = timestamp - prevTimestamp;
        prevTimestamp = timestamp;
        temp = outOptions.deltaTime + ticksLeftovers;
        outOptions.ticks = Math.trunc( temp / options.msPerTick );
        ticksLeftovers = temp - outOptions.ticks * options.msPerTick;
        Object.keys( options ).forEach( function ( key ) {
          if ( key === 'msPerTick' || key === 'render' ) {
            return;
          }
          if ( options[ key ] === 'immediate' ) {
            options[ key ] = immediates[ key ];
            outOptions[ key ] = true;
            if ( outOptions.run !== 'immediate' ) {
              outOptions.run = !!options.run || 'immediate';
            }
          } else if ( outOptions[ key ] !== 'immediate' ) {
            outOptions[ key ] = !!options[ key ] && !!options.run;
          }
          if ( key !== 'run' && outOptions[ key ] ) {
            outOptions.render = true;
          }
          if ( options [ key ] > 0 ) {
            options[ key ] -= outOptions.ticks;
            if ( options[ key ] < 0 ) {
              options[ key ] = 0;
            }
          }
        });
        if ( outOptions.run || optionsUpdates.render ) {
          animate( outOptions, context );
        }
        if ( options.run ) {
          id = window.requestAnimationFrame( rAFCallee );
        } else {
          id = null;
          startTime = -1;
        }
      } );
      return { ...options };
    }
function innerAnimateRAFed ( optionsUpdates ) { var immediates = { } ; if ( optionsUpdates ) { Object . keys ( optionsUpdates ) . forEach ( function ( key ) { if ( ! ( key in options ) ) { throw new RangeError ( key + ' is not a valid option' ) ; } if ( optionsUpdates [ key ] === 'toggle' ) { options [ key ] = options [ key ] === Infinity ? 0 : Infinity ; } else if ( optionsUpdates [ key ] === 'immediate' ) { immediates [ key ] = options [ key ] ; options [ key ] = optionsUpdates [ key ] ; } else { options [ key ] = optionsUpdates [ key ] ; } } ) ; } if ( id !== null ) { window . cancelAnimationFrame ( id ) ; id = null ; } id = window . requestAnimationFrame ( function rAFCallee ( timestamp ) { var outOptions = { } ; var temp ; outOptions . render = options . render ; options . render = false ; if ( startTime < 0 ) { startTime = timestamp ; prevTimestamp = timestamp ; ticksLeftovers = 0 ; } outOptions . startTime = startTime ; outOptions . timestamp = timestamp ; outOptions . deltaTime = timestamp - prevTimestamp ; prevTimestamp = timestamp ; temp = outOptions . deltaTime + ticksLeftovers ; outOptions . ticks = Math . trunc ( temp / options . msPerTick ) ; ticksLeftovers = temp - outOptions . ticks * options . msPerTick ; Object . keys ( options ) . forEach ( function ( key ) { if ( key === 'msPerTick' || key === 'render' ) { return ; } if ( options [ key ] === 'immediate' ) { options [ key ] = immediates [ key ] ; outOptions [ key ] = true ; if ( outOptions . run !== 'immediate' ) { outOptions . run = ! ! options . run || 'immediate' ; } } else if ( outOptions [ key ] !== 'immediate' ) { outOptions [ key ] = ! ! options [ key ] && ! ! options . run ; } if ( key !== 'run' && outOptions [ key ] ) { outOptions . render = true ; } if ( options [ key ] > 0 ) { options [ key ] -= outOptions . ticks ; if ( options [ key ] < 0 ) { options [ key ] = 0 ; } } } ) ; if ( outOptions . run || optionsUpdates . render ) { animate ( outOptions , context ) ; } if ( options . run ) { id = window . requestAnimationFrame ( rAFCallee ) ; } else { id = null ; startTime = - 1 ; } } ) ; return { ... options } ; }
the animate function via rAF, either with or without updating options
the animate function via rAF either with or without updating options
// immediates stores existing values of options which have been set to // 'immediate' so they can be restored and processed as if the 'immediate' // was never passed.  'immediate' in optionsUpdates will just guarantee the // outOptions.optionName will be true even if options.optionName is // zero, and cause animate() to be called with outOptions.run set to // 'immediate' if run === 0, guaranteeing this call to innerAnimateRAFed // will cause the immediate option to be executed once and rendered // update any options passed in optionsUpdates // Only default options or options explicitly set initially allowed // Cancel any pending rAF call since since we are queueing up one below // queue up rAF to process the options and call animate() if necessary // rAFCallee is the actual callback for rAF that may get called repeatedly // without another explicit call to innerAnimateRAFed() if run option > ticks // outOptions is formed by processing options is passed to animate() // reset time if startTime has been set < 0 // outOptions time related options // Process options, updating outOptions appropriately // Only call animate() if run === true or 'immediate' or render explicitly true // Queue up rAFCallee again (this function) if further run ticks remain // if run === 0, animate() may have been called above but since ticks were // subtracted after outOptions.run was set true or 'immediate', no ticks // are left for further runs, meaning no need to queue up another rAF // reset time