reptile7's JavaScript blog
Sunday, August 01, 2010
Let's Scroll
Blog Entry #186

In today's post, we will check over the scrolling text script of HTML Goodies' "So, You Want A JavaScript Ticker Tape, Huh?" tutorial.

We previously went through a scrolling text script in HTML Goodies' JavaScript Script Tips #35-37, which were covered in Blog Entry #65. (In Script Tips #35-36 the script writes its scroll to the browser window's status bar whereas in Script Tip #37 the script loads its scroll into a text box, but these scripts are identical vis-à-vis creating the scroll.) The Script Tips #35-37 script and the "So, You Want A JavaScript Ticker Tape, Huh?" script have the same effect - in both cases, a text string preceded by a multispace 'buffer' scrolls from right to left in a containing field - but somewhat different modes of operation.

In brief, the Script Tips #35-37 script
(a) copies the scroll string's leftmost character and pastes it onto the right end of the scroll string,
(b) cuts the scroll string's leftmost character, and then
(c) shifts all of the scroll string's characters one position to the left;
(d) do this over and over and you've got a scroll.
As regards this sequence of operations, the "So, You Want A JavaScript Ticker Tape, Huh?" script omits step (a) and carries out steps (b-d); when the scroll string has been whittled down to its last character - when it appears to have been (almost) pushed beyond the left edge of its field - the script resets itself via resurrecting the original scroll string.

Most of the "So, You Want A JavaScript Ticker Tape, Huh?" script is posted on this page; the script's ticker( ) function trigger is detailed in the tutorial's "Activating the Script" section. Joe provides a functioning demo for the script at the top of the tutorial.

Joe's exhortations to the contrary notwithstanding, the "So, You Want A JavaScript Ticker Tape, Huh?" script can be 'messed with' quite a bit, as we'll see later.


Before we get started:
You'll notice on the tickertp.txt page that either Joe or one of the script's authors has wrapped the script in an xmp element towards the end of preserving the script's whitespace formatting. I trust y'all know that the xmp element was obsoleted long ago, and that you should now use the pre element to do this sort of thing.

Setting the stage: HTML and global variables

As in Script Tip #37, the "So, You Want A JavaScript Ticker Tape, Huh?" script displays its scroll in a text box. The box and its form container are coded by a document.write( ) command in the script's second ticker( ) function:

document.write("<form name='tickertapeform'><input name='scroll' size='35'></form>");

Alternatively and preferably, the tickertapeform form and its scroll box can be written as normal (non-script) HTML as long as the form is placed before the main script element in the source:

<form name="tickertapeform" action="">
<input type="text" name="scroll" size="35">
<script type="text/javascript">
<!-- Ticker Tape in JavaScript .. Heavily Modified by Bill Welliver

Before the scrolling action gets under way, the script declares the following global variables:
var tickertapeform;
var tt_speed = 350;
var tt_len = 35;
var tt_space = " "; // 100 spaces
var tt_tid = 0;
var tt_message = ".";
var tt_c = -tt_len;
• A tickertapeform variable is declared but not initialized; this variable does not appear subsequently in the script and its declaration can be removed.

tt_speed will represent the scroll's 'refreshment rate'; more specifically, the scroll will be updated every tt_speed milliseconds. Although initially set to 350, tt_speed doesn't need to be initialized at this point as we'll be (re)setting it in a bit.

tt_len represents the size of the scroll's field, i.e., of the scroll box; you might prefer to write this declaration as:
var tt_len = document.tickertapeform.scroll.size;
/* Really old browsers (e.g., Netscape 4.x) will not support the DOM size property, but that's their problem. */

• The aforementioned multispace buffer that precedes the scroll's text string will be extracted from the 100 spaces to which tt_space is set. I myself would have used a for loop to define tt_space:
var tt_space = "";
for (i = 0; i < 100; i++) { tt_space += " "; }
/* Or, given that 100 spaces is clearly overkill and that the scroll size is 35: */
for (i = 0; i < tt_len; i++) { tt_space += " "; }

tt_tid could (presently does not) serve as a numeric identifier for stopping the scroll - we'll have more to say about this when we discuss the script's tt_cleartid( ) function.

tt_message will represent the scroll's text string. Although initially set to . (a period), tt_message doesn't need to be initialized at this point as we'll be (re)setting it in a bit.

