reptile7's JavaScript blog
Wednesday, September 29, 2010
 
Approaching Iridescence
Blog Entry #192

We continue today our discussion of HTML Goodies' "So, You Want A Background JavaScript, Huh?" tutorial and its document.bgColor-manipulating script. In the previous entry, I noted, [A]t earlier editions of the tutorial ... the script does not work as advertised on my computer - let me flesh this out a bit.

The tutorial's 'blurb' on the Beyond HTML : JavaScript portal page reads Produce a burst of color before your page loads and alter the colors that display!, which suggests that the "Background JavaScript" script should be placed in the document head. Just before the tutorial's "Changing Colors" section, Joe more specifically recommends, Paste the script right under your <HTML> command, before the title commands. In this position it will run before putting up any text. Then write the rest of your page as you would any other. However, on my system - my Intel iMac plus the hard disk rescued from my defunct G3 iMac - all of the OS X browsers and a majority of the Classic Mac browsers balk at executing a document.bgColor command if its trigger - the command itself as top-level code, or a call to a function containing the command - appears in the document head.

Upon placing the script's bgChanger( ) calls in the document body (the bgChanger( ) function itself can be left in the document head), a much more serious problem becomes apparent. All of my system's browsers smoke through the script's bgChanger( ) runs at a rate that precludes seeing any color changes - all I see is the final white ("FFFFFF") background color - with one exception: executing the script with MSIE 4.5 (in the SheepShaver environment) gives the desired effect, an effect whose document.bgColor change occurs much faster than that of the black-to-red demo I gave you last time, I might add.

Did Joe actually try the script with Netscape way back when? I can confirm that neither Netscape 3.04, Netscape 4.61, Netscape 6.2.3, nor Netscape 7.02 acts on the script as MSIE 4.5 does, although the tutorial makes no mention of browser-specificity. But anyway, now that I know how this thing is supposed to work, let me give you a new-and-improved demo. In the div below, click the button:

Ta-da!

 
Clearly, it is necessary to somehow slow the script down in order to see its color changes. In this regard, the script's key feature - the while loop that increments red, grn, and blu - is also its Achilles heel: loops are not meant to be slowed down but rather to execute an iterative block of code as quickly as possible. The present situation is reminiscent of the assignment for HTML Goodies' JavaScript Primers #24, which attempts to use for loops to delay the execution of document.bgColor commands and is plagued by the same only-the-final-color-is-visible problem. Alternatively, we can recast the loop as a recursive function and then control the rate of recursion via the setTimeout( ) method of the window object - a technique we are well versed in at this point and that underpins the above demo. Here is an outline of the changes that the demo makes to the original backjava.txt code: • bgChanger( ) has been split into two functions: (1) an initRGB( ) function that sets up red, grn, and blu, and sets the document background to the begin color, and (2) a changeBC( ) function that handles red/grn/blu background color incrementation. Before going any further, I should note that document.bgColor is in fact deprecated and that, per Mozilla's recommendation, my demos use document.body.style.backgroundColor to set the document background color. As identifiers, the begin, end, and steps initRGB( ) parameters would ordinarily be scope-wise limited to the initRGB( ) function. The changeBC( ) function does not need to act on begin but does need to act on end and steps, and thus it is necessary to pass the latter two parameters to changeBC( ).
	...
	changeBC(end, steps); } // End of the initRGB( ) function

function changeBC(end, steps) {
	...
• Delayed changeBC( ) recursion is carried out via the following conditional: if (step <= steps) window.setTimeout("changeBC('" + end + "'," + steps + ");", 70); /* The setTimeout( ) delay in the #bgcolordemo1 demo was 200 milliseconds. Your specific choice for this number is ultimately a matter of taste, of course. */ • After an initial black-to-red run, subsequent begin-to-end runs are triggered not as top-level code but in the changeBC( ) function, and in sync with a totalsteps variable that is globally initialized to 0 and is increased by one whenever document.body.style.backgroundColor is set.
else {
	document.body.style.backgroundColor = "#" + end;
	totalsteps++;
	if (totalsteps == 25) initRGB("ff0000", "000000", 25);
	if (totalsteps == 50) initRGB("000000", "aa00ee", 25);
	if (totalsteps == 75) initRGB("aa00ee", "000000", 25);
	... } } // End of the changeBC( ) function
Other code possibilities   Losing Dec2Hex( ) I stated in the previous entry that the script's Dec2Hex( ) function is unnecessary; this is because document.body.style.backgroundColor can be set to a stringified rgb(R,G,B) function taking decimal R, G, and B values. Accordingly, in the changeBC( ) function we can comment out the red_hex/grn_hex/blu_hex lines and then set the intermediate (non-begin/end) document.body.style.backgroundColor values with: document.body.style.backgroundColor = "rgb(" + red_round + "," + grn_round + "," + blu_round + ")"; Relatedly, we could if desired feed decimal R, G, and B values to the initRGB( ) function - this would allow us to ditch initRGB( )'s charAt( ) and parseInt( ) code:
function initRGB(red_valA, grn_valA, blu_valA, red_valB, grn_valB, blu_valB, steps) {
	steps = steps - 1;
	red_int = (red_valB - red_valA) / steps;
	grn_int = (grn_valB - grn_valA) / steps;
	blu_int = (blu_valB - blu_valA) / steps;
	... }

