Home Articles FAQs XREF Games Software Instant Books BBS About FOLDOC RFCs Feedback Sitemap
irt.Org

Related items

How to do the impossible with Google Gears

Out and About

JavaScript Bouncing Balls

Multi-dialogue forms on one page

Turning Tables Into Selection Lists

Drag and Drop with Microsoft Internet Explorer 5

Dynamic Floating Tool Tips

What is DHTML?

String Gradients the Fun Way!

"The Light Fantastic"

Image Manipulation Techniques

You are here: irt.org | Articles | Dynamic HTML (DHTML) | Image Manipulation Techniques [ previous next ]

Published on: Monday 31st May 1999 By: Martin Webb

Introduction

This article will demonstrate how to get the best image manipulation techniques out of each browser, using a mixture of Frames, Images, Floating Frames, Tables, Layers, JavaScript, DHTML and Microsoft's Multimedia effects.

The completed working example of a slide puzzle presented at the end of this article will work on all Microsoft and Netscape browsers as far back as Netscape Navigator 2 and Microsoft Internet Explorer 3.

Imagination

Ever since Netscape introduced the image tag, images have been appearing on web sites - initially static, but as animated GIF's were used, people saw animation and (some) people liked what they saw.

With the introduction of JavaScript 1.0 in Netscape 2 and the inclusion of the JavaScript 1.1 Image object in Netscape 3, JavaScript has been used to provide simple image manipulations - swapping or highlighting the image when the mouse hovers over the image, slideshows, games, etc, ever since.

Unfortunately, Microsoft didn't include support for the image object in their first version of JScript, included in Microsoft Internet Explorer 3 - as JScript 1.0 was based on the then JavaScript 1.0. So we were in the situtation where two comparable client Web browsers had different support for different objects.

Since then, the most oft asked JavaScript question has been "How can I swap images in Microsoft Internet Explorer?", due to the basic failure to understand that just because browsers can display images, doesn't necessarily mean that the images can be controlled using JavaScript.

Fortunately, it is extremely easy to use JavaScript to detect whether a browser has support for the JavaScript Image object:

<SCRIPT LANGUAGE="JavaScript"><!--
if (document.images) {
    // supports the Image object
}
else {
    // does not support the image object
}
//--></SCRIPT>

The remainder of this article will demonstrate how to detect whether the browser has support for frames, floating frames, images, layers, DHTML and multimedia effects, and demonstrates a simple image sliding puzzle that can be used in all JavaScript enabled browers.

Detection

What do we detect and why? Well, objects, so that we can use them without error. We could detect the browser - but its always best to detect for object support. If a browser supports the Image object then we can use the Image object to swap images, if it doesn't then we need to use some other mechanism instead - frames or floating frames.

Floating frames, inserted into a document using the <IFRAME> and </IFRAME> tags, can be utilised in Mircrosoft Internet Explorer. We'll use them later in this article to hold images, we can then change the source of the frames to display other images - viola': image swapping!

For browsers that support neither images or floating frames, then we can simply use frames. You might find the resultant code cumbersome to use, and slower than other techniques, but it at least provides an alternative to the message "Sorry, your browser is too old".

Browser technology has moved on since the inclusion of images. Dyanimc HTML is causing many web developers headaches, as they get to grips with the different implementations supported by Netscape and Microsoft. Added to this is the dictum "There is more that one way to do it". Netscape and Microsoft support Cascading Style Sheets, which can be utilised to manipulate images, and Explorer has additional Multimedia support in its Windows versions of Internet Explorer.

So, not only do we need to detect for support of the Image object, but support for other technologies as well:

* Only on the Windows platform.

Selection

Rather than detect the browser type and version, we will detect support for images and objects:

<SCRIPT TYPE="text/javascript" LANGUAGE="JavaScript"><!--
if (document.images) {
    if (document.all && navigator.platform.indexOf('Mac') == -1) {
        FilterDisplay();
    }
    else if (document.all) {
        SpanDisplay();
    }
    else if (navigator.appName == 'Microsoft Internet Explorer') {
        IFrameDisplay();
    }
    else if (document.layers) {
        LayerDisplay();
    }
    else 
        ImageDisplay();
}
else {
    FrameDisplay();
}
//--></SCRIPT>

The previous code executes:

We can now use the above selection criteria to present different implementations of a slide puzzle.

Presentation

The slide puzzle we will demonstrate can be simply adapted to show any set of images at any shape or size, by the amendment of the single JavaScript source code line:

