reptile7's JavaScript blog
Tuesday, January 01, 2008
 
Strings in Living Technicolor
Blog Entry #99

Today we return to the topic of color as we take up the "Rainbow Text" script discussed in HTML Goodies' JavaScript Script Tips #81, #82, and #83. As you know, the 'traditional'* HTML tool for adding color to inline text is the now-deprecated font element and its color attribute. The core JavaScript String object has a corresponding fontcolor( ) method that in effect wraps a string in a <font color="color"> ... </font> container. (Although not deprecated, the fontcolor( ) method is nonetheless "non-standard" in the sense that it is not part of ECMAScript.) The Script Tips #81-83 Script uses the fontcolor( ) method in conjunction with other JavaScript tools to create randomly and periodically 'heterocolored' text strings, which are displayed here.
(*I hesitate to use the word 'traditional' because the font element does not appear in early versions of HTML, e.g., HTML 2.0.)

The Script Tips #81-83 Script can be accessed by following the Here's the Code links in all three script tips and is reproduced in the div below:

<html>
<head>

<title>Put Some Colors Into The Text</title>

<script language="javascript" type="text/javascript">
<!-- Start hiding
var i;

function ColoredText( ) {
var argLen = ColoredText.arguments.length;
if (argLen == 0)
{ argLen = 1; }

var text = ColoredText.arguments[0]; 
var textLen = ColoredText.arguments[0].length;
var defClrsArray = new Array("red", "purple", "cyan", "green", "blue", "magenta"); /* default colors, change as needed */

for (i = 0; i < textLen; i++) {
charColor = text.charAt(i);

if (argLen == 1) 
{
colorCode = Math.floor(Math.random( ) * defClrsArray.length);
tempStr = charColor.fontcolor(defClrsArray[colorCode]);
}

else
{
colorCode = i % (argLen - 1);
tempStr = charColor.fontcolor(ColoredText.arguments[colorCode + 1]);
}
document.write(tempStr);
}
}
// Stop hiding -->

</script>
</head>

<body bgcolor="#ffffcc">

<script language="javascript" type="text/javascript">

<!-- Start hiding

ColoredText("This is a text sample written using the function ColoredText");

document.write("<br />");

ColoredText("Another text sample, this time only with red and orange repeatedly", "red", "orange");

document.write("<br /><h1>");

ColoredText("Another sample with shades of green", "#006000", "#007000", "#008000", "#009000", "#00a000", "#00b000");

document.write("</h1><br /><br /><center><font face='courier' size='+2'>");

ColoredText("Try refreshing the page a couple of times!");

document.write("</font></center>");

// Stop hiding -->

</script>

</body>

</html>

Overview

We begin our analysis, as we often do, with the script document body. The body element has one child, a script element. The body script element contains four calls for the ColoredText( ) function, which sits in a separate script element in the document head.
(1,4) The first and fourth ColoredText( ) calls will generate strings whose characters are randomly colored with the color values of the defClrsArray array.
(2) The second ColoredText( ) call will generate a string whose characters are alternately colored red and orange.
(3) The third ColoredText( ) call will generate a string whose characters are periodically (i.e., in a repeated cycle) colored with different shades of green.

Otherwise, the script document body has no real structure to speak of. The ColoredText( ) calls are flanked by document.write( ) commands whose parameters contain some perfunctory markup, all of which ultimately serves a presentational purpose. Is it worth it to separate the HTML and JavaScript in this document? Not really, IMO - I'm not sure it's even worth it to replace the center and font elements surrounding the fourth ColoredText( ) call with a style rule set. However, in the "Setting heterocolor by identifier" section below, we'll see that all of the script's JavaScript can easily be 'modularized' (isolated) for application to other documents.

Random heterocolor

In this section, we'll deconstruct what happens when the browser hits the first ColoredText( ) call:

ColoredText("This is a text sample written using the function ColoredText");

This line triggers the ColoredText( ) function and passes thereto the string This is a text sample written using the function ColoredText.