<!-- Black to red: -->
<element onEvent="initRGB(0,0,0,255,0,0,25);"> ...
Moreover, there's no need to hold on to the begin variable in this case as document.body.style.backgroundColor can be set to its initial color with document.body.style.backgroundColor = "rgb(" + red_valA + "," + grn_valA + "," + blu_valA + ")"; but you'll still need to define end in the initRGB( ) function as end = "rgb(" + red_valB + "," + grn_valB + "," + blu_valB + ")"; and then pass end to the changeBC( ) function for setting document.body.style.backgroundColor to its final color. (OK, we could get rid of end too if we wanted to. I can think of at least one end-less alternative but it doesn't offer any improvement over the preceding code.) A smoother color change In preparation for this post, I wrote an alternate version of the #bgcolordemo2 demo in which red/grn/blu are incremented not by red_int/grn_int/blu_int but by one decimal unit at a time; this alternate demo - let's call it #bgcolordemo3 - was inspired by HTML Goodies' JavaScript Script Tips #76-78 script, which (when using Netscape 4.x, and only when using Netscape 4.x) vertically rolls out and rolls up a layer element on a pixel-by-pixel basis and which we checked over in Blog Entry #94. As a means of effecting the color 'flashes' of the #bgcolordemo2 demo, the #bgcolordemo3 code now strikes me as inefficient but it does give smoother transitions vis-à-vis the slower color change of the #bgcolordemo1 demo, so I thought we would talk about it a bit. #bgcolordemo3's initRGB( ) function has a two-parameter String hexcodeA, String hexcodeB signature, and it specifies red, grn, blu, red_valB, grn_valB, and blu_valB à la the #bgcolordemo2 script. However, #bgcolordemo3 eliminates the initRGB( ) steps calculations and recasts the incrementation code in the changeBC( ) function as: if (red < red_valB) red++; else if (red > red_valB) red--; if (grn < grn_valB) grn++; else if (grn > grn_valB) grn--; if (blu < blu_valB) blu++; else if (blu > blu_valB) blu--; document.body.style.backgroundColor = "rgb(" + red + "," + grn + "," + blu + ")"; Delayed changeBC( ) recursion is carried out via the following conditional: if (!(red == red_valB && grn == grn_valB && blu == blu_valB)) window.setTimeout(changeBC, 10); /* More incrementations ⇒ a shorter setTimeout( ) delay. Mozilla addresses here the minimum value for the setTimeout( ) delay parameter. */ As long as the current color - rgb(red,grn,blu) - is not equal to the final color - rgb(red_valB,grn_valB,blu_valB) - then changeBC( ) will be re-called. changeBC( ) is not parameterized: we've already gotten rid of steps; the end variable is eliminated by setting document.body.style.backgroundColor to its final color with document.body.style.backgroundColor = "rgb(" + red_valB + "," + grn_valB + "," + blu_valB + ")"; in an accompanying else clause. After an initial script run, subsequent runs are triggered in the else clause and in sync with a bgChange variable that is globally initialized to 0 and increased by one at the end of a run. ... bgChange++; if (bgChange == 1) initRGB("ff0000", "000000"); if (bgChange == 2) initRGB("000000", "aa00ee"); if (bgChange == 3) initRGB("aa00ee", "000000"); ...   Other applications/demo #3 The code detailed in this entry can be applied not only to the background color of a document but to any colorable aspect of a Web page: text, borders, tables and rows/cells thereof, etc. Accordingly, I thought it would be cool to wrap up this post by applying the A smoother color change code to a text scroll:
 

The scroll part of the demo was taken from the #scrolldemo189 demo at the end of Blog Entry #189. The demo applies to the scroll a series of colors - red, orange, yellow, green, blue, indigo, and violet - that runs cyclically via the following conditional:

if (bgChange == 6) { bgChange = 0; initRGB("ee82ee", "ff0000"); } // Violet to red

A brief note on script authorship

At the top of the tutorial page, Joe acknowledges, Thanks to Josh Robbins for this script. On the other hand... I was curious as to whether anyone had come up with a catchy name for #aa00ee, which is not a standard color, so I did a Google search on it; among the many resulting hits were a number of pages hosting the "Background JavaScript" script, including this page on which a Geoff Baysinger claims authorship of the script (excluding the Dec2Hex( ) function, which he credits to the hIdaho ColorCenter). Geoff or Josh or whoever, we thank you for your efforts.

We're nearing the end of the 'classic' Beyond HTML : JavaScript tutorials written by Joe, and there's really just one left to cover, "A Quick Tutorial on JavaScript Variable Passing" - we'll hit this guy next time.

reptile7

Comments: Post a Comment

<< Home

Powered by Blogger

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