Rainy Day Fun with the HTML DOM

All HTML and JavaScript code in this article is copyright 2012 by Jim Lawless under the MIT/X11 source code license. See: http://www.mailsend-online.com/license2012.php

I like to tinker with JavaScript and the HTML DOM. Tonight, I decided that I wanted to process a body of text in a DIV tag applying style transformations to each word in the DIV. I knew I would build several variations, so the first thing I did was to construct a skeleton HTML document with a text fragment taken from Abraham Lincoln’s Gettysburg Address. ( I mean no disrespect to the body of speech that I used … I just needed a common body of text… )

The skeletal HTML document looks like this:

<html><head><title>Rainy day fun with the HTML DOM</title></head>
<body onload="loader()">
<script type="text/javascript">
   function loader() {
   }
</script>
<div id="main">
Four score and seven years ago our fathers brought forth, upon this continent, a new nation, conceived in liberty, and dedicated to the proposition that "all men are created equal"
<p>
Now we are engaged in a great civil war, testing whether that nation, or any nation so conceived, and so dedicated, can long endure. We are met on a great battle field of that war. We have come to dedicate a portion of it, as a final resting place for those who died here, that the nation might live. This we may, in all propriety do. But, in a larger sense, we can not dedicate—we can not consecrate—we can not hallow, this ground—The brave men, living and dead, who struggled here, have hallowed it, far above our poor power to add or detract. The world will little note, nor long remember what we say here; while it can never forget what they did here.
</div>
</body></html>

Note that I’ve named the DIV “main” and I have created a JavaScript function named loader() that will be executed once the page has rendered.

Throughout the rest of this post, I will only be posting the JavaScript fragments that I’ll be replacing in the SCRIPT area.

The first effect I tried to apply was to convert the color of some words to green and the following word’s color to red. In order to separate out the words, I grabbed the value of the innerHTML attribute from the DIV named
“main”. Then, I applied a regular expression that would retrieve tokens consisting of runs of non-whitespace characters with runs of whitespace characters appended.

      s=document.getElementById("main").innerHTML.toString();
      ar=s.match(/[^\s]+\s+/g);

The code then iterates over the array, encasing each token ( if not a paragraph tag ) inside FONT tags that specify alternating color attributes. Please note that I love to use FONT tags just to surround arbitrary groups of text in HTML documents so that I can reference a style attribute for that group of text … I strive to avoid using any formal FONT tag attributes.

The complete block of JavaScript looks like this:

   function loader() {
      var ar,s,i,htm,toggle=false;
      s=document.getElementById("main").innerHTML.toString();
      ar=s.match(/[^\s]+\s+/g);
      htm="";
      for(i=0;i<ar.length;i++) {
         s=ar[i];
         if(s=="<p>") {
            htm+=s;
         }
         else {
            toggle=!toggle;
            color="green";
            if(toggle) {
               color="red";
            }
             htm+="<font style=\"color:" + color + ";\">" +
                  s + "</font>";
         }
      }
      //alert(htm);
      document.getElementById("main").innerHTML=htm;
   }

Note that there’s a commented-out call to alert() in the code right after I concatenate all of these FONT-shrouded tokens together again. If you remove the comment characters, the alert will display a fragment of the new HTML block. It should look something like this:

When we assign that newly-formed HTML string back to the “main” DIV’s innerHTML attribute, the display then ends up looking similar to the following:

I was able to change colors of words alternately. Let’s now try to change more than just the color attributes of each token’s style property. Let’s change the font-family and font-size settings.

This time, when building the replacement HTML, I assign an ID to each FONT-encased token. Please consider the following JavaScript fragment:

   var ele;

   var colors=["red","orange","green","blue","violet","black"];
   var faces=["Courier New","Times New Roman", "Arial", "Trebuchet", "Comic Sans MS" ];
   var sizes=[4,14,20,30,40];

   function randomEntry(x) {
      var pos=parseInt(Math.random()*x.length);
      return x[pos];
   }

   function loader() {
      var ar,s,i,htm;
      s=document.getElementById("main").innerHTML.toString();
      ar=s.match(/[^\s]+\s+/g);
      htm="";
      for(i=0;i<ar.length;i++) {
         s=ar[i];
         if(s=="<p>") {
            htm+=s;
         }
         else {
             htm+="<font id=\"z" + i + "\">" +
                  s + "</font>";
         }
      }
      //alert(htm);
      document.getElementById("main").innerHTML=htm;
         // build an array of all of these elements encased
         // in font tags.
      ele=document.getElementById("main").getElementsByTagName("font");
      for(i=0;i<ele.length;i++) {
         ele[i].style.fontFamily=randomEntry(faces);
         ele[i].style.fontSize=randomEntry(sizes);
         ele[i].style.color=randomEntry(colors);
      }
   }

