reptile7's JavaScript blog
Monday, October 27, 2014
 
Text Fader 1.4
Blog Entry #339

Excepting a small amount of unused code, we have now worked through the Java Goodies Text Fader 1.3 script in its entirety. Over the past four entries we have made various modifications to the script, namely, we've
(a) cross-browserized the layers|style|both-gated features of the getMid( ), moveLayer( ), and changeColor( ) functions,
(b) eliminated the script's base 16 ↔ base 10 interconversion code (the convert and hexbase arrays, the value index, etc.),
(c) removed inapplicable or unnecessary style declarations, and
(d) cleaned up the fadeText( ) and changeColor( ) function call syntax.
Are there any other changes we would like to make?

More extra stuff

We haven't said anything about the script's writeOn( ) function

function writeOn(obj, str) { if (layers) with (document[obj]) { document.open( ); document.write(str); document.close( ); } if (style) { eval(obj + ".innerHTML = str"); } }

and there's a reason for that: it's never called. The writeOn( ) function's raison d'être is to load the str string into the fadeMe01|fadeMe02 div, a task already handled by the changeColor( ) function. Throw it out.

What else? The style sheet in the document head includes a

.content1 { font: 16pt Verdana, Arial, Helvetica; width: 400px; text-align: center; }

rule but there are no class="content1" elements in the document. The .content1 rule is superfluous, and can be removed, because its font, width, and text-align settings are identical to those for the style sheet's .content rule.

Deparameterization

In parameterizing the recursive changeColor( ) function we effectively set its five parameters

function changeColor(obj, str, rgb1, speed, counter) { ... }

over and over again. In point of fact, we don't need to parameterize the changeColor( ) function at all.

(0-1) If we get the obj div and assign it to a global stringDiv variable in the fadeText( ) function, then we won't need to pass obj to the changeColor( ) function. The str string can subsequently be loaded into the stringDiv div in the fadeText( ) function.

var stringDiv; function fadeText(obj, str, rgb1, rgb2, step) { /* We'll lose the fadeText( ) speed parameter momentarily. */ stringDiv = document.getElementById(obj); stringDiv.innerHTML = str; ... }

(2) If we use the decimal tempR/tempG/tempB values and an rgb( ) function to style.color the stringDiv div and its link descendants in the changeColor( ) function

stringDiv.style.color = "rgb(" + tempR + ", " + tempG + ", " + tempB + ")";
var divLinks = stringDiv.getElementsByTagName("a");

for (i = 0; i < divLinks.length; i++) divLinks[i].style.color = "rgb(" + tempR + ", " + tempG + ", " + tempB + ")";

// In the fadeText( ) function, initialize tempR/tempG/tempB just before the changeColor( ) call:
tempR = s2r, tempG = s2g, tempB = s2b;
changeColor( );


then we won't need to pass rgb1 to the changeColor( ) function.

(3) For all twelve fadeText( ) calls, the value of the speed parameter is 10. If you're OK with this (I'm OK with it) then instead of feeding 10/speed to the fadeText( ) and changeColor( ) functions we can either set it in the top-level code

var speed = 10; function changeColor( ) { ... timerID = window.setTimeout(changeColor, speed); ... }

or hard-code the 10 in the recursive changeColor( ) call.

timerID = window.setTimeout(changeColor, 10);

(4) Lastly, the counter counter can be initialized to 0 in the top-level code and reset via an else counter = 0; clause that follows the if (counter < smallest) { ... } clause in the changeColor( ) function.

Separating structure and behavior

The Text Fader 1.3 movie works with a total of eight str strings (as noted in the previous post, two of the strings, "<span class='content'><b>TeXT FaDeR 1.3</b></span>" and "<span class='content'>THe ReWRiTTeN VeRSioN</span>", appear in more than one scene). I prefer to place the strings (their text+HTML) in separate divs in the document body rather than in the fadeText( ) calls.

