erikjung
4/4/2016 - 4:04 AM

tweenNumber.js

/**
 * Tweens a number from `startValue` to `endValue` over the `duration` time period, 
 * calling `onAnimationFrame` on each animation frame.
 * 
 * @example 
 * // Tween to 100 from 0 over 2 seconds
 * tweenNumber(n => console.log(`step value: ${n}`), 100, 0, 2000);
 */
function tweenNumber (
  onAnimationFrame,
  endValue,
  startValue = 0,
  duration = 500
) {
  var start;
  var elapsed;
  var progress;
  var stepValue;
  
  /**
   * 1. Math.ceil() because rounding of microsecond timestamp vs. duration
   * 2. Math.max() because elapsed time could be greater than stupidly short duration
   */
  function iterate (timestamp) {
    start = start || timestamp;
    elapsed = Math.ceil(timestamp - start); // 1
    progress = elapsed / Math.max(elapsed, duration); // 2
    stepValue = startValue + (endValue - startValue) * progress;
    
    onAnimationFrame(stepValue, progress);
    
    if (progress < 1) {
      window.requestAnimationFrame(iterate);
    }
  }
  // Force positive duration of at least 1ms
  duration = Math.max(duration, 1);
  window.requestAnimationFrame(iterate);
};