var height = 4, width = 6, imageHeight = 50, imageWidth = 50, blank = 1, ext = '.jpg';

The width and height control the width/number of images across the screen and height/number of images down the screen. With the above settings, the slide puzzle will be made of a grid of images 4 across by 6 down - a total of 24 images.

The size of each image is specified by imageHeight and imageWidth. This can be used to display enlarged versions of small images - useful with GIF images containing clear primary colors.

The blank value dictates which numbered image is not shown - the starting position of the blank image in the slide puzzle. Every slide puzzle must have a blank slot.

All that is then needed is a sequential number of images named, for example, as 1.jpg through to 24.jpg. Plus an additional blank.gif for the blank slot. The code is written so as to expect the images to all be located in an images subdirectory.

Before I forget, you'll also need a blank.htm file for the frame version, containing just:

<BODY></BODY>

Implementation

Rather then describe each of the various implementations in excrutiating detail, I'll concentrate first on the simple Image implementation, and then highlight the major differences in the other implementations.

The slide puzzle is controlled with the use of three main JavaScript functions. The image implementation, described later, is controlled by the three functions: ImageDisplay() which creates the initial slide puzzle layout, ImageSlideImage() which is triggered when an image is clicked or selected and ImageSwapImage() which carries out the image swap.

The different implementations of the slide puzzle have their own versions of these functions:

ImageDisplay()ImageSlideImage()ImageSwapImage()
FilterDisplay()FilterSlideImage()FilterSwapImage()
SpanDisplay()SpanSlideImage()SpanSwapImage()
IFrameDisplay()IFrameSlideImage()IFrameSwapImage()
LayerDisplay()LayerSlideImage()LayerSwapImage()
FrameDisplay()FrameSlideImage()FrameSwapImage()

In addition to these, the frame and floating frame implementations have three extra functions each:

FrameSetFramesFrameSetFrameContent()FrameBlankFrameContent()
IFrameSetFramesIFrameSetFrameContent()IFrameBlankFrameContent()

Image Implementation

The ImageDisplay() function is fairly simple. It creates a table containing the required number of rows and columns to hold all the images. Each image is contained within a link tag, with a HREF property that executes the ImageSlideImage() function, passing the number of the image that was clicked - this is the number of the original image placed in the table cell and not the image number of the current image in the cell - it could be considered to be a cell number.

function ImageDisplay() {
    var image = 1;
    var output = '<TABLE BORDER=1 CELLPADDING=0 CELLSPACING=0>';
    for (var y=0; y<height; y++) {
        output += '<TR>'
        for (var x=0; x<width; x++, image++) {
            if (image != blank)
                output += '<TD><A HREF="javascript:ImageSlideImage(' + image + ')"><IMG SRC="images/' + image + ext + '" NAME="image' + image +'" HEIGHT=' + imageHeight + ' WIDTH=' + imageWidth + ' BORDER=0><\/A><\/TD>';
            else
                output += '<TD><A HREF="javascript:ImageSlideImage(' + image + ')"><IMG SRC="images/blank.gif" NAME="image' + image +'" HEIGHT=' + imageHeight + ' WIDTH=' + imageWidth + ' BORDER=0><\/A><\/TD>';
        }
        output += '<\/TR>';
    }
    output += '<\/TABLE>';
    document.write(output);
}

The ImageSlideImage() function, invokde when an image is clicked, simply checks to make sure that the image clicked is next to the blank spot. If it is then it invokes the ImageSwapImage() function to carry out the image swap.

function ImageSlideImage(image) {
    swapped = false;
    if ((Math.floor((image-1)/width) != 0) && (blank == image-width))
        ImageSwapImage(image);
    else if (((image-1)%width != width-1) && (blank == image+1))
        ImageSwapImage(image);
    else if ((Math.floor((image-1)/width) != height-1) && (blank == image+width))
        ImageSwapImage(image);
    else if (((image-1)%width != 0) && (blank == image-1))
        ImageSwapImage(image);
}

The ImageSwapImage() function swaps the two images around:

function ImageSwapImage(image) {
    document.images['image'+blank].src = document.images['image'+image].src;
    blank = image;
    document.images['image'+blank].src = 'images/blank.gif';
    swapped = true;
}

If all browsers supported images, and only images, that would be the end of the article. As we are providing alternatives to the Image implementation, we need to describe the different JavaScript functions used in the remaininf implementations: Filter, Span, IFrame, Layer and Frame.

Filter Implementation