<!-- Put these guys right after the fadeMe02 div. -->
<div id="string0" class="movieString"><span class="content"><b><a href="mailto:agent_teg@ThePentagon.com?subject=Text%20Fader%201.3">Teg WoRKz</a></b> Interactive</span><div class="small">proudly presents</div></div>
...
<div id="string7" class="movieString"><span class="content"><b>The</b> - <b>End</b>!!!</span></div>


The divs are equipped with class="movieString" attributes so that they can be zeroed out with a .movieString { display:none; } style rule. The divs have id strings that can be assigned to the fadeText( ) str parameter

function fadeText(obj, str, rgb1, rgb2, step) { ... }
...
fadeText("fadeMe01", "string0", "000000", "CCCCCC", 2);
window.setTimeout(function ( ) { fadeText("fadeMe01", "string1", "CCCCCC", "000000", 4); }, 8000);
...


in order to load the div content into the stringDiv div (vide supra) via a

stringDiv.innerHTML = document.getElementById(str).innerHTML;

statement.

Last-minute notes

• Remove the document type declaration at the beginning of the document so that older versions of IE can get the viewport dimensions with document.body.clientWidth and document.body.clientHeight.

• Most of the movie strings contain b elements, whose bolding action can be carried out by a font-weight:bold; style declaration if you're a stickler for separating structure and presentation.

/* Recast the .content style rule as: */
.content { font: bold 16pt Verdana, Arial, Helvetica; }
/* Use a separate rule for non-bolded spans: */
.content1 { font: 16pt Verdana, Arial, Helvetica; }


Moreover, it is now clear to me that the divs in those strings (e.g., <div class="small">proudly presents</div>) are not just style carriers but are also being used to cause line breaks, which rubs me the wrong way; in the next section's demo I've converted those divs to spans and inserted <br>s as appropriate.

• Keep the smallest = Math.round(smallest / step); operation in the fadeText( ) function - there's no point in resetting smallest over and over again in the changeColor( ) function.

• If you're going to keep the stopClock( ) function, then call it before calling the layout( ) function.

window.onload = function ( ) { stopClock( ); layout( ); }

Demo

A "Text Fader 1.3 : The re-written version" Google search turns up several pages that put the script into practice. These pages employ the original script code and consequently do not accommodate non-IE modern browsers. It evidently falls to us, then, to put forward a cross-browser demo.

Click the Lights, Camera, Action! button to view the Text Fader 1.3 movie.
The movie takes about a minute to run - it's over when you see
The - End!!!.


The movie takes place in an id="screenDiv" div. To position the fadeMe01/fadeMe02 divs in the screenDiv div it is necessary to give the latter a position:relative; styling.

Sunday, October 19, 2014
 
Fader Stills Show
Blog Entry #338

We continue today our deconstruction of the Java Goodies Text Fader 1.3 script. Having slogged through the script's fadeText( ) and changeColor( ) functions in the last two entries, we're ready to see how the first four fadeText( ) function calls play out from start to finish.

Recap

The first fadeText( ) call

fadeText("fadeMe01", "<span class='content'><b><a href='mailto:agent_teg@ThePentagon.com?subject=Text%20Fader%201.3'>Teg WoRKz</a></b> Interactive</span><div class='small'>proudly presents</div>", "000000", "CCCCCC", 10, 2);

