Tacky DHTML web tricks #1

Magic trickIt's been a while since we've had some DHTML (Sorry, I mean, DOM scripting) action here, so I thought I'd get us back on track with some stupid DHTML tricks for your web page. Today I'll be showing you the Strongbad-esque technique I've been employing around these parts: hidden popup images.

Have a browse at some of the more recent articles around here. Scan your mouse over all the words. If you find them, pretty images spring to life - adding form and colour to the page. Then, seconds later, they are gone. Leaving you - the reader - intrigued and amused.

So how do you do it?

Well, first some considerations to make popup images practical:

  1. It's got to be easy to add new images. Otherwises it's not gunna happen.
  2. It must provide a method of varying parameters on each image, for added wackiness.
  3. It has to "gracefully degrade" if viewed on browsers that don't support javascript.

First off, I'll show you how I define the popups. This is the only bit you have to change for each image.
<span class="popalots" id="image.jpg_2_100_-100">words here!</span>
Pretty tricky 'eh? I'll break it down for you:

span tag: Every image will be popped-up in response to a mouseover event on the span tag.
class="popalots": To differentiate our pop-ups from regular "spans", we give it our popup class name.
words here!: This is the word/phrase that you want the user to mouseover over. over.
id="image.jpg_2_100_-100": The work-horse of the team - all of our parameters are defined in the id, seperated by underscores. The parameters will be discussed in a tick.

But how?
Put your right hand inOk, thats defining the popup. But how does it work? Well, it's a simple beast to be sure. But to make it even simplier I am using a this nice event manager by Keith Gaughan which takes care of adding events to DOM objects in Mozilla and IE. And cleaning up icky memory leaks too.

We start by define a global array for holding our popup images for preloading. Then add an onload event to the window to do our setup...

var popalot_images = [];
EventManager.Add( window, "load", popalots_setup() );

To add a mouseover event to all the popups, we get every span on the page, then check each one to see if its our popup friend. If it is, add the event:

var spans = document.getElementsByTagName( "span" );
for ( i = 0; i < spans.length; i++ ) {   if ( spans[ i ].className == "popalot" )   {     EventManager.Add( spans[ i ],       "mouseover",       popalots_moused );     ...   } }

Now when a user mouses over one of our popalot spans it will call popalots_moused with the event. To setup our pop up we grab the target of the event, and read the parameters from the id:

var target = e.target ? e.target : e.srcElement;
var popDivId = target.id;
var popParams = popDivId.split( "_" );

The Parameters
Thanks to the split, our popParams variable now contains an array of "parameters" that were defined in the span's id, with each parameter delimited by an underscore. Heres the id format I'm using on my spans:

path|image name_display time_x offset_yoffset

for example:


This popups up the image "images/popups/popup1.jpg" for 2.5 seconds, 100 pixels right of the mouse and 100 pixels above the mouse.

Poppin' it up
Once we have our parameters, we are ready to add the popup. First create a new div for the image

popDiv = document.createElement( "div" );

Then we set the div's attributes from our popParams array of parameters. Once we are all set up, we add the div to the DOM

var popName = popParams[ 0 ];
var popTime = popParams[ 1 ];
document.body.appendChild( popDiv );

At this point, an image will popup when you mouseover the div, but it will just stick around for ever. Annoying if you are trying to read what's underneath it. So we add a timer to get rid of it after a certain amount of time - as specified in the parameters.

setTimeout( "popalota_kill('pop_" + popDivId + "')", popTime * 1000 );

Then our popalota_kill function removes it from the DOM, and we are back to where we started!

var popDiv = document.getElementById( popDivId );
if ( popDiv ) popDiv.parentNode.removeChild( popDiv );

Yep. Amazing. You can make it nicer though. The script is really straight forward... almost elegant.... I'll put it in a standalone page as a better example. One day. I really like things that use document.getElementsByTagName. I'm going to go see what else I can make with it...