Processing.js Frame Animation Queue

A couple weeks ago, I mentioned that I was using Processing.js to animate a visualization tool for work. Today’s article showcases the class-based strategy we used to handle animation frames.

There is a simple Demo available, if you would like to see Processing.js in action.

Getting ready

To start using processing, you will need three things: the latest Processing.js code, a canvas element on an HTML page with the data-processing-sources attribute set, and a .pde file for your processing code. Here is a sample HTML:

<html>
    <head>
        <title>Processing.js Test App</title>
        <script src="pathToProcessing/processing.min.js"></script>
    </head>
    <body onload="init">
        <canvas data-processing-sources="pathToPde/processingTestApp.pde" width="1000" height="500"> </canvas>
    </body>
</html>

How do it…

In the .pde file, define the animation base class:

function AnimationFrameClass () {}
AnimationFrameClass.prototype = {
    data: null,  // optional data (for internal use of children)
    draw: null,  // required, the function to render this animation
    onend: null,  // optional function to call, when animation is finished
    // required function to indicate when to stop, by default after max_frames
    finished: function() {
        return this.max_frames < this.frame;
    },
    max_frames: 100,  // default maximum number of frames for this animation
    name: null,  // the name of the animation, useful for debugging
    reset: function() {  // restart the frame counter
        this.frame = 0;
    },
    onstart: null,  // optional function to call, before animation begins
    started: false,  // used by draw function
    frame: 0  // required, the frame counter
};

If you are not using a library and need an inheritance function, add the following as well:

function inherit(C, P, p) {
	var F = function () {};
	F.prototype = P.prototype;
	C.prototype = new F();
	C.uber = P.prototype;
	C.uber_constructor = P;
	C.prototype.constructor = C;

	if (p) {
		for (var prop in p) {
			if (p.hasOwnProperty(prop)) {
				C.prototype[prop] = p[prop];
			}
		}
	}

	return C;
}

Here is a simple example that extends the animation base class to draw the background:

color BackgroundColor = 0xFFCCCCCC;
var BackgroundAnim = inherit(function() {}, AnimationFrameClass, {
    draw: function() {
        background(BackgroundColor);
    },

    finished: function() {
        return false;  // never stops
    },

    name: 'Background Animation'
});

Globally, define a queue that AnimationFrameClass instances are appended to and process the queue in the special draw function:

var Queue = [];

// called automatically by processing continuing the animation, draws a frame
void draw() {
    var newQueue = [],
        i = 0,
        j = Queue.length,
        animObj;

    for (; i < j; i += 1) {
        // clear fill and stroke that may have been set by previous animations
        noFill();
        noStroke();
        animObj = Queue[i];

        // fire started function
        if (!animObj.started) {
            animObj.started = true;
            animObj.onstart && animObj.onstart();
        }

        // draw and increment the frame
        animObj.draw();
        animObj.frame += 1;

        // fire the end function
        if (animObj.finished()) {
            animObj.onend && animObj.onend();
        }
        // this animation stays in the queue for the next frame
        else {
            newQueue.push(animObj);
        }
    }

    Queue = newQueue;
}

Don’t forget to define the setup function, which is called automatically by Processing.js on startup:

void setup() {
	size(500, 500);
}

The following would then draw a gray background:

Queue.push(new BackgroundAnim());

How it works…

Processing.js searches the DOM for canvas tags with data-processing-sources attribute defined, downloads the .pde file, and applies a post processor against the code converting it to functioning JavaScript that drives the canvas element. You write your animation logic (the .pde file) in a modified Processing environment, which behaves like the Java-based Processing language, except it also has access to global JavaScript variables. For example, if you include a library like jQuery before Processing.js runs, then the code in the .pde will be able to use jQuery. That said, today’s example uses straight processing logic.

The AnimationFrameClass is a simple class that can be extended to include logic for drawing any kind of animation frame. The example above includes a Queue array that all animation instances are pushed onto and processed from. The order that animations are added to the Queue, is the order that they will be rendered during an animation frame, so they should be appended background to foreground. An animation frame is automatically handled by Processing.js when it calls the global draw function. The draw function of each AnimationFrameClass objects will be called each frame.

As each animation is iterated over several things happen. If an onstart function is defined and the started property is not set to true, then the onstart function is called. Use onstart to handle one-frame animations or to queue an animation that happens when the current animation first starts. Next the draw function is called and the frame counter incremented. Each subclass of AnimationFrameClass should define its draw function, which is what will be rendered on each frame. If the finished function returns true, then the onend function is called, where you might queue an ending or series animation. If the animation is not finished, it will be appended back onto the Queue for processing again in the next frame.

Check out the Demo for a fully functioning app with lots of sample animations.

There’s more…

This article focuses mostly on my frame animation technique, and not all the awesome power of the Processing language and Processing.js. For more details, see the Processing.js documentation.