function ColoredText( ) {
var argLen = ColoredText.arguments.length;

The length (size) of the arguments[ ] object (i.e., the number of ColoredText( ) arguments) - 1 in this case - is assigned to the variable argLen.

Comments
• Every JavaScript function has a local arguments[ ] object for accessing/referencing the arguments passed to that function. The individual arguments of the arguments[ ] object are referenced ordinally à la a client-side document collection: arguments[0] is the first argument, arguments[1] is the second argument, etc.; however, the arguments[ ] object is technically not an array because the properties and methods of the core JavaScript Array object do not apply to it.
• The arguments[ ] object and the composite arguments.length property were once properties of the core JavaScript Function object, but these 'relationships' were deprecated by JavaScript 1.4; consequently, in the ColoredText( ) function, neither arguments.length, arguments[0], nor arguments[colorCode + 1] should be prefaced with a ColoredText reference, e.g., the first ColoredText( ) statement should be recast as:
var argLen = arguments.length;
• Contra Script Tips #81-83, the This is a text sample written using the function ColoredText string is indeed a ColoredText( ) argument; per the first comment above, it's arguments[0].

if (argLen == 0) { argLen = 1; }

None of the ColoredText( ) calls in the document body has no arguments; this conditional never comes into play and can be removed.

var text = arguments[0];
var textLen = arguments[0].length;

The arguments[0] string is assigned to the variable text; the length of the arguments[0] string, 60, is assigned to the variable textLen.

var defClrsArray = new Array("red", "purple", "cyan", "green", "blue", "magenta");
/* FYI: the W3C uses the color keywords aqua and fuchsia for the colors cyan (#00ffff) and magenta (#ff00ff), respectively. IMO, cyan is a nice background color but an awful text color, and should not have been included. */

An array of six color keyword strings is created and assigned to the variable defClrsArray.

for (i = 0; i < textLen; i++) {

A 60-iteration for loop will run through and color the arguments[0] string characters.

charColor = text.charAt(i);

For the for loop's first iteration, text.charAt(0) returns T, which is assigned to the variable charColor.

if (argLen == 1) {
colorCode = Math.floor(Math.random( ) * defClrsArray.length);

The if condition returns true. The right side of the subsequent statement generates a random integer in the range 0 to 5, inclusive, which is assigned to the variable colorCode. Here's what's going on:
(1) Math.random( ) returns a random number between 0 and 1, and running many digits past the decimal point (contra Script Tip #82, it does not generate a random number between 000 and 999).
(2) Multiplying the Math.random( ) return by defClrsArray.length, 6, gives a random number between 0 and 6, and still running many digits past the decimal point.
(3) The Math.random( ) * defClrsArray.length return is rounded down by Math.floor( ) to the 0-5 integer range.
The colorCode range matches the range of defClrsArray index numbers, bringing us to...

tempStr = charColor.fontcolor(defClrsArray[colorCode]); }

We plug colorCode into the square brackets of a defClrsArray[ ] reference; the resulting defClrsArray[colorCode] expression evaluates to a random defClrsArray color value, which is applied to charColor by the fontcolor( ) method to give a colored character that is assigned to the variable tempStr. For example, if colorCode is 5, then defClrsArray[colorCode] evaluates to magenta and charColor=T is thus converted to tempStr=T.

The browser skips over the else block and moves to...

document.write(tempStr); }

The colored tempStr character (T, T, whatever) is written to the page, concluding the first loop iteration. And so it goes: the loop's subsequent iterations randomly color and then print the rest of the arguments[0] string characters.

The preceding discussion also applies to the fourth ColoredText( ) call, for which argLen is also 1.

Periodic heterocolor

In this section, let's look at what happens when the browser hits the third ColoredText( ) call:

ColoredText("Another sample with shades of green", "#006000", "#007000", "#008000", "#009000", "#00a000", "#00b000");

This code triggers the ColoredText( ) function and passes thereto a set of seven arguments.

function ColoredText( ) {
var argLen = arguments.length;
var text = arguments[0];
var textLen = arguments[0].length;
var defClrsArray = new Array("red", "purple", "cyan", "green", "blue", "magenta");
for (i = 0; i < textLen; i++) {
charColor = text.charAt(i);
if (argLen == 1) {

In order:
(1) arguments.length, 7, is assigned to argLen.
(2) arguments[0], the Another sample with shades of green text string, is assigned to text.
(3) arguments[0].length, 35, is assigned to textLen.
(4) The defClrsArray array is again created, although we won't be using it this time.
(5) A 35-iteration for loop kicks off.
(6) text.charAt(0), A, is assigned to charColor in the loop's first iteration.
(7) The (argLen == 1) if condition returns false, so the browser moves on to...

else {
colorCode = i % (argLen - 1);

As the loop proceeds, the right side of the above statement cyclically generates the numbers 0, 1, 2, 3, 4, and 5, which individually are assigned to colorCode:
• For i = 0, 6, 12, 18, 24, 30: i % 6 = 0.
• For i = 1, 7, 13, 19, 25, 31: i % 6 = 1.
• For i = 2, 8, 14, 20, 26, 32: i % 6 = 2; etc.
(We previously discussed the % arithmetic operator in Blog Entry #36. Contra Script Tip #83, 6 % 5 does not equal 1.2 and does not return 2; rather, 6 % 5 equals and returns 1.)

tempStr = charColor.fontcolor(arguments[colorCode + 1]); }
document.write(tempStr); }

The 0-5 colorCode range is incremented so that it matches the range of the index numbers of the ColoredText( ) arguments specifying shades of green (arguments[1] through arguments[6]); otherwise, the first line above is analogous to the fontcolor( ) command of the previous section. For the loop's first iteration, colorCode is 0 and arguments[1] evaluates to the color #006000, which is applied to charColor to give A, which is in turn assigned to tempStr, which is then written to the page.

For the loop's second iteration, text.charAt(1), n, is given a #007000 color (arguments[2]); for the third iteration, text.charAt(2), o, is given a #008000 color (arguments[3]); and so on. The sequence of green shades begins again with the loop's seventh iteration, in which text.charAt(6), r, is given the #006000 color (arguments[1]). In total, the loop colors the arguments[0] string characters with the arguments[1]-arguments[6] color cycle not quite six times.

For the second ColoredText( ) call, the ColoredText( ) function similarly applies a arguments[1]-arguments[2] color cycle to the arguments[0] string; a detailed deconstruction of this case is left to you.

To return or not to return

On my computer and regardless of browser, the ColoredText( ) function is somehow able to direct its output to specific points on the page without a return statement, e.g., the Another sample with shades of green string is in practice rendered as an h1 element. Before the fact, one might think that the colored arguments[0] strings would be written one after the other at the beginning of the document body, without any markup, if they are not returned, and maybe that does happen with some browsers. If need be, here's how you can ensure that the outputted strings are sent to their intended destinations:

(1) First, nest the ColoredText( ) calls in document.write( ) commands, e.g.,

document.write(ColoredText("Try refreshing the page a couple of times!"));

For each call, we'll want to return a completed string and not just one character; towards this end:

(2) Begin the ColoredText( ) function with:

function ColoredText( ) {
var newString = "";

(3) Conclude the if and else blocks with newString += tempStr statements, e.g.,

else {
colorCode = i % (argLen - 1);
tempStr = charColor.fontcolor(arguments[colorCode + 1]);
newString += tempStr; }

(4) Finally, outside of the for loop, conclude the ColoredText( ) function with:

return newString; }

Steps (2)-(4) utilize a "start with an empty string, and build the new string character by character" methodology that we previously encountered in the multiple search engine script of Script Tips #42-44.

It's been a while since we've used the += shorthand assignment operator; Mozilla defines it on this page if you could use a refresher thereon.

Setting heterocolor by identifier

This topic deserves its own entry and we'll get to it next time.

reptile7

Comments: Post a Comment

<< Home

Powered by Blogger

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