CodeCodex @ whatisfound.com

Random Bars and the Goblet of Fire

Have you ever used PowerPoint or some similar slideshow program, and thought that some of the transitions were actually kind of cool? No? Well, you probably get dates on weekends, or something lame like that. What are you even doing on this page? This is for people who want to see one of those slideshow transitions duplicated vis-a-vis JavaScript. Oh sure, now your interest is piqued...

Example

Click the image of my gorgeous face to watch the random bars effect. (This will pause the colored bars in the background to save on CPU effort...especially for Internet Explorer)

Explained

For as nifty as this looks, it's actually got a pretty straightforward solution. The first thing you should know is that you have been tricked; the image above is not an <img/> tag, but a <div> with me as a background-image and just exactly the right width and height set to that of the image proper. Here's the CSS for the <div> above:

div#randomBarsDemo { background-image:url('images/mse_profilepic_1.jpg'); width:175px; height:200px; margin:0 auto; } div#randomBarsDemo div { background-color:#111; width:100%; /* For IE6 */ font-size:0; }

Next, you fill the picture <div> with lots of short, opaque <div>s until the image is completely covered. I use <div>s with alternating heights of 1px and 2px. Then, all you have to do is loop over all the short <div>s and randomly set their background-color to “transparent”.

Gotcha!

Make sure you do a background-color:transparent and not a display:none. If you turn off the display property, the short <div>s will lose their layout, and no matter what order you hide them in, it will look like you're simply revealing the picture from the bottom up as each <div> below moves up to fill the space left by the one that is no longer being displayed.

Sounds simple enough, right? For the most part, yes. Doubtless, you could take what I've said so far, and write your own solution with no trouble. But being not only a web developer, but a huge nerd Computer Science major as well, I want the solution to be as efficient and random as possible. There are three functions (aren't there always?) that I use to pull this off: randomBars, getRandomOrder, and addShutters.

addShutters(viewscreen, height)

// *** Pass this function to randomBars as the only argument to trigger the effect function addShutters(viewscreenName,height) { var vs = document.getElementById(viewscreenName); if(vs.getElementsByTagName('div').length) return false; var indexArray = []; var short = true; for(var i = 0; i < height; i++) { var shutter = document.createElement('div'); var shutCSS = shutter.style; if(short || height - i == 1) shutCSS.height = "1px"; else { shutCSS.height = "2px"; height--; } if(navigator.appVersion.indexOf('MSIE 6.0') != -1) // *** Defeat IE6 implicit DIV min-height shutter.innerHTML = " "; vs.appendChild(shutter); indexArray.push(i); short = !short; } indexArray.push(vs,height); return indexArray; }

The first comment pretty much says it all. This function is essentially the primer for randomBars; its job is to fill the target element (div#randomBarsDemo on this page) with short <div> elements (“shutters”). You can set the width and background-color for these via CSS (see above). For all it's complicated looking-ness, this is actually the most straightforward of the set.

It accepts the ID of the element to fill with shutters (I call it “viewscreen” because window is already taken), as well as the height of that container. You could cut out the height argument, and have it work that part out internally, but I obviously couldn't be bothered. The first thing it does after getting a reference to the viewscreen is to see if that already has shutters inside of it, and if so, returns false. This prevents the effect from occurring while it is already occurring. You really don't want that to happen. Your CPU will thank you later.

Next up is the loop. Using a boolean as a kind of alternator, I make 1px and 2px shutters, add them to the viewscreen and push their counter onto an array creatively named indexArray. That second comment there is also fairly self-explanatory, but it turns out that IE6 has this strage rule about minimum size of empty <div>s, so just chuck in a whitespace character, and you're good to go.

At the end of the function, I push the reference to viewscreen and the height of viewscreen onto indexArray. They don't really belong there, but randomBars uses both, so I say why go through the effort of figuring them out twice when they can piggyback on the array? By the end of this, your target viewscreen should be exactly full of 1px and 2px <div>s, and you should be ready to read on.

randomBars(indexArray)

function randomBars(indexArray) { if(!indexArray) return; var height = indexArray.pop(); var viewscreen = indexArray.pop(); var shutterList = viewscreen.getElementsByTagName('div'); var flr = Math.floor; var rndm = Math.random; var interval = setInterval(function () { shutterList[getRandomIndex(flr,rndm,indexArray)].style.backgroundColor = "transparent"; if(!indexArray.length) { clearInterval(interval); $("#randomBarsDemo").empty(); // *** jQuery only pauseColorBars(); return; } },20); }

This function accepts the result of addShutters which is either a fancy array or false, and as you can tell from the first line, if it's the latter, we're gonna stop right there. Otherwise, we pop the last two values off to get our height and the reference to our viewscreen.

Next, a little something you might not have seen before. I store the functions Math.floor and Math.random in their own variables. I'm going to be using them a lot, and it will be a little more efficient to not have to look them up from the Math object each time.

The final bit of code in randomBars is a setInterval call, which is where the magic of the effect happens. This runs through indexArray and makes the corresponding shutter invisible. When there are no more shutters, it cancels itself, and the picture will stand fully revealed.

getRandomIndex(floor, random, indexArray)

function getRandomIndex(flr, rndm, indexArray) { return indexArray.splice(flr(rndm()*10000) % indexArray.length, 1); }

And here is the little helper function that could. It gets a random number from 0 to the length of indexArray-1, then splices out and returns whichever shutter counter that random index corresponds to. And presto-change-o, you've got the random bars effect.

Splice is nice.

Splice is a bit of a weird function, and one you probably don't see very often. It lets you pull stuff out or cram stuff into an array from any index you specify. Splice takes the form Array.splice(X, Y[, Z]). X is the index of Array used as a starting point, Y is how many elements to remove (0 if you're just adding to Array), and Z is the optional parameter of elements you are adding to the array, which you can obviously leave off if you are removing elements. Any removed elements are returned by the function. For further reading and examples, try the W3Schools page.

Exposed

So that's the random bars effect. Best thing ever, right? Well, imagine if you modified those shutters so that instead of being 100% wide and either 1px or 2px tall, they were uniformly 2px squares. If you made all of them randomly turn transparent, it would look an awful lot like a disintegration effect! Pretty cool stuff.

Here would normally be the place where I put a link to some composite library of cool JavaScript effects and tricks (including this one!), but I've been busy porting all this over from my old site, so you're stuck with writing these on your own for the time being. Check back soon!

Last updated: May 7, 2010