reptile7's JavaScript blog
Sunday, July 15, 2012
Pisces Arpeggia
Blog Entry #258

In today's post we will take up the Swimming Fish Example (Chapter 11) of Netscape's Dynamic HTML in Netscape Communicator resource. The Swimming Fish Example involves two animations in the vein of the animations appearing in HTML Goodies' "How to Create a JavaScript Animation" tutorial, but with a twist: the translating image is threaded through a set of images with differing z-axis positions, as though it were running an obstacle course. To see the first of these animations, click the button in the div below.

Fish Example 1

Note that the swimming fish passes in front of the blue and green poles but behind the red pole. The animation can be stopped by clicking the button. The second animation is even cooler: it moves the fish from left to right and from right to left, and reverses the z-axis positions of the poles for the right-to-left direction so that the fish passes in front of the red pole and behind the green and blue poles. I'll give you a demo for this animation in due course. The first and second animations are respectively covered by the example's Positioning and Moving the Fish and Poles and Changing the Stacking Order of Fish and Poles sections. We'll discuss the first animation in this entry and go after the second animation in the following entry. The Positioning and Moving the Fish and Poles section offers two versions of the first animation: (1) a fish1.htm version that works with actual layer elements; and (2) a fish1css.htm version that works with positioned span elements. We will confine ourselves to the fish1css.htm code for the deconstruction that follows. Fish and pole HTML/CSS The swimming fish is an animated .gif and each pole is a static .gif; these images are wrapped in span elements, which are given identifiers and positioned absolutely. #bluepole { position: absolute; top: 150px; left: 160px; } #greenpole { position: absolute; top: 150px; left: 360px; } #redpole { position: absolute; top: 150px; left: 260px; } #fish { position: absolute; top: 170px; left: 40px; } ... <span id="bluepole"><img src="bluepole.gif"></span> <span id="greenpole"><img src="greenpole.gif"></span> <span id="fish"><img src="fish1.gif"></span> <span id="redpole"><img src="redpole.gif"></span> With respect to their z-axis positions, the four span elements are stacked back to front in source order, that is, the bluepole span is on the bottom, the greenpole span is above the bluepole span, the fish span is above the greenpole span, and the redpole span is on top. Here is a brief technical explanation of the span stacking order: (1) Each of the four spans is part of the root stacking context established by the document's html element and has a stack level of 0 in that context. (2) Boxes with the same stack level in a stacking context are stacked back to front according to document tree order, quoting the W3C. (3) In a CSS context, tree order is defined as the preorder depth-first traversal of the rendering tree, meaning that the span elements, as DOM siblings, are tree-ordered as they are encountered by the browser's HTML rendering engine, and are therefore z-stacked in source order. The default span stacking order can be overridden by giving the spans specific (non-auto) z-index values, and we'll do that for the second animation. Other HTML Filling out the fish1css.htm document body is a "Fish Example 1" h1 heading and a button for setting the fish span in motion. <h1>Fish Example 1</h1> <form><input type="button" value="Move the fish" onclick="movefish( ); return false;"></form> (The button is my own little contribution - it's not in the fish1css.htm code.) Let's go, fish Clicking the button calls the following movefish( ) function: function movefish( ) {     var fish = document.layers["fish"];     if (fish.left < 400) { fish.offset(5, 0); }     else { fish.left = 10; }     window.setTimeout("movefish( );", 10);     return; } As intimated in the previous post, Netscape 4.x treats positioned non-layer elements as 'honorary layers' that can be accessed à la actual layer elements and manipulated via the properties and methods of the client-side layer object. The first animation acts only on the fish span; the second animation acts on all four spans. The movefish( ) function first gets the fish span/layer and assigns it to a fish variable. Next, an if...else statement tests if the value of fish's left property - the horizontal distance in pixels between the left edge of the viewport and the left edge of the fish layer - is less than 400; if so, then the fish layer is moved horizontally 5 pixels to the right by a fish.offset(5,0); command; if not (when the fish left value hits 400), then the fish left value is set to 10. Finally, a setTimeout( ) command re-calls the movefish( ) function after a 10-millisecond delay to keep the animation going. • In contrast to CSS's top/right/bottom/left properties (vide infra), the layer object's left/top properties can be read if they are set in a style sheet. • The default unit of measurement for the layer object's left/top properties is pixels; it is not necessary to append px unit identifiers to the fish left values. • Neither the DHiNC resource nor the JavaScript 1.3 Client-Side Reference lists an offset( ) method for the layer object, and the Swimming Fish Example's text itself (see the Moving the Fish subsection) specifies the layer object's moveBy( ) method for moving the fish layer. From running the fish1css.htm demo with Netscape Communicator 4.61 in the SheepShaver environment, I can confirm that the offset( ) method does what the moveBy( ) method does. (FWIW: the offset( ) method does not turn up in a probe of the fish object.) But we actually don't have to use either of these methods to move the fish: a fish.left += 5; statement would do the trick. • Lastly and least, the return false; statement in the button's onclick event handler and the return; statement at the end of the movefish( ) function body serve no purpose, and can be thrown out. A new-and-improved movefish( ) So, how do we get the movefish( ) function to work with modern browsers? (1) Access the swimming fish with a document.getElementById("fish") expression. (2) Exchange the fish.left/offset( ) action for corresponding style object commands that read and write the CSS left property. (3) To read the CSS left property, it is necessary to set the initial fish left offset (40px) either via an HTML style attribute or scriptically; in the Remarks section of its style object page, Microsoft notes, The style object does not provide access to the style assignments in style sheets. (4) The value of the CSS left property includes a unit identifier and has a string data type in a JavaScript context, so to arithmetically increment it we'll have to extract its numerical part: the top-level parseInt( ) function is tailor-made for this operation. (The value of the layer object's left property has a number data type.) (5) The browsers on my computer let me get away with assigning a number to a expression (e.g., else = 10;), but I still think it's a good idea to tack on a unit identifier and stringify the value; after all, the unit is supposed to be there. Putting it all together, here is my demo's JavaScript: var fish = document.getElementById("fish"); = "0px"; var leftnumber, timerID; function movefish( ) {     leftnumber = parseInt(, 10);     if (leftnumber < 400) = (leftnumber + 5) + "px";     else = "10px";     timerID = window.setTimeout("movefish( );", 30); }   Other demo notes Do we really need the span containers? Nah, throw 'em out - there's no reason not to directly position/manipulate the imgs themselves. The original 10-millisecond setTimeout( ) delay gave a fish movement that was too fast for my taste, so I increased it to 30 milliseconds. The setTimeout( ) command is assigned to a globally declared timerID, which can be 'cleared' by the button <button type="button" onclick="window.clearTimeout(timerID);">Chill out, fish</button> to stop the animation.
We'll put the Changing the Stacking Order of Fish and Poles animation under the microscope in our next episode.

Comments: Post a Comment

<< Home

Powered by Blogger

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