reptile7's JavaScript blog
Thursday, February 14, 2013
When the Butterfly Hits the Wall
Blog Entry #279

We continue today our analysis of Peter Gehrig's floating images script. We have one last script function to consider, namely, the checkposition( ) function, which bounces the span+i spans when they hit the edges of the viewport. As for the script's setValues( ), checkmovement( ), and movepictures( ) functions, the checkposition( ) function body comprises separate if statements that respectively cater to IE and Netscape; we will work with the IE statement in the discussion below.

function checkposition( ) {
    if (document.all) {
        for (i = 0; i <= numberofimages; i++) {
            var thisspan = eval("document.all.span" + i + ".style");
            ... } ... } ... }

Each if statement in turn contains another four if statements that respectively bounce the spans at the viewport's four edges. Here's the IE statement code that handles the right-edge action:

if (thisspan.posLeft > marginright - imgwidth[i]) {
    thisspan.posLeft -= Math.abs(stepx[i] + 1);
    stepx[i] = randommaker(floatingspeed) * -1; /* Alternatively: stepx[i] = -randommaker(floatingspeed); */ }

Recall that marginright was set to document.body.clientWidth-5 by the corresponding IE statement in the setValues( ) function and that imgwidth[i], the span-link-image width, is 35 (pixels). If a span's style.posLeft (left edge) moves within a 40px-wide buffer abutting the right edge of the viewport:

(1) The span's stepx[i] horizontal step is incremented and the span is shifted leftward by stepx[i]+1 pixels.

(2) A new, negative stepx[i] is calculated for the span by feeding floatingspeed (5) to the randommaker( ) function and then multiplying the rand return by -1.

The checkposition( ) function is called before the movepictures( ) function for a reason: a span's starting style.posLeft offset could be inside the marginright-imgwidth[i] buffer; in this situation the Math.abs( ) operation keeps the span moving leftward (more precisely, it prevents any rightward movement) if a single stepx[i]+1 shift does not push the span's style.posLeft out of the buffer. That said, the thisspan.posLeft -= Math.abs(stepx[i] + 1); statement is in fact unnecessary as the movepictures( ) function by itself will push the span out of the buffer sooner or later (within a second), regardless of the span's style.posLeft/stepx[i] values.

The corresponding if statements for the viewport's other three edges are given below. The posLeft/posTop assignments in these statements are again unnecessary. I have no idea why the stepx[i] shift in the right-edge statement is incremented whereas the stepx[i]/stepy[i] shifts in the other statements are not.

var marginleft = 0;
var margintop = 0;

if (thisspan.posLeft < marginleft) { // For the left edge
    thisspan.posLeft += Math.abs(stepx[i]);
    stepx[i] = randommaker(floatingspeed); }
if (thisspan.posTop > marginbottom - imgheight[i]) { // For the bottom edge
    thisspan.posTop -= Math.abs(stepy[i]);
    stepy[i] = randommaker(floatingspeed) * -1; }
if (thisspan.posTop < margintop) { // For the top edge
    thisspan.posTop += Math.abs(stepy[i]);
    stepy[i] = randommaker(floatingspeed); }

A span is bounced rightward if its style.posLeft moves to the left of marginleft, the viewport's left edge; it is bounced upward if its style.posTop (top edge) is initially positioned in or moves within a 40px-high marginbottom-imgheight[i] buffer at the bottom of the viewport; it is bounced downward if its style.posTop moves above margintop, the viewport's top edge.

The horizontal scrollbar thing, revisited

Let's get back to the marginright-imgwidth[i] right buffer for a moment. If a span is outside the buffer, then the -5 subtraction built into marginright should prevent the span from bumping into the right edge of the viewport and generating a horizontal scrollbar
(a) on the IE side whether or not a vertical scrollbar is initially present
(b) and on the Netscape side if a vertical scrollbar is not initially present
(recall that 4 is the highest stepx[i] value)
(c) but not on the Netscape side if a vertical scrollbar is initially present as the scrollbar's width is included in Netscape's window.innerWidth-5 marginright.
A corresponding set of circumstances applies to the marginbottom-imgheight[i] bottom buffer and the generation of a vertical scrollbar. In practice on my computer, (b) pans out but (a) and (c) don't: I end up getting horizontal and vertical scrollbars with IE 5.1.6 but not with Netscape 4.61 whether or not any scrollbars are initially present. (IE 5.x and Netscape 4.x were the current versions of IE and Netscape respectively when the floating images script was crafted in the summer of 2000.)