The FilterDisplay() function is slightly different to the ImageDisplay() function, the images include an ID attribute, and a STYLE attribute which includes a transitional blend filter lasting 0.4 seconds.

function FilterDisplay() {
    var image = 1;
    var output = '';
    for (var y=0; y<height; y++) {
        for (var x=0; x<width; x++, image++) {
            var top  = Math.floor((image-1)/width)*(imageHeight+1);
            var left = ((image-1)%width)*(imageWidth+1);
            if (image != blank)
                output += '<A HREF="javascript:FilterSlideImage(' + image + ')"><IMG ID=image' + image + ' STYLE="position:relative; zIndex:100; filter:BlendTrans(Duration=0.4)" SRC="' + image + ext + '" HEIGHT=' + imageHeight + ' WIDTH=' + imageWidth + ' BORDER=0><\/A>';
            else
                output += '<A HREF="javascript:FilterSlideImage(' + image + ')"><IMG ID=image' + image + ' STYLE="position:relative; zIndex:0; filter:BlendTrans(Duration=0.4)" SRC="blank.gif" HEIGHT=' + imageHeight + ' WIDTH=' + imageWidth + ' BORDER=0><\/A>';
        }
        output += '<BR>';
    }
    document.write(output);
}

The FilterSlideImage() function is almost identical to the ImageSlideImage() function - and is not shown.

The FilterSwapImage() function swaps the images, as before, but applies and plays the transistional blend filter - this has the effect of blending the images from one to another - an effective and attractive image change.

function FilterSwapImage(image,x,y) {
    eval('image' + blank + '.filters.item("BlendTrans").apply()');
    document.images[blank-1].src = document.images[image-1].src;
    eval('image' + blank + '.filters.item("BlendTrans").play()');
    eval('image' + image + '.filters.item("BlendTrans").apply()');
    document.images[image-1].src = 'blank.gif';
    eval('image' + image + '.filters.item("BlendTrans").play()');
    blank = image;
    swapped = true;
}

Span Implementation

The SpanDisplay() function is almost the same as the ImageDisplay() function, instead of using tables, it uses the <SPAN> and </SPAN> tags with ID attibutes. The only real difference between this version and the Image version, is that the slide puzzle is laid out without the use of tables. It is preferable to use the Image version over the Span version, but it is demonstrated here, for the techniques used. This version will actually work in both Netscape Navigator 4+ and Microsoft Internet Explorer 4+.

function SpanDisplay() {
    var image = 1;
    var output = '';
    for (var y=0; y<height; y++) {
        for (var x=0; x<width; x++, image++) {
            if (image != blank)
                output += '<SPAN ID=image' + image + '><A HREF="javascript:SpanSlideImage(' + image + ')"><IMG SRC="images/' + image + ext + '" HEIGHT=' + imageHeight + ' WIDTH=' + imageWidth + ' BORDER=0><\/A><\/SPAN>';
            else
                output += '<SPAN ID=image' + image + '><A HREF="javascript:SpanSlideImage(' + image + ')"><IMG SRC="images/blank.gif" HEIGHT=' + imageHeight + ' WIDTH=' + imageWidth + ' BORDER=0><\/A><\/SPAN>';
        }
        output += '<BR>';
    }
    document.write(output);
}

The LayerSlideImage() and LayerSwapImage() functiosn are almost identical to the Image implementation function versions.

Layer Implementation

Although the LayerDisplay() function uses <DIV> and </DIV> tags instead of the usual Netscape <LAYER> and </LAYER> tags, they are still treated as Layers within the LayerSwapImage() function, which access the layers through the Layer object. Also included in the LayerDisplay() function are the inclusion of style attributes to specify the absolute positions of the images - including the zIndex, i.e. the relative order of the layers over one another.

The absolute top and left positions of each image are calculated based on the position of the image within the slide puzzle.

function LayerDisplay() {
    var image = 1;
    var output = '<DIV STYLE="position:relative;"><\/DIV>';
    for (var y=0; y<height; y++) {
        for (var x=0; x<width; x++, image++) {
            var top  = Math.floor((image-1)/width)*imageHeight;
            var left = ((image-1)%width)*(imageWidth) + (window.innerWidth - width*(imageWidth))/2;
            if (image != blank)
                output += '<DIV STYLE="position:absolute; top:' + top + 'px; left:' + left + 'px; zIndex:100;"><A HREF="javascript:LayerSlideImage(' + image + ')"><IMG SRC="images/' + image + ext + '" HEIGHT=' + imageHeight + ' WIDTH=' + imageWidth + ' BORDER=0><\/A><\/DIV>';
            else
                output += '<DIV STYLE="position:absolute; top:' + top + 'px; left:' + left + 'px; zIndex:0;"><A HREF="javascript:LayerSlideImage(' + image + ')"><IMG SRC="images/blank.gif" HEIGHT=' + imageHeight + ' WIDTH=' + imageWidth + ' BORDER=0><\/A><\/DIV>';
        }
    }
    document.write(output);
}

