﻿/**
* AnimateCSS.js:
* This file defines a function named animateCSS(), which serves as a framework
* for creating CSS-based animations.  The arguments to this function are:
*
*     element: The HTML element that is to be animated.
*     numFrames: The total number of frames in the animation.
*     timePerFrame: The number of milliseconds to display each frame.
*     animation: An object that defines the animation; described below.
*     whendone: An optional function to call when the animation finishes.
*               If specified, this function is passed element as its argument.
*
* The animateCSS() function simply defines an animation framework.  It is the
* properties of the animation object that specify the animation to be
* done. Each property should have the same name as a CSS style property.  The
* value of each property must be a function that returns values for that
* style property.  Each function is passed the frame number and the total
* amount of elapsed time, and it can use these to compute the style value it
* should return for that frame.  For example, to animate an image so that it
* slides in from the upperleft, you might invoke animateCSS as follows:
*
*  animateCSS(image, 25, 50,  // Animate image for 25 frames of 50ms each
*             { // Set top and left attributes for each frame as follows
*               top: function(frame,time) { return frame*8 + "px"; },
*               left: function(frame,time) { return frame*8 + "px"; }
*             });
*             
**/
function animateCSS(element, numFrames, timePerFrame, animation, whendone) {
    var frame = 0;   // Store current frame number
    var time = 0;    // Store total elapsed time

    // Arrange to call displayNextFrame() every timePerFrame milliseconds.
    // This will display each of the frames of the animation.
    var intervalId = setInterval(displayNextFrame, timePerFrame);

    // The call to animateCSS() returns now, but the line above ensures that
    // the nested function defined below will be invoked once for each frame
    // of the animation.  Because this function is defined inside 
    // animateCSS(), it has access to the arguments and local variables of
    // animateCSS() even though it is invoked after that function has returned!
    function displayNextFrame() {
        if (frame >= numFrames) {             // First, see if we're done
            clearInterval(intervalId);        // If so, stop calling ourselves
            if (whendone) whendone(element);  // Invoke whendone function
            return;                           // And we're finished
        }

        // Now loop through all properties defined in the animation object
        for (var cssprop in animation) {
            // For each property, call its animation function, passing the
            // frame number and the elapsed time.  Use the return value of the
            // function as the new value of the corresponding style property
            // of the specified element.  Use try/catch to ignore any
            // exceptions caused by bad return values.
            try {
                //   alert(animation[cssprop](frame, time, element));
                element.style[cssprop] = animation[cssprop](frame, time, element);
            } catch (e) { }
        }

        frame++;               // Increment the frame number
        time += timePerFrame;  // Increment the elapsed time
    }
}