Monday, September 29, 2014
Planning a Color Trip
Blog Entry #336
We return now to our discussion of the Text Fader 1.3 script and its various functions. Today's post will be largely devoted to the fadeText( ) function, which carries out a set of foundational calculations in support of the script's fading operations. Its name notwithstanding, the fadeText( ) function doesn't actually fade the movie strings - the changeColor( ) function does that.
fadeText( ) parameterization
In the previous post we set the script functions in motion by calling the layout( ) function and then moved the fadeMe01 div to the center of the viewport via the getMid( ) and moveLayer( ) functions. In the layout( ) function the
moveLayer("fadeMe01", midY - 50, midX - 200);
call is followed by four calls to the fadeText( ) function, which are spread out timewise by window.setTimeout( ) commands.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);
window.setTimeout("fadeText('fadeMe01', '<span class=\"content\"><b>Teg WoRKz</b> Interactive</span><div class=\"small\">proudly presents</div>', 'CCCCCC', '000000', 10, 4);", 8000);
window.setTimeout("fadeText('fadeMe01', '<div class=\"small\">A</div><span class=\"content\"><b>Teg WoRKz</b> Production</span>', '000000', 'CCCCFF', 10, 2);", 12000);
window.setTimeout("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);
N.B. The quote formatting of the delayed fadeText( ) calls can be simplified by using the func, delay setTimeout( ) syntax, e.g.:
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);
Each fadeText( ) call passes six arguments to the fadeText( ) function.
function fadeText(obj, str, rgb1, rgb2, speed, step) { ... }
(0) arguments[0] is the id of the div whose text will be faded, and is given an obj identifier.
(1) arguments[1] is a text+HTML string that will be loaded into the obj div, and is given an str identifier.
(2) arguments[2] is the str text's starting color in the form of a #-less six-digit RRGGBB value, and is given an rgb1 identifier.
(3) arguments[3] is the str text's ending color in the form of a #-less six-digit RRGGBB value, and is given an rgb2 identifier.
(4) arguments[4] will serve as the setTimeout( ) delay for a recursive changeColor( ) call, and is given a speed identifier.
(5) arguments[5] controls the gradualness of the rgb1 → rgb2 transition, and is given a step identifier.
Having gone through this, I should note that the fadeText( ) function does not in fact act on the obj, str, and speed arguments but merely passes them on to the changeColor( ) function.
More CSS
Each of the above str strings contains a span with a class='content' identifier and a div with a class='small' identifier; these elements are styled with:
.content { font: 16pt Verdana, Arial, Helvetica; width: 400px; text-align: center; }
.small { font: 6pt Verdana, Arial, Helvetica; width: 400px; text-align: center; }
The width and text-align properties ordinarily do not apply to span elements - we can make them apply if we give the spans an inline-block display although there's no burning reason to do so - the
.content
rule's width:400px;
declaration can be thrown out and its text-align:center;
declaration can be applied to the fadeMe01 div.#fadeMe01 { position: absolute; text-align: center; width: 410px; }
.content { font: 16pt Verdana, Arial, Helvetica; }
Also:
• Link underlines are subtracted via an
a { text-decoration:none; }
rule.• Oddly, b elements are styled with a
b { font-weight:bold; }
rule. Are there any situations in which <b></b>
and font-weight:bold;
give different renderings? Maybe, I don't know - I suppose there's no harm in keeping the rule but I'd get rid of it.Slice and decimalize
The fadeText( ) body initially declares an r1/g1/b1/r2/g2/b2 set of variables.
var r1, g1, b1, r2, g2, b2;
Next, fadeText( ) splits the rgb1 and rgb2 colors into their RR, GG, and BB components, which are decimalized via an external hexToDec( ) function; the decimal R/G/B values are assigned to the r1-b2 variables.
for (cnt = 1; cnt <= 2; cnt++) {
eval("r" + cnt + " = hexToDec(rgb" + cnt + ".slice(0, 2));");
eval("g" + cnt + " = hexToDec(rgb" + cnt + ".slice(2, 4));");
eval("b" + cnt + " = hexToDec(rgb" + cnt + ".slice(4, 6));"); }
...
function hexToDec(hex) {
var value = 0;
while (true) {
if (convert[value] == hex) break;
value++; }
return value; }
We'll address the form of this code in a moment, but first, here's what's going on in more detail:
(1) As far as I am aware we've never worked with the slice( ) method of the String object before. In the present case slice( ) behaves just like substring( ), e.g.,
"Hello World".slice(0, 2);
extracts/returns the He section of Hello World, i.e., the section running from the 0th character up to but not including the 2nd character indexwise. Each rgb+cnt.slice( ) operation gives an RR|GG|BB value that is passed to the hexToDec( ) function and given a hex identifier.(2) The hexToDec( ) function runs through the convert database in order (convert[0], convert[1], ...) via a while loop until it finds a convert[value] value that equals hex, at which point a break statement terminates the loop and value is returned to the fadeText( ) function, which assigns the hexToDec( ) return to r|g|b+cnt.
The for loop with its cnt counter/index and the eval( ) function allow us to 'ordinalize' the code and thereby make it more compact than it otherwise would be. However, we really should be getting rid of the eval( ) calls. Is it that much more effort to write out six lines of code for the r1-b2 assignments? No, it isn't.
r1 = hexToDec(rgb1.slice(0, 2));
g1 = hexToDec(rgb1.slice(2, 4));
b1 = hexToDec(rgb1.slice(4, 6));
r2 = hexToDec(rgb2.slice(0, 2));
g2 = hexToDec(rgb2.slice(2, 4));
b2 = hexToDec(rgb2.slice(4, 6));
Moreover, the hexToDec( ) function is redundant in that the rgb1/rgb2 RR/GG/BB values can be decimalized via the parseInt( ) function (h/t commoner and the Java Goodies Color Gradient Text script).
r1 = parseInt(rgb1.slice(0, 2), 16);
g1 = parseInt(rgb1.slice(2, 4), 16);
b1 = parseInt(rgb1.slice(4, 6), 16);
r2 = parseInt(rgb2.slice(0, 2), 16);
g2 = parseInt(rgb2.slice(2, 4), 16);
b2 = parseInt(rgb2.slice(4, 6), 16);
Pre-fade increments
The Text Fader 1.3 script is designed to change the R/G/B components of the rgb1 color to their rgb2 counterparts
(a) in a proportional manner and
(b) as gradually as is practically possible.
Toward this end, the script looks at the r1 → r2, g1 → g2, and b1 → b2 'color distances' and then bases the changeColor( ) fading process on the largest of those distances.
When the for loop has finished executing, control passes to a with block whose first three statements copy the r1, g1, and b1 values to s2r, s2g, and s2b variables; in the changeColor( ) function s2r/s2g/s2b will hold the RR/GG/BB color values of the str string as it fades.
/* These variables are declared globally just before the hexToDec( ) function. */
var s1, s2, s3, s2r, s2g, s2b, smallest;
...
with (Math) {
s2r = r1;
s2g = g1;
s2b = b1; ... }
As you may know, Mozilla discommends the use of the with statement. Losing the with code will require us to laboriously prepend M, a, t, h, . to some up-and-coming abs( ) commands, but if you've come this far in the discussion you should be up to the task of doing that. ;-)
Moving on, the r1/g1/b1 → r2/g2/b2 color distances are calculated by:
s1 = Math.abs(r1 - r2);
s2 = Math.abs(g1 - g2);
s3 = Math.abs(b1 - b2);
The s1/s2/s3 values compose a ratio in proportion to which we will increment the rgb1 R/G/B components. At this point the s1-s3 numbers are not so useful. Let's change that, shall we?
An if...else if...else construct determines whether the s1, s2, or s3 distance is largest and assigns that distance to a smallest variable.
if (s1 > s2 && s1 > s3) { smallest = s1; }
else if (s2 > s1 && s2 > s3) { smallest = s2; }
else { smallest = s3; }
This code breaks down if two of the distances are equal and larger than the third distance, e.g., for a
"0000FF"
→ "FFFFFF"
(blue to white) transition, in which case the smaller distance is assigned to smallest: changing the > operators to >= solves this problem.Division of s1/s2/s3 by smallest converts them to a minimized while normalized-to-1 form.
s1 = (s1 == 0) ? 0 : s1 / smallest;
s2 = (s2 == 0) ? 0 : s2 / smallest;
s3 = (s3 == 0) ? 0 : s3 / smallest;
Testing if s1, s2, or s3 is 0 becomes necessary only if smallest itself is 0, which would happen if rgb1 and rgb2 were equal, which should not be the case.
The resulting s1/s2/s3 values are multiplied by step.
s1 *= step;
s2 *= step;
s3 *= step;
The step adjustments vary the incrementation, and therefore the speed, of an rgb1 → rgb2 transition. Consider the first two fadeText( ) calls: the second call's
"CCCCCC"
→ "000000"
fade is twice as fast as the first call's "000000"
→ "CCCCCC"
fade because the calls' step values are 4 and 2, respectively. If an s1/s2/s3 value needs to go down and not up for the rgb1 → rgb2 transition, it is converted to its additive inverse.
if (r1 > r2) { s1 = -s1; }
if (g1 > g2) { s2 = -s2; }
if (b1 > b2) { s3 = -s3; }
We're almost ready to call the changeColor( ) function. The pre-fade increment data for the first fadeText( ) call's
"000000"
→ "CCCCCC"
transition is:r1 = g1 = b1 = 0
r2 = g2 = b2 = 204
s2r = s2g = s2b = 0
s1 = s2 = s3 = 2 (204 → 1 → 2)
smallest = 204
We'll apply this data (well, some of it) to the str string in the following entry.
Actually, reptile7's JavaScript blog is powered by Café La Llave. ;-)