the LayerSlideImage() function additionally passes either the imageHeight or the imageWidth of the image to the LayerSwapImage() function.

function LayerSlideImage(image) {
    swapped = false;
    if ((Math.floor((image-1)/width) != 0) && (blank == image-width))
        LayerSwapImage(image,0,-1,imageHeight);
    else if (((image-1)%width != width-1) && (blank == image+1))
        LayerSwapImage(image,1,0,imageWidth);
    else if ((Math.floor((image-1)/width) != height-1) && (blank == image+width))
        LayerSwapImage(image,0,1,imageHeight);
    else if (((image-1)%width != 0) && (blank == image-1))
        LayerSwapImage(image,-1,0,imageWidth);
}

The LayerSwapImage() function uses the additionally passed image width or height to move the layer from one position to the next using the Layer objects moveBy() method, before then swapping the layers over by replacing the contents of the layers using the src property and altering the the zIndex property of the layers, so that the blank slot always has a lower zIndex value, i.e. it appears beneath all the other layers, such that when a layer is moved across it, the layers appear to pass by one another - a visually appealing alternative to the Multimedia effects in Microsoft Internet Explorer.

function LayerSwapImage(image,x,y,step) {
    for (var i=0; i<step; i++)
        document.layers[image-1].moveBy(x,y);
    document.layers[blank-1].document.images[0].src = document.layers[image-1].document.images[0].src;
    document.layers[blank-1].zindex = 100;
    document.layers[image-1].zindex = 0;
    document.layers[image-1].document.images[0].src = 'images/blank.gif';
    document.layers[image-1].moveBy(-x*imageWidth,-y*imageHeight);
    blank = image;
    swapped = true;
}

IFrame Implementation

The IFrameDisplay() function creates a table of empty floating frames, as opposed to a table of images. Once the table has been written to the document, then the additional function IFrameSetFrames() is invoked.

function IFrameDisplay() {
    var image = 1;
    var output = '<TABLE BORDER=1 CELLPADDING=0 CELLSPACING=0>';
    for (var y=0; y<height; y++) {
        output += '<TR>'
        for (var x=0; x<width; x++, image++) {
            output += '<TD><IFRAME FRAMEBORDER=0 MARGINHEIGHT=0 MARGINWIDTH=0 SCROLLING=NO HEIGHT=' + imageHeight + ' WIDTH=' + imageWidth + '><\/IFRAME><\/TD>';
        }
        output += '<\/TR>';
    }
    output += '<\/TABLE>';
    document.write(output);

    IFrameSetFrames();
}

The additional IFrameSetFrames() function, along with the IFrameSetFrameContent() and IFrameBlankFrameContent() functions populate the initially empty floating frames with dynamically generated HTML image links. Each of the images links executes the parent frames - the current document - IFrameSlideImage() function when the image links are clicked.

function IFrameSetFrames() {
    for (var i=1; i<=height*width; i++) {
        if (i != blank)
            IFrameSetFrameContent(i,i);
        else
            IFrameBlankFrameContent(i);
    }
}

function IFrameSetFrameContent(frame,image) {
    document.frames[frame-1].document.open();
    document.frames[frame-1].document.write('<TITLE>' + image + '<\/TITLE><A HREF="javascript:parent.IFrameSlideImage(' + frame +',' + image + ')"><IMG SRC="images/' + image + ext + '" BORDER=0 HEIGHT=' + imageHeight + ' WIDTH=' + imageWidth + '><\/A>');
    document.frames[frame-1].document.close();
}

function IFrameBlankFrameContent(frame) {
    document.frames[frame-1].document.open();
    document.frames[frame-1].document.write('<IMG SRC="images/blank.gif" BORDER=0 HEIGHT=' + imageHeight + ' WIDTH=' + imageWidth + '>');
    document.frames[frame-1].document.close();
}

The IFrameSlideImage() function is almost identical to the ImageSlideImage() function.