If you uncomment the alert() call in the code above, you’ll see something that looks like the following:

Note that each element has an ID beginning with the letter “z” followed by an incremental number. To create an array of these elements as HTML DOM nodes, I issued the following line of code:

      ele=document.getElementById("main").getElementsByTagName("font");

Which then retrieves a list of all FONT elements within the DIV named “main”.

After obtaining this list, I alter each element’s color, size, and font display characteristics, applying random values. If you reload the page several times, you’ll likely see interesting combinations that would look similar to:

I would like to now apply some sort of animation effect to the body of text, but changing the font-family and font-size attributes of each element at a high-frequency just makes for a display that’s painful to look at. Instead, I changed the code so that once per second, the function everySecond() causes every FONT element to attain a new color style. The code is as follows:

   var ele;

   var colors=["red","orange","green","blue","violet","black"];
   var faces=["Courier New","Times New Roman", "Arial", "Trebuchet", "Comic Sans MS" ];
   var sizes=[4,14,20,30,40];

   function randomEntry(x) {
      var pos=parseInt(Math.random()*x.length);
      return x[pos];
   }

   function loader() {
      var ar,s,i,htm;
      s=document.getElementById("main").innerHTML.toString();
      ar=s.match(/[^\s]+\s+/g);
      htm="";
      for(i=0;i<ar.length;i++) {
         s=ar[i];
         if(s=="<p>") {
            htm+=s;
         }
         else {
             htm+="<font id=\"z" + i + "\">" +
                  s + "</font>";
         }
      }
      //alert(htm);
      document.getElementById("main").innerHTML=htm;
         // build an array of all of these elements encased
         // in font tags.
      ele=document.getElementById("main").getElementsByTagName("font");
      setInterval("everySecond()",1000);
   }
   function everySecond() {
      for(i=0;i<ele.length;i++) {
         ele[i].style.color=randomEntry(colors);
      }
   }

The output looks similar to the following:

…with colors that alternate once per second.

I then decided to increase the frequency of the changes, but in the next generation of the document, I would apply the visual transformations to the FONT elements one at a time when the special-effect function everyInterval() is invoked. During the execution of the everyInterval() function, the element’s font-family and color attributes are changed.

   var ele;

   var colors=["red","orange","green","blue","violet","black"];
   var faces=["Courier New","Times New Roman", "Arial", "Trebuchet", "Comic Sans MS" ];
   var sizes=[4,14,20,30,40];

   function randomEntry(x) {
      var pos=parseInt(Math.random()*x.length);
      return x[pos];
   }

   function loader() {
      var ar,s,i,htm;
      s=document.getElementById("main").innerHTML.toString();
      ar=s.match(/[^\s]+\s+/g);
      htm="";
      for(i=0;i<ar.length;i++) {
         s=ar[i];
         if(s=="<p>") {
            htm+=s;
         }
         else {
             htm+="<font id=\"z" + i + "\">" +
                  s + "</font>";
         }
      }
      //alert(htm);
      document.getElementById("main").innerHTML=htm;
         // build an array of all of these elements encased
         // in font tags.
      ele=document.getElementById("main").getElementsByTagName("font");
      setInterval("everyInterval()",100);
   }

   var lastOne=0;

   function everyInterval() {
      ele[lastOne].style.fontFamily=randomEntry(faces);
      ele[lastOne].style.color=randomEntry(colors);
      lastOne++;
      if(lastOne==ele.length)
         lastOne=0;
   }

The effect is that each word, from right to left, will change color and font sequentially. The effect will look something like the following:

Note that eventually, the process starts over with the first word.

To see each one of these effects in action, please visit the following links:

http://www.mailsend-online.com/wp2/rainy2.htm

http://www.mailsend-online.com/wp2/rainy3.htm

http://www.mailsend-online.com/wp2/rainy4.htm

http://www.mailsend-online.com/wp2/rainy5.htm

Have fun with variations on the above themes!

Advertisements

About Jim Lawless

I've been programming computers for about 36 years ... 30 of that professionally. I've been a teacher, I've worked as a consultant, and have written articles here and there for publications like Dr. Dobbs Journal, The C/C++ Users Journal, Nuts and Volts, and others.
This entry was posted in Technology and tagged , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s