• A counter variable of sorts, tt_c plays a central role in determining the scroll's display - we'll have more to say about it when we discuss the script's move( ) function.


Let's get scrolling, shall we? The script is set in motion by a call to a ticker( ) function. Joe places this call in a separate script element

<script type="text/javascript">

following the script's main script element; equivalently, the ticker( ) function call could be placed at the end of the main script element or triggered by an onload event handler in the body element start-tag. "THE SCRIPT GOES HERE", the ticker( ) function call parameter, will be the scroll's text string.

You'll notice I said "a" ticker( ) function and not "the" ticker( ) function: that's because there are actually two ticker( ) functions in the main script element, something Joe strangely does not comment on.
function ticker(m, l, s) {
tt_message = m;
tt_len = l;
tt_speed = s;
document.write("<form name='tickertapeform'><input name='scroll' size='");
document.write("' value=''></form>");
tt_start(document.tickertapeform); }

function ticker(m) {
tt_message = m;
tt_len = 35;
tt_speed = 250;
document.write("<form name='tickertapeform'><input name='scroll' size='35'></form>");
tt_start(document.tickertapeform); }
As shown above, the first ticker( ) function expects to be passed three parameters whereas the second ticker( ) function expects only one parameter. In line with our one-parameter ticker( ) function call, the second ticker( ) function is the one that we want, and is the one that is called in practice by virtue of it appearing later in the source. The first ticker( ) function can therefore be thrown out, although changing the ticker( ) function call to ticker("THE SCRIPT GOES HERE", 35, 250); would allow you to route the script through the first ticker( ) function and throw out the second ticker( ) function if you'd rather do that.

In the second ticker( ) function:
(1-3) THE SCRIPT GOES HERE, 35, and 250 are assigned to tt_message, tt_len, and tt_speed, respectively.
(4) Next, the scroll text box and its form container are written to the page - this line should be removed if the form is written as normal HTML as described earlier.
(5) The last line calls the script's tt_start( ) function and passes thereto document.tickertapeform, a reference to the tickertapeform form.

So, let's move to the tt_start( ) function:
function tt_start(x) {
tt_f = x;
tt_tid = window.setTimeout("move( );", tt_speed); }
In the tt_start( ) function:
(1) document.tickertapeform is given a tt_f identifier.
(2) The script's move( ) function is called after a delay of 250 (tt_speed) milliseconds.


The move( ) function is where the scrolling action happens, and is the only one of the script's functions that is really necessary. Like the SBScroll( ) function of the Script Tips #35-37 script, the move( ) function sets and changes the composition of its scroll in a looplike, if more complex, manner. Here it is:
function move( ) {
cend = Math.min(tt_c + tt_len, tt_message.length);
if (tt_c < 0)
cstart = 0;
cstart = tt_c;
if (tt_c < 0)
tt_f.scroll.value = tt_space.substring(0, -tt_c) + tt_message.substring(cstart, cend);
tt_f.scroll.value = tt_message.substring(cstart, cend);
tt_c = tt_c + 1;
if (tt_c == tt_message.length)
tt_c = -tt_len;
tt_tid = window.setTimeout("move( );", tt_speed); }
Prior to calling the SBScroll( ) function, the Script Tips #35-37 script prepends 18 spaces to its text string to give a larger spaces+text string, which is subsequently manipulated by the SBScroll( ) function. In contrast, the "So, You Want A JavaScript Ticker Tape, Huh?" script keeps its tt_space 'space zone' and tt_message 'text zone' separate, and the move( ) function creates its scroll by acting on these zones separately - this is ultimately why move( ) is more complicated than it needs to be.

The space zone and text zone characters that make up the move( ) scroll are directly or indirectly determined by tt_c, a secondary index that supplements the normal 0-to-stringName.length-1 indexing of a JavaScript string. The tt_c index traverses the entire length of the space and text zones; its value ranges from -35 for the first space character of the space zone to tt_message.length for the 'null character' that would follow the final character of the text zone.