The IFrameSwapImage() function reuses the IFrameSetFrameContent() and IFrameBlankFrameContent() functions to swap the images by changing the contents of the frames.

function IFrameSwapImage(frame,image) {
    setIFrameContent(blank,image);
    blank = frame;
    blankIFrameContent(blank);
    swapped = true;
}

Frame Implementation

The FrameDisplay() function is not disimilar ot the IFrameDisplay() function. Instead of writing empty floating frames to the document, it instead writes a frameset (equivalent to the the tables used in other implementations) to hold empty blank.htm files.

Rather than then immeadiately replace the empty blank.htm files, we use the framesets onLoad event handler to invoke the FrameSetFrames() function. This ensures that all the frames have been correctly defined before we attempt to write into them.

function FrameDisplay() {
    var image = 1;
    var output = '<FRAMESET ROWS="' + imageHeight*height + ',*" FRAMEBORDER=0 BORDER=0 onLoad="FrameSetFrames()">';
    output += '<FRAMESET COLS="*,' + imageWidth*width + ',*">';
    output += '<FRAME SRC="blank.htm">';
    output += '<FRAMESET ROWS="'; for (i=1; i<height; i++) output += imageHeight + ','; output += imageHeight; output += '" FRAMEBORDER=0 BORDER=0>';
    for (var y=0; y<height; y++) {
        output += '<FRAMESET COLS="'; for (i=1; i<width; i++) output += imageWidth + ','; output += imageWidth; output += '" FRAMEBORDER=0 BORDER=0>';
        for (var x=0; x<width; x++, image++)
            output += '<FRAME NAME="' + image + '" SRC="blank.htm" HEIGHT=' + height + ' WIDTH=' + width + ' MARGINHEIGHT=0 MARGINWIDTH=0 SCROLLING=NO MARGINWIDTH=1 MARGINHEIGHT=1 NORESIZE>';
        output += '<\/FRAMESET>';
    }
    output += '<\/FRAMESET>';
    output += '<FRAME SRC="blank.htm">';
    output += '<\/FRAMESET>';
    output += '<FRAME SRC="blank.htm">';
    output += '<\/FRAMESET>';
    document.write(output);
}

The FrameSetFrames(), FrameSetFrameContent() and FrameBlankFrameContent() functions are similar to the previous IFrameSetFrames(), IFrameSetFrameContent() and IFrameBlankFrameContent() functions, except that instead of writing to the frames within the current document, it writes to the frames within the current window - a slight but subtle distiction.

function FrameSetFrames() {
    for (var i=1; i<=height*width; i++) {
        if (i != blank)
            FrameSetFrameContent(i,i);
        else
            FrameBlankFrameContent(i);
    }
}

function FrameSetFrameContent(frame,image) {
    window.frames[frame].document.open();
    window.frames[frame].document.write('<TITLE>' + image + '<\/TITLE><A HREF="javascript:parent.FrameSlideImage(' + frame +',' + image + ')"><IMG SRC="images/' + image + ext + '" BORDER=0 HEIGHT=' + imageHeight + ' WIDTH=' + imageWidth + '><\/A>');
    window.frames[frame].document.close();
}

function FrameBlankFrameContent(frame) {
    window.frames[frame].location.href = 'images/blank.gif';
}

The FrameSlideImage() and FrameSwapImage() functions are almost identical to the IFrameSlideImage() and iFrameSwapImage() functions - and are not shown.

Conclusion

