API Docs for: 1.0.0
Show:

File: css_animation.js

/**
 *  @module CSSAnimation
 */
/**
 *  Animates CSS for a given element (constructor throws Direction error).
 *  @class CSSAnimation
 *  @constructor
 *  @param  {Object} props  properties to animate:
 *    @param  {HTMLElement} props.targetEl  the element to animate
 *    @param  {String} props.cssProperty    a CSS property, e.g. opacity, top
 *    @param  {String} props.cssUnit        a CSS 'length' unit, e.g. px
 *    @param  {int} props.minValue          the minimum of the range of values to change
 *    @param  {int} props.maxValue          the maximum of the range of values to change
 *    @param  {String} props.direction      up | down (min to max | max to min)
 *    @param  {float} props.duration        how long the animation lasts in seconds
 *    @param  {float} props.fps             frames per second
 *    @param  {int} props.transitionType    pre-defined constants: CSSAnimationLinearTransition |
 *                                            CSSAnimationEaseTransition | CSSAnimationEaseInOutTransition
 *    @param  {float} props.lambdaPower     exponent for easing: in > 1, out < 1, default 2
 *  @return {void}
 */
function CSSAnimation(props)
{
  var opts = props || {};

  // animated object properties
  this.cssProperty = opts.cssProperty || "";
  this.cssUnit = opts.cssUnit || "";
  this.targetEl = opts.targetEl || null;

  // animation properties
  this.direction = opts.direction || "up";
  this.duration = opts.duration || 0;
  this.fps = opts.fps || 48;
  this.lambdaPower = opts.lambdaPower || 2;
  this.maxValue = opts.maxValue || 0;
  this.minValue = opts.minValue || 0;
  this.transitionType = opts.transitionType || CSSAnimation.LINEAR_TRANSITION;

  // private members
  this.totalFrames = this.fps * this.duration;
  this.frame = 0;
  this.mspf = 1000 / this.fps // ms per frame

  // validate direction
  switch (this.direction) {
    case "down":
      this.currentValue = this.maxValue;
      break;

    case "up":
      this.currentValue = this.minValue;
      break;

    default:
      throw "Error: direction must be 'up' or 'down'."
  }
}

/**
 *  Transition type.
 *  @property LINEAR_TRANSITION
 *  @type {int}
 *  @static
 *  @final
 */
CSSAnimation.LINEAR_TRANSITION = 1;

/**
 *  Transition type.
 *  @property EASE_TRANSITION
 *  @type {int}
 *  @static
 *  @final
 */
CSSAnimation.EASE_TRANSITION = 2;

/**
 *  Transition type.
 *  @property EASE_IN_OUT_TRANSITION
 *  @type {int}
 *  @static
 *  @final
 */
CSSAnimation.EASE_IN_OUT_TRANSITION = 3;

/**
 *  Calculates the difference between each frame's animation value.
 *  @method _interpolate
 *  @protected
 *  @return {float}
 */
CSSAnimation.prototype._interpolate = function () {
  var delta, lambda, lambdaPower;

  switch (this.transitionType) {
    case CSSAnimation.EASE_TRANSITION:
      delta = this.maxValue - this.minValue;
      lambda = Math.pow(this.frame * (1.0 / (this.totalFrames - 1.0)), this.lambdaPower);
      break;

    // case CSSAnimation.EASE_IN_OUT_TRANSITION:
      // // ease in the first half, out the second half
      // delta = (this.maxValue - this.minValue) / 2.0;
// 
      // if (this.frame < this.totalFrames / 2) {
        // lambdaPower = this.lambdaPower;
      // }
      // else {
        // lambdaPower = 1 / this.lambdaPower;
      // }
// 
      // lambda = Math.pow(this.frame * (1.0 / (this.totalFrames / 2 - 1.0)), lambdaPower);
      // break;

    default:
      delta = this.maxValue - this.minValue;
      lambda = this.frame * (1.0 / (this.totalFrames - 1.0));
  }

  if (this.direction == "down") {
    return this.maxValue - lambda * delta;
  }
  else {
    output.innerHTML += (lambda * delta) + "\n";
    return this.minValue + lambda * delta;
  }
};

/**
 *  Performs the animation.
 *  @method animate
 *  @return {void}
 */
CSSAnimation.prototype.animate = function ()
{
  var _this = this;

  function innerAnimate()
  {
    _this.animate();
  }

  this.targetEl.style[this.cssProperty] = this._interpolate() + this.cssUnit;

  this.frame = (this.frame + 1) % this.totalFrames;

  if (this.frame + 1 < this.totalFrames) {
      setTimeout(innerAnimate, this.mspf);
  }

  // if this is the last iteration then do the transform again but don't reiterate
  if (this.frame + 1 == this.totalFrames) {
    this.targetEl.style[this.cssProperty] = this._interpolate() + this.cssUnit;
  }
}