As tt_c moves through the space zone,
(1) tt_space.substring(0, -tt_c) returns a decrementing number of spaces, and
(2) tt_message.substring(cstart, cend) returns an initially incrementing number of text characters, which
(a) maxes out at the total number of text characters if the text string's length is less than the size of the scroll field, but
(b) continues to increment, up to a maximum of 35, if the string's length exceeds the scroll size.
These two groups of characters are concatenated to give the scroll. At any given time, no more than 35 scroll characters appear in the scroll field (even if you're using a sans-serif font, which can place more than 35 characters in a size="35" box).

As tt_c moves through the text zone, the scroll is simply given by tt_message.substring(cstart, cend), which, depending on the text string's length, returns 35 or fewer text characters and eventually or immediately shrinks to a single (the last tt_message) character, as detailed below.

Left and right boundaries for the range of the scroll's text string that is displayed at a given time are respectively set by cstart and cend variables. cstart is initialized to 0 and remains at 0 (i.e., is anchored to the first tt_message character) as tt_c moves through the space zone; cstart is set to tt_c and increments along with tt_c as tt_c moves through the text zone. For all tt_c values, cend is set by the following statement:

cend = Math.min(tt_c + tt_len, tt_message.length);

This unintuitive command - not so easy to get a handle on - adds 35 (tt_len) to the tt_c index and then compares the resulting index to tt_message's length; in practical terms:
(a) if tt_c + tt_len is less than tt_message.length, then the scroll value (tt_f.scroll.value) will end ('cend') somewhere in the interior of tt_message and will span the entire scroll size, i.e., there are more characters to the right that have yet to scroll into view, whereas
(b) if tt_message.length is less than tt_c + tt_len, then the scroll value will cend with tt_message's final character and will not span the entire scroll size, i.e., it'll be followed by empty space, as the right end of tt_message is now to the left of the right edge of the scroll field.

Now, to really see what's going on in the move( ) function, we need a test tt_message string; we could use Joe's THE SCRIPT GOES HERE dummy text for this purpose, but a string whose length exceeds the size of the scroll field would be a better choice. Accordingly, we will in the discussion below apply move( ) to The rain in Spain falls mainly on the plain..., for which tt_c will undergo a cycle of 82 values - -35 to 46, inclusive - over 81 move( ) 'iterations'. tt_c's value maps to the space zone for the first 35 move( ) iterations and to the text zone for the remaining move( ) iterations.

In the 1st move( ) iteration, tt_c begins at -35 (-tt_len), cstart is 0, and cend is 0; consequently, 35 tt_space spaces + 0 tt_message characters are written to the scroll field:

tt_c is incremented to -34 and move( ) is re-called after a 250-ms delay.

In the 10th move( ) iteration, tt_c begins at -26, cstart is 0, and cend is 9; 26 tt_space spaces + the first 9 tt_message characters are written to the scroll field:

tt_c is incremented to -25 and move( ) is re-called after a 250-ms delay.

In the 36th move( ) iteration, tt_c begins at 0, cstart is 0 for the last time in the cycle, and cend is 35. We are now in the text zone and move( )'s else clauses are operative. The first 35 tt_message characters are written to the scroll field:

tt_c is incremented to 1 and move( ) is re-called after a 250-ms delay.

In the 47th move( ) iteration, tt_c begins at 11, cstart is 11, and cend is 46 (tt_message.length), where it will stay for the rest of the cycle. The last 35 tt_message characters are written to the scroll field:

tt_c is incremented to 12 and move( ) is re-called after a 250-ms delay.

In the 72nd move( ) iteration, tt_c begins at 36, cstart is 36, and cend is 46. The last 10 tt_message characters are written to the scroll field:

tt_message's concluding ellipsis is followed by empty space, and not by space characters as would be so for the Script Tips #35-37 script.
tt_c is incremented to 37 and move( ) is re-called after a 250-ms delay.

In the 81st and last move( ) iteration of the cycle, tt_c begins at 45, cstart is 45, and cend is 46. The last tt_message character is written to the scroll field:

tt_c is incremented to 46 and now equals tt_message.length, so it is reset to -35 (-tt_len) by move( )'s third if statement; move( ) is re-called after a 250-ms delay to begin the next cycle.

That's how the script works as it appears on the tickertp.txt page. In the following entry, we'll first discuss how to stop (and restart) the scroll and then see if we can't clean the script up by getting rid of its unnecessary code.


Comments: Post a Comment

<< Home

Powered by Blogger

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