Obviously, the slide puzzle, good though it is, only demonstrates some of the techniques that you can use for real in more substantive applications. Hopefully, you will make use of object detetion, rather than browser detection - as and when future browsers are released they will begin to support more and more objects. If you future proof your code now, then you'll not need to revist your code in the future to tweak it for the latest version X of browser Y - your code should be intelligent enough to work out what it should and shouldn't do all by itself (well that's the theory.)

Examination

The working example will detect which objects are supported by your browser and implement the most suitable version of the slide puzzle - don't waste too much time playing it :-)

Obfuscation

This article did not descibe each and every function definition in detail, therefore the source code is available in full below:

<SCRIPT TYPE="text/javascript" LANGUAGE="JavaScript"><!--
var height = 4, width = 6, imageHeight = 100, imageWidth = 100, blank = 1, ext = '.jpg';

var swapped = false;

function FilterSlideImage(image) {
    swapped = false;
    if ((Math.floor((image-1)/width) != 0) && (blank == image-width))
        FilterSwapImage(image,0,-1);
    else if (((image-1)%width != width-1) && (blank == image+1))
        FilterSwapImage(image,1,0);
    else if ((Math.floor((image-1)/width) != height-1) && (blank == image+width))
        FilterSwapImage(image,0,1);
    else if (((image-1)%width != 0) && (blank == image-1))
        FilterSwapImage(image,-1,0);
}

function IFrameSlideImage(frame,image) {
    swapped = false;
    if ((Math.floor((frame-1)/width) != 0) && (blank == frame-width))
        IFrameSwapImage(frame,image);
    else if (((frame-1)%width != width-1) && (blank == frame+1))
        IFrameSwapImage(frame,image);
    else if ((Math.floor((frame-1)/width) != height-1) && (blank == frame+width))
        IFrameSwapImage(frame,image);
    else if (((frame-1)%width != 0) && (blank == frame-1))
        IFrameSwapImage(frame,image);
}

function FrameSlideImage(frame,image) {
    swapped = false;
    if ((Math.floor((frame-1)/width) != 0) && (blank == frame-width))
        FrameSwapImage(frame,image);
    else if (((frame-1)%width != width-1) && (blank == frame+1))
        FrameSwapImage(frame,image);
    else if ((Math.floor((frame-1)/width) != height-1) && (blank == frame+width))
        FrameSwapImage(frame,image);
    else if (((frame-1)%width != 0) && (blank == frame-1))
        FrameSwapImage(frame,image);
}

function LayerSlideImage(image) {
    swapped = false;
    if ((Math.floor((image-1)/width) != 0) && (blank == image-width))
        LayerSwapImage(image,0,-1,imageHeight);
    else if (((image-1)%width != width-1) && (blank == image+1))
        LayerSwapImage(image,1,0,imageWidth);
    else if ((Math.floor((image-1)/width) != height-1) && (blank == image+width))
        LayerSwapImage(image,0,1,imageHeight);
    else if (((image-1)%width != 0) && (blank == image-1))
        LayerSwapImage(image,-1,0,imageWidth);
}

function SpanSlideImage(image) {
    swapped = false;
    if ((Math.floor((image-1)/width) != 0) && (blank == image-width))
        SpanSwapImage(image);
    else if (((image-1)%width != width-1) && (blank == image+1))
        SpanSwapImage(image);
    else if ((Math.floor((image-1)/width) != height-1) && (blank == image+width))
        SpanSwapImage(image);
    else if (((image-1)%width != 0) && (blank == image-1))
        SpanSwapImage(image);
}

function ImageSlideImage(image) {
    swapped = false;
    if ((Math.floor((image-1)/width) != 0) && (blank == image-width))
        ImageSwapImage(image);
    else if (((image-1)%width != width-1) && (blank == image+1))
        ImageSwapImage(image);
    else if ((Math.floor((image-1)/width) != height-1) && (blank == image+width))
        ImageSwapImage(image);
    else if (((image-1)%width != 0) && (blank == image-1))
        ImageSwapImage(image);
}

function FilterSwapImage(image,x,y) {
    eval('image' + blank + '.filters.item("BlendTrans").apply()');
    document.images[blank-1].src = document.images[image-1].src;
    eval('image' + blank + '.filters.item("BlendTrans").play()');
    eval('image' + image + '.filters.item("BlendTrans").apply()');
    document.images[image-1].src = 'blank.gif';
    eval('image' + image + '.filters.item("BlendTrans").play()');
    blank = image;
    swapped = true;
}

function IFrameSwapImage(frame,image) {
    setIFrameContent(blank,image);
    blank = frame;
    blankIFrameContent(blank);
    swapped = true;
}

function FrameSwapImage(frame,image) {
    FrameSetFrameContent(blank,image);
    blank = frame;
    FrameBlankFrameContent(blank);
    swapped = true;
}

function LayerSwapImage(image,x,y,step) {
    for (var i=0; i<step; i++)
        document.layers[image-1].moveBy(x,y);
    document.layers[blank-1].document.images[0].src = document.layers[image-1].document.images[0].src;
    document.layers[blank-1].zindex = 100;
    document.layers[image-1].zindex = 0;
    document.layers[image-1].document.images[0].src = 'images/blank.gif';
    document.layers[image-1].moveBy(-x*imageWidth,-y*imageHeight);
    blank = image;
    swapped = true;
}

function SpanSwapImage(image) {
    document.images[blank-1].src = document.images[image-1].src;
    blank = image;
    document.images[image-1].src = 'images/blank.gif';
    swapped = true;
}

function ImageSwapImage(image) {
    document.images['image'+blank].src = document.images['image'+image].src;
    blank = image;
    document.images['image'+blank].src = 'images/blank.gif';
    swapped = true;
}

function FilterDisplay() {
    var image = 1;
    var output = '';
    for (var y=0; y<height; y++) {
        for (var x=0; x<width; x++, image++) {
            var top  = Math.floor((image-1)/width)*(imageHeight+1);
            var left = ((image-1)%width)*(imageWidth+1);
            if (image != blank)
                output += '<A HREF="javascript:FilterSlideImage(' + image + ')"><IMG ID=image' + image + ' STYLE="position:relative; zIndex:100; filter:BlendTrans(Duration=0.4)" SRC="' + image + ext + '" HEIGHT=' + imageHeight + ' WIDTH=' + imageWidth + ' BORDER=0><\/A>';
            else
                output += '<A HREF="javascript:FilterSlideImage(' + image + ')"><IMG ID=image' + image + ' STYLE="position:relative; zIndex:0; filter:BlendTrans(Duration=0.4)" SRC="blank.gif" HEIGHT=' + imageHeight + ' WIDTH=' + imageWidth + ' BORDER=0><\/A>';
        }
        output += '<BR>';
    }
    document.write(output);
}

function IFrameDisplay() {
    var image = 1;
    var output = '<TABLE BORDER=1 CELLPADDING=0 CELLSPACING=0>';
    for (var y=0; y<height; y++) {
        output += '<TR>'
        for (var x=0; x<width; x++, image++) {
            output += '<TD><IFRAME FRAMEBORDER=0 MARGINHEIGHT=0 MARGINWIDTH=0 SCROLLING=NO HEIGHT=' + imageHeight + ' WIDTH=' + imageWidth + '><\/IFRAME><\/TD>';
        }
        output += '<\/TR>';
    }
    output += '<\/TABLE>';
    document.write(output);

    IFrameSetFrames();
}

function FrameDisplay() {
    var image = 1;
    var output = '<FRAMESET ROWS="' + imageHeight*height + ',*" FRAMEBORDER=0 BORDER=0 onLoad="FrameSetFrames()">';
    output += '<FRAMESET COLS="*,' + imageWidth*width + ',*">';
    output += '<FRAME SRC="blank.htm">';
    output += '<FRAMESET ROWS="'; for (i=1; i<height; i++) output += imageHeight + ','; output += imageHeight; output += '" FRAMEBORDER=0 BORDER=0>';
    for (var y=0; y<height; y++) {
        output += '<FRAMESET COLS="'; for (i=1; i<width; i++) output += imageWidth + ','; output += imageWidth; output += '" FRAMEBORDER=0 BORDER=0>';
        for (var x=0; x<width; x++, image++)
            output += '<FRAME NAME="' + image + '" SRC="blank.htm" HEIGHT=' + height + ' WIDTH=' + width + ' MARGINHEIGHT=0 MARGINWIDTH=0 SCROLLING=NO MARGINWIDTH=1 MARGINHEIGHT=1 NORESIZE>';
        output += '<\/FRAMESET>';
    }
    output += '<\/FRAMESET>';
    output += '<FRAME SRC="blank.htm">';
    output += '<\/FRAMESET>';
    output += '<FRAME SRC="blank.htm">';
    output += '<\/FRAMESET>';
    document.write(output);
}

function LayerDisplay() {
    var image = 1;
    var output = '<DIV STYLE="position:relative;"><\/DIV>';
    for (var y=0; y<height; y++) {
        for (var x=0; x<width; x++, image++) {
            var top  = Math.floor((image-1)/width)*imageHeight;
            var left = ((image-1)%width)*(imageWidth) + (window.innerWidth - width*(imageWidth))/2;
            if (image != blank)
                output += '<DIV STYLE="position:absolute; top:' + top + 'px; left:' + left + 'px; zIndex:100;"><A HREF="javascript:LayerSlideImage(' + image + ')"><IMG SRC="images/' + image + ext + '" HEIGHT=' + imageHeight + ' WIDTH=' + imageWidth + ' BORDER=0><\/A><\/DIV>';
            else
                output += '<DIV STYLE="position:absolute; top:' + top + 'px; left:' + left + 'px; zIndex:0;"><A HREF="javascript:LayerSlideImage(' + image + ')"><IMG SRC="images/blank.gif" HEIGHT=' + imageHeight + ' WIDTH=' + imageWidth + ' BORDER=0><\/A><\/DIV>';
        }
    }
    document.write(output);
}

function SpanDisplay() {
    var image = 1;
    var output = '';
    for (var y=0; y<height; y++) {
        for (var x=0; x<width; x++, image++) {
            if (image != blank)
                output += '<SPAN ID=image' + image + '><A HREF="javascript:SpanSlideImage(' + image + ')"><IMG SRC="images/' + image + ext + '" HEIGHT=' + imageHeight + ' WIDTH=' + imageWidth + ' BORDER=0><\/A><\/SPAN>';
            else
                output += '<SPAN ID=image' + image + '><A HREF="javascript:SpanSlideImage(' + image + ')"><IMG SRC="images/blank.gif" HEIGHT=' + imageHeight + ' WIDTH=' + imageWidth + ' BORDER=0><\/A><\/SPAN>';
        }
        output += '<BR>';
    }
    document.write(output);
}

function ImageDisplay() {
    var image = 1;
    var output = '<TABLE BORDER=1 CELLPADDING=0 CELLSPACING=0>';
    for (var y=0; y<height; y++) {
        output += '<TR>'
        for (var x=0; x<width; x++, image++) {
            if (image != blank)
                output += '<TD><A HREF="javascript:ImageSlideImage(' + image + ')"><IMG SRC="images/' + image + ext + '" NAME="image' + image +'" HEIGHT=' + imageHeight + ' WIDTH=' + imageWidth + ' BORDER=0><\/A><\/TD>';
            else
                output += '<TD><A HREF="javascript:ImageSlideImage(' + image + ')"><IMG SRC="images/blank.gif" NAME="image' + image +'" HEIGHT=' + imageHeight + ' WIDTH=' + imageWidth + ' BORDER=0><\/A><\/TD>';
        }
        output += '<\/TR>';
    }
    output += '<\/TABLE>';
    document.write(output);
}

function FrameSetFrames() {
    for (var i=1; i<=height*width; i++) {
        if (i != blank)
            FrameSetFrameContent(i,i);
        else
            FrameBlankFrameContent(i);
    }
}

function FrameSetFrameContent(frame,image) {
    window.frames[frame].document.open();
    window.frames[frame].document.write('<TITLE>' + image + '<\/TITLE><A HREF="javascript:parent.FrameSlideImage(' + frame +',' + image + ')"><IMG SRC="images/' + image + ext + '" BORDER=0 HEIGHT=' + imageHeight + ' WIDTH=' + imageWidth + '><\/A>');
    window.frames[frame].document.close();
}

function FrameBlankFrameContent(frame) {
    window.frames[frame].location.href = 'images/blank.gif';
}

function IFrameSetFrames() {
    for (var i=1; i<=height*width; i++) {
        if (i != blank)
            IFrameSetFrameContent(i,i);
        else
            IFrameBlankFrameContent(i);
    }
}

function IFrameSetFrameContent(frame,image) {
    document.frames[frame-1].document.open();
    document.frames[frame-1].document.write('<TITLE>' + image + '<\/TITLE><A HREF="javascript:parent.IFrameSlideImage(' + frame +',' + image + ')"><IMG SRC="images/' + image + ext + '" BORDER=0 HEIGHT=' + imageHeight + ' WIDTH=' + imageWidth + '><\/A>');
    document.frames[frame-1].document.close();
}

function IFrameBlankFrameContent(frame) {
    document.frames[frame-1].document.open();
    document.frames[frame-1].document.write('<IMG SRC="images/blank.gif" BORDER=0 HEIGHT=' + imageHeight + ' WIDTH=' + imageWidth + '>');
    document.frames[frame-1].document.close();
}

if (document.images) {
    if (document.all && navigator.platform.indexOf('Mac') == -1) {
        FilterDisplay();
    }
    else if (document.all) {
        SpanDisplay();
    }
    else if (navigator.appName == 'Microsoft Internet Explorer') {
        IFrameDisplay();
    }
    else if (document.layers) {
        LayerDisplay();
    }
    else 
        ImageDisplay();
}
else {
    FrameDisplay();
}
//--></SCRIPT>

Related items

How to do the impossible with Google Gears

Out and About

JavaScript Bouncing Balls

Multi-dialogue forms on one page

Turning Tables Into Selection Lists

Drag and Drop with Microsoft Internet Explorer 5

Dynamic Floating Tool Tips

What is DHTML?

String Gradients the Fun Way!

"The Light Fantastic"

©2018 Martin Webb