Let’s make some badass (canvas) noise!

Couple of days ago I had a chat with a good friend of mine and he mentioned he was in the process of building a simple 404 page for one of his portals. He wanted to add some small touches to it and one of them was TV static/grain animation.

As the day went by he showed me a working prototype and although it all looked good there was one thing that poked one of my split identities (the one anal about performance and optimising filesize) in the eye. You see, the existing idea was using several Photoshop generated frames and simply animating the background position or using animated GIF, but I knew from my old and rather painful experiences that noisy images are a bitch to compress—JPEGS will render artifacts straight away, while lossless formats will be huge.

It took me about 2 minutes to make a call and start my lazy bastard friend with a bit of a canvas goodness. The initial script was supposed to generate a single frame of noise/grain and, since it looked rather nice, I hoped he’d take it from there and make it animate and all that. Unfortunately when you’re busy , you have to prioritise, and in this case making a noise script was not very high on his todo list(;

One day passed and I for a reason I can explain that unfinished thing was started to drive me mad, so I decided to make it work and so here it is(:

Oops your canvas is rather dead, atm!

Usage

The class init method accepts 2 parameters: required selector string followed by a settings object. Keep in mind that the whole thing was designed to target only one element—no matter what selector you pass, it’ll only use its first instance. The script will also take the contents of the container element and inject it inside canvas element as a fallback.

StaticGen.init('#selector', {
    width         : 0,      /* main canvas width. Defaults to container width */
    height        : 0,      /* main canvas height. Defaults to container height */
    tileWidth     : 200,    /* unique tile width */
    tileHeight    : 200,    /* unique tile height */
    totalFrames   : 4,      /* number of total static frames */
    fps           : 8,      /* errr… number of frames per second? */
    pixelWidth    : 2,      /* single static grain width */
    pixelHeight   : 2,      /* single static grain height */
    stretchH      : 8,      /* amount of horizontal stretching applied to each static grain. Possible options: 'fit' to fit container width or int>1 */
    stretchV      : 1,      /* amount of vertical stretching applied to each static grain. Possible options: 'fit' to fit container width or int>1 */
    scanLines     : true,   /* leave a 1px high gap between {pixelHeight}px pixel rows */
    randomizeRows : true    /* should each row be randomly offset by a fraction of {pixelWidth}? */
});

To be fair, I had a bit of a brainfu…melt with writing half decent explanations of what each parameter did, so I suggest you take a look at this interactive playground and figure them out while experimenting.

Methods

In case you wanted to have a bit more control of the animation, there’re also few simple methods available:

Redraw

Redraws the canvas using a new set of options without interfering with the DOM.

StaticGen.redraw({
    tileWidth   : 300,
    tileHeight  : 100
});

Pause

Pause the animation.

StaticGen.pause();

Resume

Resumes paused animation.

StaticGen.resume();

Few things to note:

  1. my experience with canvas is as amazing as with professional ice skating ballet—I do look good in short pink skirts but that’s where it ends.
  2. In the recent months I’ve become rather sensitive about stuffing everything with jQuery. It’s a brilliant framework, don’t get me wrong, but most of the time too bloated and an overkill—that’s why I built this script vanilla JS style.
  3. Don’t make the same mistake I did and never ever use getImageData/putImageData—these methods are slow and evil. If you draw everything in the separate canvas, which doesn’t even have to be inserted into DOM, and then use drawImage to extract data of it, you’ll increase your script’s performance dramatically.

Finally—yes—it is the most useless piece of code I’ve ever written but, hey, at 2KB someone will find it useful one day, I’m sure of it(;

Get it at GitHub