Lissa dealt with the scrollbar generation problem by giving the body element overflow-x:hidden; and overflow-y:hidden; stylings.

<body id="thisbody" bgcolor="#ffcc00" onload="setValues( );" style="width:100%;overflow-x:hidden;overflow-y:hidden;">

We first encountered the overflow-x and overflow-y style properties in our discussion of Peter Gehrig's cursor trailer script, for which I thought they were superfluous, but I would agree that they are useful in the present case. The overflow-x and overflow-y properties are dimensional versions of the standard CSS overflow property and are themselves on track to be standardized. Back in the day overflow-x and overflow-y were IE only (and didn't work on the Mac platform); today they are supported by all of the major browsers. However, if overflow-x and overflow-y are both set to hidden, then it would probably be a good idea to replace the overflow-x:hidden;overflow-y:hidden; declarations with a single overflow:hidden; declaration as W3Schools reports that overflow-x and overflow-y do not work properly in IE 8 and earlier.

More retool

In this section I'll describe the additional changes I would make to the floating images script.


First and foremost, I would throw out the span+i span wrappers and the your_image_link link wrappers and just work with a bttr0.gif/bttr1.gif/bttr2.gif/bttr3.gif/bttr4.gif set of images.

.floatingimage { position: absolute; }
for (i = 0; i < your_image.length; i++) document.write("<img id='img" + i + "' class='floatingimage' src='bttr" + i + ".gif'>");

In the setValues( ), movepictures( ), and checkposition( ) functions, I would reference the images via a globally declared floats array.

var floats = new Array(5);
if (document.getElementById)
    window.onload = function ( ) {
        for (i = 0; i < your_image.length; i++) floats[i] = document.getElementById("img" + i);
        setValues( ); }

Although modern browsers support the original script's document.all.span code, getting the images with the getElementById( ) method is clearly the better way to go. Moreover, defining the floats array when the page loads makes it unnecessary to create thisspan-type object references over and over again in the script's functions.


Naturally, we want to replace the nonstandard posLeft/posTop property pair with the standard left/top property pair. When writing offsets a simple substitution of the latter for the former will suffice:

// Initial positioning in the setValues( ) function:
for (i = 0; i < your_image.length; i++) {
    floats[i].style.left = randommaker(marginright) + "px";
    floats[i] = randommaker(marginbottom) + "px"; }

The px unit specifications are not necessary if the user's browser is running in quirks mode but I encourage you to put them there anyway.

When reading and subsequently operating on offsets in the movepictures( ) and checkposition( ) functions the situation is more complicated because left and top are strings that include unit identifiers; for these operations we'll need to 'numberify' left and top via the top-level parseInt( ) function.

function movepictures( ) {
    for (i = 0; i < your_image.length; i++) {
        floats[i].style.left = parseInt(floats[i].style.left, 10) + stepx[i] + "px";
        floats[i] = parseInt(floats[i], 10) + stepy[i] + "px"; } }


• The script's layer object code is only supported by Netscape 4.x - throw it out. The three if(document.all) gates can be traded in for a single if(document.getElementById) gate that guards the window.onload functionality.

• The -5 subtractions of the marginbottom/marginright definitions can themselves be subtracted if the document body's overflow is hidden.

// The source for my original demo put these statements in the window.onload function body.
marginright = window.innerWidth ? window.innerWidth : document.body.clientWidth;
marginbottom = window.innerHeight ? window.innerHeight : document.body.clientHeight;

• The var x, y; declaration in the first script element can be removed: no use is made of these variables.


Spring is in the air...

Further study

The How do I make floating images? subsection's Peter Gehrig link to is dead; however, there are several floating images scripts at that you may want to check out:
(1) Image Gallery with Floating Thumbnails
(2) JavaScript 3D-Slideshow
(3) Floating YouTube Video
(4) Floating Images Animation
(5) New-Year-Animation: Floating Luckycharms Script
(Unfortunately, most of the images accompanying these scripts were not saved by the Internet Archive - the Floating Luckycharms Script images are there but the rest of them are gone - but at least the code is still available.)

We'll move on to Section 7's trailing images script in the following entry.

Comments: Post a Comment

<< Home

Powered by Blogger

Actually, reptile7's JavaScript blog is powered by Café La Llave. ;-)