reptile7's JavaScript blog
Saturday, September 18, 2010
The Black and the Red
Blog Entry #191

The scrolling text scripts we've discussed in recent entries nicely illustrate an important aspect of JavaScript: JavaScript can dynamically change values not only 'all in one go' but also in a gradual, stepwise manner. Our Beyond HTML : JavaScript tutorial du jour, "So, You Want A Background JavaScript, Huh?", continues in this vein by presenting a script designed to gradually change a document's background color.

The "Background JavaScript" script can be accessed by following the tutorial's The Script Is Here link. The script was once put in the tutorial source so as to provide a script demo as the tutorial page loads but, à la the "Live Script" script discussed in the previous post, was removed therefrom when the HTML Goodies site was remodeled in early 2005. However, at earlier editions of the tutorial (e.g., here) the script does not work as advertised on my computer, so perhaps I should give you a little taste of how it's supposed to go here and now. In the div below, click the button:

Cool, huh?

I'll discuss my demo, how its code differs from that on the backjava.txt page, and how it can be improved in due course, but for now, let's get deconstructing the backjava.txt code, shall we? Script overview The "Background JavaScript" script comprises two script elements (the first script element's start-tag is missing on the current backjava.txt page but is present on the pre-15-February-2005 backjava.txt page). The first script element contains three functions, in source order: (1) an initArray( ) function, which is never called and can be thrown out; (2) a Dec2Hex( ) function for converting decimal numbers to hexadecimal numbers - we'll see later that this function is also unnecessary; and (3) a bgChanger( ) function that does most of the script's work. The second script element holds a series of eight calls to bgChanger( ); each call takes the document background color from a begin color to an end color. Per these calls, the document's background color is changed from black to red to black to #aa00ee (labeled purple in the preceding comment, but purple is actually #800080) to black to blue to black to finally white. The first bgChanger( ) call (bgChanger("000000", "000000", 25);) does not in fact effect a background color change - it is meant to function as a black-to-black "pause" - and can be removed. Let us then consider the second bgChanger( ) call, which takes us from black to red: // black to red bgChanger("000000", "FF0000", 25); 000000 and FF0000 are of course the RRGGBB hex codes for black and red, respectively. bgChanger( ) will initially set document.bgColor to 000000 (it was not necessary to preface an RRGGBB value with a hash mark (#) in classical JavaScript) and then incrementally change document.bgColor to FF0000 over the course of 23 intermediate RRGGBB values; however, this change is carried out on a decimal basis, as detailed below. 00 to FF The black to red background color change makes a good deconstruction test case as it will allow us to focus on the RR parts of these colors' hex codes and mostly ignore the GG and BB parts, for which no change occurs. As shown above, the second bgChanger( ) call passes to bgChanger( )
function bgChanger(begin, end, steps) {
	steps = steps -1;
	... }
three arguments: (1) the string "000000", which is assigned to begin; (2) the string "FF0000", which is assigned to end; and (3) 25, which specifies the total number of values that will be assigned to document.bgColor from start to finish and is given a steps identifier. bgChanger( )'s first statement decrements steps to 24 - we'll see why in a moment. The next two bgChanger( ) lines extract the RR part of "000000" and convert it to its decimal equivalent redA = begin.charAt(0) + begin.charAt(1); // Returns the string "00" red_valA = parseInt(redA, 16); // Returns the number 0 /* In the original script, the parseInt( ) radix argument, 16, is single-quoted; it shouldn't be. */ and the two bgChanger( ) lines after that do the same for "FF0000": redB = end.charAt(0) + end.charAt(1); // Returns the string "FF" red_valB = parseInt(redB, 16); // Returns the number 255 So, RR-wise we want to decimally begin at 0 (red_valA) and end at 255 (red_valB). The next bgChanger( ) line uses steps to calculate an equidistant spacing between (25) successive R values via which 0 will be incremented to 255: red_int = ((red_valB - red_valA) / steps) * -1; // Returns the number -10.625 (Recall from middle school geometry class that if a line segment running from a to b is divided into c point-delimited segments of equal length, then the distance between points is given by (a - b) / c.) The next ten bgChanger( ) lines carry out analogous operations for the GG and BB parts of "000000" and "FF0000"; by inspection, you should be able to determine that grn_valA, grn_valB, grn_int, blu_valA, blu_valB, and blu_int will all be 0. The following bgChanger( ) line declares/initializes to 2 a step counter variable for RR value incrementation. Subsequently, red_valA, grn_valA, and blu_valA, all 0, are respectively assigned to red, grn, and blu variables. step = 2; red = red_valA; grn = grn_valA; blu = blu_valA; We are ready to begin setting and changing the document background color. A document.bgColor = begin; assignment sets the document background color to its initial color, black, and is followed by a while loop that will take the red part of document.bgColor from 0 to 244.375.
while (steps >= step) {
	red -= red_int;
	red_round = Math.round(red);
	red_hex = Dec2Hex(red);
	/* Analogous code for grn and blu */
	document.bgColor = red_hex + grn_hex + blu_hex;
	step++; }
The loop body will be executed 23 times. Here's what happens in the first loop iteration: (1) red -= red_int; increments red to 10.625. Perhaps you are wondering, "Why don't we use the += operator to increment red, and get rid of the -1 factor in red_int's declaration?" Well, that would be more intuitive, wouldn't it? (2) red_round = Math.round(red); rounds red up to 11, which is assigned to red_round. (3) The script's Dec2Hex( ) function is called; Dec2Hex( ) should be passed red_round and not red.
var hexChars = "0123456789ABCDEF";

function Dec2Hex(Dec) {
	var a = Dec % 16; /* The % arithmetic operator is briefly summarized here. */
	var b = (Dec - a) / 16;
	hex = "" + hexChars.charAt(b) + hexChars.charAt(a);
	return hex; }
(4) Dec2Hex( ) converts the red_round number to a corresponding two-digit hexadecimal string. (a) red_round is given a Dec identifier. (b) The var a = Dec % 16; line indirectly calculates the ones-place digit of Dec's hexadecimal equivalent. 11 % 16 gives 11, which is assigned to an a variable. (c) The var b = (Dec - a) / 16; line indirectly calculates the tens-place digit of Dec's hexadecimal equivalent. (11 - 11) / 16 gives 0, which is assigned to a b variable. (d) The hex = "" + hexChars.charAt(b) + hexChars.charAt(a); line builds the two-digit hexadecimal string. An empty string, 0 (hexChars.charAt(b)), and B (hexChars.charAt(a)) are concatenated to give the string "0B", which is assigned to hex. (e) hex is returned to the Dec2Hex( ) function call. Back in the bgChanger( ) function, the Dec2Hex( ) return is given a red_hex identifier. We can convert Dec to hex more straightforwardly, and without the need for the hexChars hexadecimal digit string, via the toString( ) method of the Number object:
function Dec2Hex(Dec) {
	var hex = Dec.toString(16);
	if (/^[0-9a-f]$/.test(hex)) hex = 0 + hex; /* This statement ensures a two-digit hex if the toString( ) return only holds one digit. */
	return hex; }
(5) The analogous grn and blu parts of the loop lead to a "00" string return for both grn_hex and blu_hex. (6) red_hex ("0B"), grn_hex ("00"), and blu_hex ("00") are concatenated to give "0B0000", which is assigned to document.bgColor. (7) step++; increments step to 3. In the second loop iteration: red increments to 21.25, which is rounded to 21, which is converted by Dec2Hex( ) to the string "15", and therefore "150000" is assigned to document.bgColor. red_hex - more precisely, the number it stringifies - continues to hexadecimally increase by B or A (depending on whether the Math.round( ) operation rounds up or down, respectively) in successive iterations until it hits "F4" in the 23rd iteration. Here are the document.bgColor hex codes for these iterations:
3rd: 200000		10th: 6A0000		17th: B50000
4th: 2B0000		11th: 750000		18th: BF0000
5th: 350000		12th: 800000		19th: CA0000
6th: 400000		13th: 8A0000		20th: D50000
7th: 4A0000		14th: 950000		21st: DF0000
8th: 550000		15th: 9F0000		22nd: EA0000
9th: 600000		16th: AA0000		23rd: F40000
At the end of the 23rd iteration, step increments to 25 and consequently the while condition is no longer true. Control now passes to bgChanger( )'s final statement, a document.bgColor = end; command that sets the document background color to FF0000. I trust you can à la my analysis work through the other bgChanger( ) color changes at this point. Let's sum up: • The bgChanger( ) function first separates the RR/GG/BB parts of the begin and end hex code strings and converts them to decimal equivalents. • bgChanger( ) next calculates equidistant spacings for the R/G/B parts of the values that we want to assign to document.bgColor and then serially raises or lowers the decimal begin R/G/B numbers by those spacings. • The raised/lowered decimal R/G/B numbers are converted back to corresponding hexadecimal strings, which are reassembled into hex code strings, which in turn are assigned to document.bgColor to change the document background color. So far, so good. As for how this all works in practice, well, we'll get to that in the next post. reptile7

Comments: Post a Comment

<< Home

Powered by Blogger

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