• The step gradient is 2.
• The smallest color distance is 204.
• After division by smallest, multiplication by step, and sign-adjustment as necessary ("processing" hereafter), the s1/s2/s3 increments are all 2.
• The changeColor( ) loop runs for smallest = 102 iterations.
• The tempR/tempG/tempB color components all max out at 204.
• The changeColor( ) loop takes the str text color from rgb(0, 0, 0) (#000000) to rgb(204, 204, 204) (#CCCCCC).

Teg WoRKz Interactive
proudly presents


(Don't know 'bout you, but a 6pt font-size is too small for my taste.)

The second fadeText( ) call

window.setTimeout(function ( ) { fadeText("fadeMe01", "<span class='content'><b>Teg WoRKz</b> Interactive</span><div class='small'>proudly presents</div>", "CCCCCC", "000000", 10, 4); }, 8000);

• The step gradient is 4 ⇒ this fade'll be twice as fast as the first one.
• The smallest color distance is again 204.
• After processing, the s1/s2/s3 increments are all -4.
• The changeColor( ) loop runs for smallest = 51 iterations.
• The tempR/tempG/tempB components all bottom out at 0 and are unnecessarily reset to 0.
• The changeColor( ) loop takes the str text color from rgb(204, 204, 204) (#CCCCCC) to rgb(0, 0, 0) (#000000).



The third fadeText( ) call

window.setTimeout(function ( ) { fadeText("fadeMe01", "<div class='small'>A</div><span class='content'><b>Teg WoRKz</b> Production</span>", "000000", "CCCCFF", 10, 2); }, 12000);

• The step gradient is 2.
• The smallest color distance is 255, for a maximal b1b2 change.
• After processing, the s1 and s2 increments are 1.6 and the s3 increment is 2.
• The changeColor( ) loop runs for smallest = 128 iterations.
• The tempR and tempG components max out at 205 (Math.round(1.6 × smallest)); the tempB component maxes out at 256 (2 × smallest) and is adjusted to 255.
• The changeColor( ) loop takes the str text color from rgb(0, 0, 0) (#000000) to rgb(205, 205, 255) (#CDCDFF) - slightly off from the target, but close enough.

A
Teg WoRKz Production


The fourth fadeText( ) call

window.setTimeout(function ( ) { fadeText("fadeMe01", "<div class='small'>A</div><span class='content'><b><a href='mailto:agent_teg@ThePentagon.com?subject=Text%20Fader%201.3'>Teg WoRKz</a></b> Production</span>", "CCCCFF", "000000", 10, 4); }, 20000);

• The step gradient is 4.
• The smallest color distance is again 255.
• After processing, the s1 and s2 increments are -3.2 and the s3 increment is -4.
• The changeColor( ) loop runs for smallest = 64 iterations.
• The tempR and tempG components bottom out at -1 (Math.round(204 + (-3.2 × smallest))) and are adjusted to 0; the tempB component bottoms out at -1 (255 + (-4 × smallest)) and is adjusted to 0 as well.
• The changeColor( ) loop takes the str text color from rgb(204, 204, 255) (#CCCCFF) to rgb(0, 0, 0) (#000000).

(I don't need to show you another solid black rectangle, do I? Didn't think so.)

The rest of the movie

At this point we've gone through about a third of the layout( ) function whose call starts the Text Fader 1.3 movie. Let's keep going, shall we?

Recall that the fadeMe01 div was initially given a window.innerHeight ÷ 2 - 50 top offset. After the fourth fadeText( ) call, the fadeMe01 div is shifted upward by 50px and the fadeMe02 div is positioned 10px higher than the initial fadeMe01 div position.

window.setTimeout(function ( ) { moveLayer("fadeMe01", midY - 100, midX - 200); }, 24000);
window.setTimeout(function ( ) { moveLayer("fadeMe02", midY - 60, midX - 200); }, 24000);


The fadeMe01 div still holds the fourth fadeText( ) call's str string

A
Teg WoRKz Production


although you can't see it against the black background; the fadeMe02 div is empty.

The fadeMe01 div is subsequently charged with a TeXT FaDeR 1.3 string that (in practice) fades from black to #CDCDFF.

window.setTimeout(function ( ) { fadeText("fadeMe01", "<span class='content'><b>TeXT FaDeR 1.3</b></span>", "000000", "CCCCFF", 10, 4); }, 26000);

TeXT FaDeR 1.3

The fadeMe02 div is charged with a THe ReWRiTTeN VeRSioN string that fades from black to #9A9AFF.

window.setTimeout(function ( ) { fadeText("fadeMe02", "<span class='content'>THe ReWRiTTeN VeRSioN</span>", "000000", "9999FF", 10, 4); }, 32000);

THe ReWRiTTeN VeRSioN

The TeXT FaDeR 1.3 string in the fadeMe01 div is faded to red.

window.setTimeout(function ( ) { fadeText("fadeMe01", "<span class='content'><b>TeXT FaDeR 1.3</b></span>", "CCCCFF", "FF0000", 10, 4); }, 36000);

TeXT FaDeR 1.3

The THe ReWRiTTeN VeRSioN string in the fadeMe02 div is faded to #99FF33

window.setTimeout(function ( ) { fadeText("fadeMe02", "<span class='content'>THe ReWRiTTeN VeRSioN</span>", "9999FF", "99FF33", 10, 4); }, 40000);

THe ReWRiTTeN VeRSioN

and then to #CCCCCB

window.setTimeout(function ( ) { fadeText("fadeMe02", "<span class='content'>THe ReWRiTTeN VeRSioN</span>", "99FF33", "CCCCCC", 10, 4); }, 44000);

THe ReWRiTTeN VeRSioN

and then to black.

window.setTimeout(function ( ) { fadeText("fadeMe02", "<span class='content'>THe ReWRiTTeN VeRSioN</span>", "CCCCCC", "000000", 10, 4); }, 48000);

BTW, the #CCCCFF, #9999FF, and #CCCCCC colors are known as periwinkle, rich periwinkle, and gray80, respectively. The #99FF33 color doesn't have a name AFAIK.

Two more 'scenes' to go. The THe ReWRiTTeN VeRSioN string in the fadeMe02 div is replaced by a readme-type string that fades from black to gray80.

window.setTimeout(function ( ) { fadeText("fadeMe02", "<span class='small'>This script is provided as if without support or warranty of any kind. I will not be held liable by any damage that this script might cause. COPYRIGHT<sup>&copy;</sup> 1998. <a href='mailto:agent_teg@ThePentagon.com?subject=Text%20Fader%201.3'>Teg Workz</a></span><div class='small'>Open this page with a text editor to view the syntax command.</div>", "000000", "CCCCCC", 10, 4); }, 52000);

CSS note: The .small style rule features width and text-align settings that ordinarily do not apply to a span element. Alternatively and preferably, we can pre-format the entire readme string with a single <div class='small'></div> container and use a <br> to push the last sentence to a new line.

This script is provided as if without support or warranty of any kind. I will not be held liable by any damage that this script might cause. COPYRIGHT© 1998. Teg Workz
Open this page with a text editor to view the syntax command.


Finally, the TeXT FaDeR 1.3 string in the fadeMe01 div is replaced by a The - End!!! string that fades from black to red.

window.setTimeout(function ( ) { fadeText("fadeMe01", "<span class='content'><b>The</b> - <b>End</b>!!!</div>", "000000", "FF0000", 10, 4); }, 57500);

Note that the str string has a <span>/</div> tag mismatch - I'd make it a div vis-à-vis a span as it has no flanking content.

The - End!!!

We will conclude our Text Fader 1.3 script discussion with one last post in which we clean up the code some more and provide a demo.

Thursday, October 09, 2014
 
Δcolor/Δt
Blog Entry #337

Welcome back to our discourse on the Java Goodies Text Fader 1.3 script. Today we'll take on the script's changeColor( ) function, which
(1) loads the text+HTML str string into the fadeMe01 or fadeMe02 div and
(2) changes the str text's color from rgb1 to rgb2.

The changeColor( ) function is set up like a

for (var counter = 0; counter < smallest; counter++) { ...statements... }

loop in that it runs for smallest iterations according to a counter < smallest condition. The counter variable is initialized to 0 when changeColor( ) is called and is incremented by a counter++ expression near the end of the function. The smallest limit is set by a

smallest = Math.round(smallest / step);

command that divides the smallest color distance by the step gradient, round( )s the quotient, and assigns the resulting integer back to smallest. The smallest redefinition concludes the with block in the fadeText( ) function although you can move it to the beginning of the changeColor( ) function if you want to.

When the fadeText( ) with statement has finished executing, control passes to an if...else statement whose if clause triggers the changeColor( ) functionality. Non-IE modern browsers won't go through the both gate; of course, we would really prefer to not condition the changeColor( ) call at all.

if (both) { changeColor(obj, str, rgb1, speed, 0); }
else { document.write("Error: For some reason you tried viewing this page with a browser that doesn't [have] JavaScript/CSS block support."); }


The changeColor( ) call passes five arguments to the changeColor( ) function. The obj, str, rgb1, and speed arguments are the same ones we passed to the fadeText( ) function in the previous post; arguments[4], 0, is assigned to the counter counter.

The aforementioned counter < smallest condition gatekeeps the changeColor( ) body.

function changeColor(obj, str, rgb1, speed, counter) { if (counter < smallest) { ... } }

The changeColor( ) function is recursive: the counter++ incrementation is followed by a setTimeout( ) command that calls changeColor( ) after a 10-millisecond delay.

/* timerID is declared globally just before the stopClock( ) function. */
var timerID = null;
...
timerID = window.setTimeout("changeColor('" + obj + "', '" + str + "', '" + rgb1 + "', " + speed + ", " + counter + ")", speed);


Use of a function pointer for the first setTimeout( ) argument allows us to formulate the command as:

timerID = window.setTimeout(function ( ) { changeColor(obj, str, rgb1, speed, counter); }, speed);
/* A lot cleaner, huh? */


Stopping the clock, or not

If counter is less than smallest, the changeColor( ) function first calls a stopClock( ) function.

var timerRunning = false;

function stopClock( ) { if (timerRunning) window.clearTimeout(timerID); timerRunning = false; }

The preceding code was lifted verbatim from this Netscape example (OK, Netscape names the function stopclock( ), but otherwise...), which uses it to make sure a clock script's clock is stopped before setting it in motion.

The recursive changeColor( ) call is followed by a timerRunning = true; assignment. In the counter = 0 changeColor( ) iteration the stopClock( ) function doesn't do anything (OK, it resets timerRunning to false) but in each subsequent iteration stopClock( ) clears the timerID timeout. We shouldn't need to do this, should we? The Netscape example runs the stopclock( ) function only once, when the page loads, as a housekeeping measure. In the event, commenting out the stopClock( ) call
(4) does give rise to some jittery movie behavior with IE 4.5 and Netscape 4.61 but
(5) has no effect with IE 5.1.7
in the SheepShaver environment.

The str string and its starting color(s)

Next, the obj div's link/text colors are set to rgb1 and the str string is loaded into the obj div by either of two if statements that respectively cater(ed) to Netscape and IE.

if (layers) with (document[obj]) { document.open( ); document.linkColor = rgb1; document.fgColor = rgb1; document.write(str); document.close( ); } if (style) { eval(obj + ".document.linkColor = rgb1"); eval(obj + ".innerHTML = '<font color=' + rgb1 + '>' + str + '<\/font>'"); }

On the Netscape side, an absolutely positioned div is a layer and thus has a document property that provides access to the various methods and properties of the document object. The fadeMe01/fadeMe02 layers are empty and we can use layerObject.document commands to kit them out as we see fit.

On the IE side, the innerHTML command is straightforward enough but the eval(obj + ".document.linkColor = rgb1"); command for setting the color of unvisited hyperlinks initially threw me for a loop: I knew that obj could serve as an object reference for the fadeMe01|fadeMe02 div, but what's with the .document business? A for...in probe of obj (more specifically, of eval(obj) - obj itself is just a string)

var result = "";
for (var i in eval(obj)) result += "obj." + i + " = " + eval(obj)[i] + "\n";
window.alert(result);


revealed that, yes, the IE-interpreted obj object does in fact have an obj.document = [object document] property à la a Netscape layer - you learn something new every day.

In recasting the IE code for modern browsers, I found that

document.getElementById(obj).innerHTML = str;
document.getElementById(obj).style.color = "#" + rgb1;


would color nonlink text but not link text, which would render in white per the a:link { color:white; } style rule and then stay white and not fade; adding

var divLinks = document.getElementById(obj).getElementsByTagName("a");
for (i = 0; i < divLinks.length; i++) divLinks[i].style.color = "#" + rgb1;


solved this problem.

Increment management

With the str text color now rgb1, we're ready to start our rgb1rgb2 journey. Returning to the s1/s2/s3/s2r/s2g/s2b decimal data generated by the fadeText( ) function, we first increment s2r, s2g, and s2b by s1, s2, and s3, respectively.

s2r += s1;
s2g += s2;
s2b += s3;


As repositories for rgb1's decimal R/G/B components, the s2r/s2g/s2b values are initially integers. For some color transitions, however, one or more of the s1/s2/s3 values can be floating-point numbers, in which case the corresponding incremented s2r/s2g/s2b values will be floating-point numbers as well. The new s2r/s2g/s2b values are round( )ed (whether they need it or not) as they will shortly be mapped onto their hexadecimal counterparts via the convert database, which requires integer inputs and returns undefined if it doesn't get them.

tempR = Math.round(s2r);
tempG = Math.round(s2g);
tempB = Math.round(s2b);


For the purpose of further incrementation in subsequent changeColor( ) iterations, however, floating-point s2r/s2g/s2b values should stay just as they are - the s1/s2/s3 values are meant to take us from rgb1 to rgb2 in exactly smallest iterations, and we won't hit the rgb2 target if s2r/s2g/s2b non-integers are 'smoothed out' - so the round( ) returns are assigned to a separate set of tempR, tempG, and tempB variables.

Depending on
(a) the rgb2 value,
(b) the step value, and
(c) whether the r1/g1/b1r2/g2/b2 color distances are or are not evenly divisible by step,
it is possible for one or more of the tempR/tempG/tempB values to stray outside the 0-255 range at the end of a fading operation. If any of the tempR/tempG/tempB values hit 0 or go below 0, they are set to 0; if any of them hit 255 or go above 255, they are set to 255.

if (tempR <= 0) tempR = 0; /* <= can be replaced by < */
if (tempG <= 0) tempG = 0;
if (tempB <= 0) tempB = 0;
if (tempR >= 255) tempR = 255; /* >= can be replaced by > */
if (tempG >= 255) tempG = 255;
if (tempB >= 255) tempB = 255;


We're getting there. In preparation for the next changeColor( ) iteration, the tempR/tempG/tempB values are plugged into the convert array and the resulting two-digit hexadecimal number strings are concatenated to give a new six-digit RRGGBB value, to which rgb1 is set.

rgb1 = convert[tempR] + convert[tempG] + convert[tempB];

Is it necessary to hexadecimalize the tempR/tempG/tempB values? Nope. Upon adding a

tempR = s2r, tempG = s2g, tempB = s2b;

line to the end of the fadeText( ) with block, we can color the str text with the decimal tempR/tempG/tempB values via an rgb( ) function.

document.getElementById(obj).style.color = "rgb(" + tempR + ", " + tempG + ", " + tempB + ")";
var divLinks = document.getElementById(obj).getElementsByTagName("a");
for (i = 0; i < divLinks.length; i++) divLinks[i].style.color = "rgb(" + tempR + ", " + tempG + ", " + tempB + ")";


Upon resetting rgb1, the changeColor( ) function concludes by incrementing counter, calling itself, and toggling timerRunning to true as described earlier.

In the following entry, we'll recap vis-à-vis the first four fadeText( ) calls, go through the rest of the Text Fader 1.3 movie, refine the code a bit more, and maybe even roll out a demo.


Powered by Blogger

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