Section 5.1. Display Morphing


5.1. Display Morphing

Display, DOM, Graphics, GUI, Morph, Page, Paint, Reference, Rich

Figure 5-1. Display Morphing


5.1.1. Goal Story

Stuart is answering a question in an online quiz, with a countdown box showing how much time remains. The countdown label changes each second, and the color gradually shifts from green to red as the countdown proceeds.

5.1.2. Problem

How can you dynamically update display elements?

5.1.3. Forces

  • As the user's task and context changes, applications need to present different types of information.

  • As information the user is working on changes, information being displayed becomes stale.

  • Stale information is a big problem in conventional web apps. Because the information cannot change until it's out of date, you sometimes see disclaimers such as "May Be Out of Date" or instructions like "Click to Refresh."

  • Submitting and redrawing the entire page interrupts the user's flow.

5.1.4. Solution

Morph page elements by altering styles and values in the Document Object Model (DOM), such as text and color properties. The DOM represents the state of the web page at any time. When JavaScript manipulates the DOM, the browser notices the changes and immediately reflects them in the user interface. To morph a page element's display, you get a reference to it and change its properties. This allows you to change the display of any element on the pageheadings, div elements, images, and even the document object itself. Note: an online demo (http://ajaxify.com/run/display) illustrates the code concepts throughout this Solution and the code snippets loosely follow from the demo.

To further illustrate the DOM, consider the following piece of HTML:

   <div >     <img  src="/books/2/755/1/html/2/photo.jpg"/>     <div >       <input  name="width" type="text" size="20"/>       <input  name="height" type="text" size="20"/>     </div>   </div> 

Figure 5-2 shows the structure that arises when the browser transforms the HTML string into a DOM model. Since each node has attributes, we can represent the model in more detail, as shown in Figure 5-3. To learn more about the DOM, experiment with the tools mentioned in DOM Inspection (Chapter 18). You can point them at a web page to view the corresponding DOM model.

Figure 5-2. DOM structure


Figure 5-3. DOM structure with attributes


Each node has a number of standard attributes and operations. Those below let you inspect surrounding DOM context:


parentNode

The element's parent node.


childNodes[]

An array of all immediate child nodes.


getElementsByTagName("tagName")

An array of all child nodes of type tagName (e.g., H1 for all level-1 headings).

The structure can be manipulated as well as inspected. Following are the key manipulation methods available on all nodes (discussed further in Page Rearrangement):


appendChild(newChild)

Appends newChild.


insertBefore(newChild, oldChild)

Inserts newChild just before oldChild.


removeChild(oldChild)

Removes oldChild.

You can also inspect the node itself; useful properties include:


id

The node's ID.


nodeType

Usually 1 to denote a standard element. 2 represents a tag attribute and 3 represents a text node (explained later in this section).


tagName

The name of the tag (e.g., "h1").

For a more complete set of properties and operations, a good source is available at HowToCreate.co.uk (http://www.howtocreate.co.uk/tutorials/index.php?tut=0&part=28).

Before using any of these properties, the first thing you need to do is get hold of a node somewhere in the DOM. Here's how to grab a reference to an image node with an ID of "logo" buried anywhere inside the DOM:

   var logo = document.getElementById("logo"); 

getElementById( ) will recurse through the whole document to find the element with a given ID property. Since calls like this are extremely commonplace, a convenience function is used throughout the demos. The function name is just one character, $, which leads to a neater syntax like this (as explained in Chapter 2):

   var logo = $("logo"); 

Now that we have a reference to the image node, we can play around with its properties. To start with, we can change its src property, which will cause it to load a new image:

   logo.src = "Images/web.png"; 

We can also set the image's alt text, which will show up on text browsers, and as a tooltip on some browsers):

   logo.alt = "The World Wide Web" 

So far, we've altered a couple of image-specific properties. Each HTML element has its own set of properties that can be manipulated via DOM manipulation. There are references such as the w3schools web site (http://www.w3schools.com/htmldom/dom_reference.asp) that list the properties for each element.

Another common task is manipulating text, which in the DOM is actually represented by special text nodes. This is a little confusing as there's no corresponding HTML tag. Look at the following text, which seems to have some text freely roaming inside a <p> tag:

   <p>Oh no! It's <strong>Mr. T</strong>!</p> 

Text always resides inside. This is also a little confusing as there's no corresponding HTML tag; the text nodes are implicit. In the example above, what the DOM holds is actually a paragraph node <p> with three children: a text node, a strong node with a text node inside it, and another text node. It's represented in the DOM as follows:

   <p>       <textnode>Oh no! It's </textnode>       <strong><textnode>Mr. T</textnode></strong>       <textnode>!</textnode>   </p> 

Although the initial HTML is trivial, building up a message like this with DOM manipulation is somewhat complex:

   message.appendChild(document.createTextNode("Oh no! It's "));   var strong = document.createElement("strong");   strong.appendChild(document.createTextNode("Mr. T"));   message.appendChild(strong);   message.appendChild(document.createTextNode("!")); 

Even when text nodes aren't involved, directly manipulating the DOM can get quite ugly. A popular alternative is to use innerHTML, which lets you specify an HTML snippet. Thus, we can rewrite the code above by simply setting the innerHTML property:

   message.innerHTML = "Oh no! It's <strong>Mr. T</strong>!"; 

By setting the element's innerHTML property, we've effectively delegated the DOM manipulation to the web browser. It's much simpler and easier to understand than direct DOM manipulation and is supported by all modern browsers. However, use it with caution, because if you give it an invalid HTML string, you might end up with a subtle bug related to an unexpected DOM state. Also, there are some subtle portability issues, which mean that a particular HTML segment won't always produce quite the same DOM model. For instance, certain kinds of whitespace will be captured as a text node by Firefox, but are then ignored by IE (http://www.agavegroup.com/?p=32). So if you use innerHTML, be careful about subsequent DOM manipulations on and around that content.

On the whole, direct DOM manipulation is often more appropriate for complex operations. IE also offers an outerHTML, less commonly used, which will not only set the element's contents, but also overwrite the element itself. With outerHTML, it's as if the element is replaced by the contents of its outerHTML property.

If we're looking at changing the display, a particularly important aspect to consider is CSS style. CSS styles and classes are just regular properties and can be manipulated just like the others. Assume the stylesheet defines a CSS class called inYourFace. When we change the message's className property to inYourFace, its display will automatically update to reflect the inYourFace definition.

   [CSS]   .inYourFace {     padding: 10px;     background-color: #ff4444;     font-size: 250%;   }   [Javascript]   message.className = "inYourFace"; 

As explained the next section, changing appearance by switching classes is a good practice, but there are also times when the JavaScript needs to manipulate style directly via the style property present on all elements. style itself has a number of properties, as you would see in a stylesheet, but with JavaScript-ish camelCase (backgroundColor) like that shown below, as opposed to the CSS hyphenated style (background-color):

   message.style.padding= "10px";   message.style.backgroundColor = "#ff4444";   message.style.fontSize = "250%"; 

5.1.5. Decisions

5.1.5.1. Will you alter the display via classname or style?

For those morphings related to CSS properties, you have a choice between manipulation via style and className. As a general rule of thumb, use className when you can and use style for special situations. Using className follows the principle of unobtrusive JavaScript, because it clears away any mention of fonts, colors, and layout from the code. Thus, the code logic is clearer and the presentation details are encapsulated better inside the stylesheet.

So what are those special cases where style should be altered? Here are a few situations:


Style depends on some variable

For example, an HTML histogram, where the height of each element is calculated according to the value it represents.


Animation

Animations are a special case of the previous point, where styles usually vary according to elapsed time.


Multiple variables

Sometimes each style property is to be tied to a particular variable; e.g., font reflects age, color reflects keyboard focus, and so on. There would be too many combinations to hold each as a separate style. You could, however, hold each as a separate class, since an element can have more than one class (its class property can be a whitespace-separated list of class names).


Prototyping

When in creative-coding mode, setting the style directly is sometimes easier than messing around with a separate stylesheet. But don't forget to refactor later on!

5.1.5.2. What sort of properties will be used?

In modern browsers, the DOM is very powerful, so you can change just about anything you can see. The following are some of the properties that can be typically altered. Note that, as just mentioned, many of the CSS styles will usually be altered indirectly, via className.


Colorstyle.backgroundColor, style.fontColor

  • Change to a distinguishing color to highlight an entire image or controlfor example, to draw the user's attention or indicate that an item has been selected.

  • Change to a distinguishing color to highlight a range of text. This could be combined with a font color change to indicate that text has been selected.

  • Change to a symbolic color to denote some status change; e.g., "red" for stopped, and "green" for running.

  • Provide an animation effect by fading or brightening a control. This can draw attention more effectively than can a sudden change in the control itself.

  • Change color according to a variable; e.g., the brightness of a blog posting's header varies according to the number of times it's been viewed.


Background Imagestyle.backgroundImage

  • Change the image to indicate the status of an element; e.g., a control might be stopped or started, or source code might be OK, have warnings, or have errors.


Border Stylestyle.borderWidth, style.borderColor, style.borderColor

  • Highlight/Select an element to draw attention to it.

  • Indicate whether some text is editable or read-only.


Font StylestylefontSize, style.fontWeight, style.fontStyle

  • Change the size, weight, and/or slant of a font to highlight some text.


Inner/Outer HTMLstyle.innerHTML, style.outerHTML

  • Change some text content.

  • Change arbitrary HTML, possibly changing the nested HTML of an element as well.


Image Sourcesrc

  • Change an image object by modifying src to point to another image URL.

5.1.6. Real-World Examples

5.1.6.1. Ajax-S

Robert Nyman's Ajax-S (http://www.robertnyman.com/ajax-s/) is a slideshow managerthink "Powerpoint Lite"that morphs the slide content as you flick through the presentation (Figure 5-4).

Figure 5-4. Ajax-S


5.1.6.2. Digg Spy

Digg Spy (http://digg.com/spy) shows new stories and events such as user moderation as they happen (Figure 5-5). What's interesting from a Display Morphing perspective is the fade effect used to highlight each item as it appears.

Figure 5-5. Digg Spy


5.1.6.3. Ajax Spell Checker

The Ajax Spell Checker (http://www.broken-notebook.com/spell_checker/index.php) highlights any misspellings. It morphs the words into a red, underlined form that is familiar to any MS-Word user. A similar service is also offered by another Ajax App, Gmail (http://gmail.com).

5.1.7. Code Example: AjaxPatterns Countdown Demo

The example is a simple countdown demo (http://www.ajaxify.com/run/countdown/). A number counts down with the background color indicating "heat level"green at the start, and transitioning to red at the end.

The div that changes color is called timeout. Its initial declaration simply specifies its ID and class:

   <div  ></div> 

Using techniques covered in the Scheduling (Chapter 7) pattern, the startup sequence arranges for onTick( ) to be called every 100 milliseconds. At each interval, timeout is modified. innerHTML changes to alter the text and style.backgroundColor changes to alter the color:

   $("timeout").innerHTML = Math.round(secsRemaining);   $("timeout").style.backgroundColor = calculatePresentColor( ); 

The background color is determined by a function that manages the transition from green to red according to secsRemaining. Colors are usually represented with hex RGB valuese.g., you can set style.backgroundColor to the string, #00ff00, to make it green. However, there's a more convenient notation for this, based on percentages, so an equivalent representation is rgb(0%,100%,0%). The algorithm here gradually increases the red component from 0 percent to 100 percent and decreases the green component from 100 percent to 0 percent. Blue is fixed at 0 percent. At each moment, the red component is assigned to the percentage of time remaining and the green component to the percentage covered so far.

   function calculatePresentColor( ) {     var secsSoFar = TOTAL_SECS - secsRemaining;     var percentSoFar = Math.round((secsSoFar / TOTAL_SECS) * 100);     var percentRemaining = Math.round((secsRemaining / TOTAL_SECS) * 100);     return "rgb(" + percentSoFar + "%, " + percentRemaining + "%, 0%)";   } 

5.1.8. Related Patterns

5.1.8.1. Page Rearrangement

Page Rearrangement looks at manipulating the overall structure of the page, whereas this pattern looks at the appearance of individual elements. Together, the two patterns cover all aspects of display manipulation.

5.1.9. Metaphor

Display Morphing is like using a magic paintbrush to change the appearance of anything on the page.

5.1.10. Want To Know More?

  • InnerHTML versus DOM Discussion between Alex Russell and Tim Scarfe (http://www.developer-x.com/content/innerhtml/default.html)




Ajax Design Patterns
Ajax Design Patterns
ISBN: 0596101805
EAN: 2147483647
Year: 2007
Pages: 169

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net