Dynamic Content Using XML
Dynamic Content Using XML
As you may recall from the previous chapter, XML is short for Extensible Markup Language. An XML file is a simple text file that uses tags to describe data. Similar to HTML, XML tags begin with a less than sign (<) and end with a greater than sign (>), and a slash (/) is used to close a tag. Collectively, an opening tag, the corresponding closing tag, and everything in between is referred to as a node when the XML content is converted into an ActionScript object. An XML object must possess a root node (a node that encom- passes all the data) to be properly read into ActionScript.
1. Create a new text file using a simple text editor (like TextEdit on Mac, or Notepad on Windows, or you can
use Dreamweaver to create a new XML file). Save the file as config.xml in your website/config directory.
If you use TextEdit on the Mac, you 2.
Enter the following text into the config.xml file: need to choose Format > Make Plain Text before saving your file.
<?xml version="1.0" encoding="UTF-8"?> When you save your file, deselect <site>
Hide Extension and manually type in the .xml extension. After you
<item name="" url="" ></item> click Save, TextEdit will ask you to <item name="" url="" ></item>
confirm that you want to use the <item name="" url="" ></item>
.xml extension; click “Use .xml” to <item name="" url="" ></item>
save the file. You will need to follow these same steps to properly save
<item name="" url="" ></item> your .css file later in the chapter <item name="" url="" ></item>
as well.
</site> The preceding code defines the structure for your
XML document. The XML document will determine what is shown in your portfolio.
The first line of the XML file is called the XML declara- tion. The declaration indicates to any system that tries to use the file that what follows is XML content. The next line contains the opening <site> tag. Note that
there is a corresponding closing tag that contains a for- ward slash ( </site> ) at the end of the file. The <site> tag will serve as the root node.
There are six opening and closing <item> tags. Inside the opening tags are two attributes. Attributes provide additional information about a tag element. The name
Animation with Scripting for Adobe Flash Professional CS5 Studio Techniques
attribute will be displayed on a menu item button and on the content title within the Flash movie. The url attribute will tell the Flash file where to look for con- tent that will be loaded when the corresponding menu item button is clicked. The address that you add to the url attribute will be relative to the location of the Flash document.
Since each item node refers to a menu item, adding or removing work samples to your portfolio will be as simple as adding or removing an item node in this file. This approach allows you to make updates with- out requiring you to update and republish your Flash movie.
3. Update your attributes on each item tag to match the files in the content directory by adding the following
highlighted text:
Adjust the name and url attributes to customize whatever content you
<item name=" MotionBrush " url=" content/ want to use in your portfolio.
➥ MotionBrushExample.swf " ></item> <item name=" MotionTrail " url=" content/
➥ MotionTrailExample.swf " ></item> <item name=" MotionBlur " url=" content/
➥ MotionBlurExample.swf " ></item> <item name=" MotionBlurTrail " url=" content/
➥ MotionBlurTrailExample.swf " ></item> <item name=" Wanderer " url=" content/
➥ WandererExample.swf " ></item> <item name=" Runner " url=" content/
➥ RunnerExample.swf " ></item>
Next, you’ll add a description that will appear in the box You can add attributes containing
below the content in your portfolio. To accomplish this, other information that you’d like to
you will add your text between each opening and clos- keep track of, such as date_added,
ing item tag. Your text will potentially contain characters project_type , and so on. These
additional attributes can then be reserved by XML (e.g., < and &); this will especially be the displayed by updating your Flash
case when you include HTML text. Thus, you will wrap file (and code), or they can remain
your text in a CDATA tag to prevent it from being parsed unseen and yet retained for your
(i.e., interpreted) as XML. A CDATA section starts with personal reference.
<![CDATA[ and ends with ]]> .
Chapter 5 Sharing Your Animation
4. Add the following highlighted descriptions to each item: <item name="MotionBrush" url="content/
➥ MotionBrushExample.swf" > <![CDATA[The MotionBrush ➥ class allows you to draw on screen using a ➥ symbol.]]> </item>
<item name="MotionTrail" url="content/ ➥ MotionTrailExample.swf" > <![CDATA[The MotionTrail
➥ class creates a trail that follows an animated ➥ symbol.]]> </item>
<item name="MotionBlur" url="content/ ➥ MotionBlurExample.swf" > <![CDATA[The MotionBlur
➥ class blurs a symbol based on its velocity.]]> ➥ </item>
<item name="MotionBlurTrail" url="content/ ➥ MotionBlurTrailExample.swf" > <![CDATA[The ➥ MotionBlurTrail combines the functionality of the ➥ MotionTrail and MotionBlur classes.]]> </item>
<item name="Wanderer" url="content/ ➥ WandererExample.swf" > <![CDATA[The Wanderer class
➥ allows you to control an animated character.]]> ➥ </item>
<item name="Runner" url="content/RunnerExample. ➥ swf" > <![CDATA[The Runner class allows you ➥ to control an animated character at varying ➥ speeds.]]> </item>
You may want to add links or formatting to your descrip- tion text. Links are useful if you want to credit another artist for some portion of the work shown or if you want to link to a live website that contains your work.
5. Add the following highlighted HTML link to the first item description:
<item name="MotionBrush" url="content/ ➥ MotionBrushExample.swf" ><![CDATA[The MotionBrush ➥ class allows you to draw on screen using a ➥ symbol. MotionBrush can be used in combination ➥ with the <a href="http://ajarproductions.com/ ➥ blog/2009/02/10/flash-extension-motionsketch/" ➥ target="_blank">MotionSketch extension</a>. ]]>
➥ </item>
Animation with Scripting for Adobe Flash Professional CS5 Studio Techniques
The anchor ( <a … > ) tag in the preceding text will cre- ate a link in the description field. The target attribute (set to _blank ) will force the link to open in a new
If you want to add bold or italic for-
window.
matting to content that will appear
Save your XML file.
in a textfield with an embedded
font, you will also need to embed Now that your content and configuration files are ready, the bold and italic variations of the
font family in the Font Embedding you can write the document class that will drive the
dialog box. Alternatively, embed-
entire site.
ding will not be necessary if your textfield uses Device Fonts with a
The Site Document Class
common web font (e.g., Arial or Verdana).
There are a number of ways to approach the coding of your site. If you feel that you could potentially reuse many of the behaviors on the site or that you might be develop- ing similar sites in the future, you may want to structure your project to be heavily object-driven (broken into smaller, more reusable classes). Given that the interac- tions in this project are pretty simple and will all take place well within reach of the site document, this chapter will approach the coding of this site using a document class. This is a somewhat subjective decision that will be largely affected by your needs as a Flash artist.
1. Return to your site.fla document in Flash. Deselect all (Command+Shift+A/Ctrl+Shift+A).
2. In the Properties panel, type in Site as the document class and click the Edit class definition button (the
pencil icon) (Figure 5.27). The first time you click this button, Flash warns you that the class doesn’t exist and
that it will create one automatically; click OK.
Figure 5.27 The Edit class definition
button in the Properties panel.
3. Click the Edit class definition button a second time. Flash shows you the document class that it generated.
Save this class as Site.as in your website folder.
4. Add the following property declarations just inside the class block:
private var menuItemStart:Point = new Point(25, ➥ 100);
private var menuItemSpacing:uint = 10; private var configFile:String = "config/
➥ config.xml";
Chapter 5 Sharing Your Animation
private var styleFile:String = "config/site.css"; private var dataLoader:URLLoader = new ➥ URLLoader(); private var styleLoader:URLLoader = new ➥ URLLoader(); private var xml:XML; private var stylesheet:StyleSheet = new ➥ StyleSheet(); private var contentLoader:Loader; private var currentMenuItem:MovieClip;
These properties will be used later in the Site class. Defining these properties at the top makes the file easy to update, and it renders the properties available to all the methods you’re going to write. Since this is
a document class, all the methods and properties will
be private, because no other class will need (or have reason) to access them.
The menuItemStart property will store the position of the first menu button, and that position will determine the position of all the subsequent buttons. It is more efficient to store this position as a Point object rather than having separate properties for x and y values. The menuItemSpacing property will determine how much vertical space (in pixels) is added between each button. The configFile and styleFile properties will store the relative locations of the XML file you just created and
a CSS file that you will create later on. The dataLoader and styleLoader objects will take the file locations and load them into the Flash file. The xml object will store the data from the loaded XML file, and the stylesheet object will store the data from the loaded CSS file. The contentLoader will be responsible for loading and storing the content that will be loaded based on the url attributes in the XML. Finally, currentMenuItem will store the active menu item once it’s been clicked.
5. Define the init method and call it from the construc- tor, as shown in the following highlighted code: public function Site(){
init(); }
Animation with Scripting for Adobe Flash Professional CS5 Studio Techniques
private function init():void { preloader_mc.visible = false; dataLoader.addEventListener(Event.COMPLETE,
➥ onDataLoaded);
styleLoader.addEventListener(Event.COMPLETE, ➥ onStylesLoaded);
styleLoader.load(new URLRequest(styleFile)); dataLoader.load(new URLRequest(configFile));
The init method starts by hiding the preloader_mc instance (since you only want it to appear when con- tent is loading). The init method then adds two event listeners to handle the loaded XML file and CSS style sheet. Finally, the load method of each loader is called, and the links are sent as URLRequest objects.
6. Add the methods (after the init method) that will be called as a result of the init method:
private function onDataLoaded(e:Event):void { xml = new XML(e.target.data); trace(xml.toXMLString()); }
private function onStylesLoaded(e:Event):void { stylesheet.parseCSS(e.target.data); description_mc.txt.styleSheet = stylesheet;
} The onDataLoaded method uses the event data that has
been passed to the method to populate the xml object. The trace method will provide confirmation that your XML data has been loaded successfully (this method will be removed in a moment). The onStylesLoaded method parses the data provided into the stylesheet object and then applies the parsed CSS to the stylesheet property of the description textfield.
7. Ensure that the following classes are imported at the top of your class package: import flash.display.MovieClip;
import flash.geom.Point; import flash.net.URLLoader;
Chapter 5 Sharing Your Animation
import flash.display.Loader; import flash.text.StyleSheet;
import flash.net.URLRequest; import flash.events.Event;
8. Save your script and test your movie (Command+Return/Ctrl+Enter).
When you test your movie, you’ll see a significant amount of text in the Output panel. You’ll see an
Unhandled ioError pointing to your nonexistent CSS file (you may have to scroll up in the Output panel). That
will be resolved later, after you’ve created the CSS file. Don’t worry about this error message for now. If Flash is able to parse your XML, you’ll also see the text from your XML file in the Output panel. If Flash cannot
parse your XML, you’ll receive an XML parser failure
message in the Output panel, and you’ll need to check your XML file for typos.
9. Once you have your XML loading successfully, you can replace the trace method call: private function onDataLoaded(e:Event):void {
xml = new XML(e.target.data); generateMenu();
10. Now define the generateMenu method below the onStylesLoaded method:
private function generateMenu():void { var items:XMLList = xml.item; var itemY:Number = menuItemStart.y; for(var i:uint=0; i < items.length(); i++) {
var mi:menuItem = new menuItem(); mi.x = menuItemStart.x; mi.y = itemY; mi.txt.text = items[i].@name; mi.index = i;
mi.addEventListener(MouseEvent.CLICK, ➥ onMenuItemClick);
addChild(mi); itemY += mi.height + menuItemSpacing; } }
Animation with Scripting for Adobe Flash Professional CS5 Studio Techniques
The generateMenu method creates a local variable, items , to store the item nodes in the XML object. Note the simplicity and power of the dot syntax used to refer- ence this list of nodes ( xml.item ). The items variable is typed to XMLList because it has no root node (it’s just
a list of the item nodes inside the XML object). Next,
a local variable is used to store the y position for the item. This position will change for each menu item.
A for loop is utilized to traverse the items list. Note the parentheses on length() . These are necessary to retrieve the length of the items list because length is
Using the index number on each
a method in the XMLList (and XML) class, whereas it menu button to trigger new con-
is a property in the Array class. Within the loop, a new tent is a smart means of achieving
menuItem instance is created from the menuItem symbol forward compatibility. If you decide
in the Library. This instance is given a position based you want back and next buttons
or a different navigation system on the stored x value and the current itemY value. The entirely, you’ll still be able to easily
text property is then assigned on the textfield within load content from places other than
the menu item. The name attribute of the current item the menu item button.
in the loop is then referenced using the @ operator. Then a new property is created dynamically on the menu item to store the current index in the loop. This index allows you to reference the correct item node in the XML when the button is pressed. A click listener is added to detect when the button has been clicked. The button is then added to the display list using the addChild method. Finally, the itemY value is increased, both to account for the height of the button that was just added and to add space for a new button that is still to be added.
Accessing XML Attributes
There are two ways to access attribute content on You’ll now begin writing the code that will load in your an XML node:
external content.
. node. @attributeName
1. Within your Site.as ActionScript file, add the . node. attribute( " attributeName " );
onMenuItemClick method below the generateMenu method:
The first method is shorthand and is generally very readable. The second method is longer but
private function onMenuItemClick(e:MouseEvent): slightly more tolerant if your attribute happens to
➥ void {
be missing. Whichever method you use is project- currentMenuItem = e.currentTarget as specific and the choice is largely based on personal
MovieClip;
preference.
Chapter 5 Sharing Your Animation
The clicked button is obtained by accessing the currentTarget property of the MouseEvent. The currentMenuItem will be stored as a Movie Clip so that you can use methods and properties of the MovieClip class without offending the compiler.
2. Ensure that flash.events.MouseEvent has been added to your import statements at the top.
3. Save your script and test your movie. You should now see six buttons with text corresponding to the item
names in your XML file (Figure 5.28).
Figure 5.28 The menu buttons are now loaded in and arranged dynamically with ActionScript.
4. Add the following highlighted code to your onMenuItemClick method:
private function onMenuItemClick(e:MouseEvent): ➥ void {
currentMenuItem = e.currentTarget as ➥ MovieClip;
loadItem(currentMenuItem.index); }
The index property that you stored in the generateMenu method will now be used to load the item content, title, and description into the corresponding symbols within your Flash document.
Animation with Scripting for Adobe Flash Professional CS5 Studio Techniques
5. Add the loadItem method below the onMenuItemClick method:
private function loadItem(n:uint):void { var xmlItem:XML = xml.item[n]; loadContent(xmlItem.@url); loadDescription(xmlItem.toString()); loadTitle(xmlItem.@name);
} The first line on the loadItem method uses Array access
notation to locate the desired item node within the stored XML object. The node is then accessed to popu- late the arguments for the method calls that follow. The description content is obtained by using the toString method on the item node.
6. Add the following method definitions below the loadItem method:
private function loadDescription( ➥ captionStr:String):void {
description_mc.txt.htmlText = captionStr;
private function loadTitle(titleStr:String):void { title_mc.txt.text = titleStr;
private function loadContent(link:String):void {
trace("link: " + link); }
The htmlText property is used for the description (rather than the text property) to ensure that the con- tent will be displayed as HTML rather than as plain text.
7. Save your script and test your movie. Click each menu button. You should see the title and description appear
in their proper places as you click each menu item, and the link to the content should appear in the Output panel (Figure 5.29).
Chapter 5 Sharing Your Animation
Figure 5.29 The Output panel displays the links from the menu button clicks.
8. Now replace the trace call in the loadContent method with the following highlighted code:
private function loadContent(link:String):void { unloadContent(contentLoader); contentLoader = new Loader(); contentLoader.load(new URLRequest(link)); content_mc.addChild(contentLoader); contentLoader.contentLoaderInfo.
➥ addEventListener(Event.OPEN, onContentLoadStarted); contentLoader.contentLoaderInfo.
➥ addEventListener(Event.COMPLETE, onContentLoaded); contentLoader.contentLoaderInfo.
➥ addEventListener(ProgressEvent.PROGRESS, ➥ onContentLoadProgress);
contentLoader.contentLoaderInfo. ➥ addEventListener(IOErrorEvent.IO_ERROR,
➥ onContentLoaded); }
The loadContent method looks complex, but what it’s doing is actually pretty simple. An unloadContent method clears out any content that has been loaded previously. Next, a fresh Loader object is assigned to
Animation with Scripting for Adobe Flash Professional CS5 Studio Techniques
the contentLoader property, and the link is loaded as
a URLRequest . The contentLoader is then added to the display list within the content_mc instance on Stage. The next four lines use the contentLoaderInfo property of the loader to add event listeners for the following scenarios: when the content starts loading, finishes loading, progresses in loading, and fails to load.
9. Add the following two methods after the loadContent method:
private function onContentLoadStarted(e:Event): ➥ void {
preloader_mc.visible = true; preloader_mc.gotoAndStop(1); }
private function onContentLoadProgress(
➥ e:ProgressEvent):void { var percent:uint = ➥ Math.ceil((e.bytesLoaded/e.bytesTotal) * 100); preloader_mc.gotoAndStop(percent); }
When the load is started, the onContentLoadStarted method will make the preloader visible and move the preloader to the first frame. As the load progresses, the
onContentLoadProgress method will calculate the per- centage loaded and will move the preloader to the cor- responding frame. Moving the preloader’s frame will animate the ring you created while the content loads. The code utilizes the bytesLoaded and bytesTotal prop- erties of the ProgressEvent to calculate the percentage, which is then translated to a frame number by multi- plying the decimal by 100 and rounding that value up to a whole number using the Math.ceil method (i.e., "ceiling"; because there is no frame 0, that value should always be rounded up to the nearest integer).
10. Add the unloadContent method below the previous two methods:
private function unloadContent(loader:Loader):void{ try { loader.close(); } catch (e:*) {}
Chapter 5 Sharing Your Animation
try { loader.unload(); } catch (e:*) {} try { removeChild(loader); } catch (e:*) {} try { loader = null; } catch (e:*) {}
} The unloadContent method utilizes try and catch
statements. Try - catch statements are similar to if - else statements except that each try statement must have a
corresponding This method for unloading content catch statement. If the code inside the was found on Grant Skinner’s
try block fails, the catch block will be executed. In the blog (http://gskinner.com/blog), preceding code, each try - catch block has been con-
which has heaps of great Flash and densed to a single line. The catch statement requires
ActionScript information and tools.
a single parameter, which has been typed here with an asterisk (*). The asterisk denotes that the argu- ment passed can be of any type. In these try - catch statements, the catch block is empty. In this case, the purpose of using try - catch is simply to avoid generating errors. The try - catch statements are a quick solu- tion for unloading content, because you won’t know exactly what state the contentLoader is in when the
unloadContent method is called. The contentLoader could be loading content, done loading, or undefined.
This unloadContent method is a nice one-size-fits-all solution.
11. Finally, add the onContentLoaded method below the previous method:
private function onContentLoaded(e:*):void { preloader_mc.visible = false; if(e.type == IOErrorEvent.IO_ERROR){
trace(e.text); }else {
The incoming parameter is typed using an asterisk, because it could be an error event or a complete event. The preloader is hidden in any case. If the incom- ing event is an error, the message will be sent to the Output panel.
Animation with Scripting for Adobe Flash Professional CS5 Studio Techniques
Thus far, your Site class should read as follows (be sure to add any missing import statements):
package {
import flash.display.MovieClip; import flash.geom.Point; import flash.net.URLLoader; import flash.text.StyleSheet; import flash.net.URLRequest; import flash.events.Event; import flash.display.Loader; import flash.events.MouseEvent; import flash.events.ProgressEvent; import flash.events.IOErrorEvent;
public class Site extends MovieClip {
private var menuItemStart:Point = new ➥ Point(25, 100);
private var menuItemSpacing:uint = 10; private var configFile:String = "config/
➥ config.xml";
private var styleFile:String = "config/ ➥ site.css";
private var dataLoader:URLLoader = new ➥ URLLoader
private var styleLoader:URLLoader = new ➥ URLLoader(); private var xml:XML; private var stylesheet:StyleSheet = new
➥ StyleSheet();
private var contentLoader:Loader; private var currentMenuItem:MovieClip;
public function Site(){ init(); }
Chapter 5 Sharing Your Animation
private function init():void { preloader_mc.visible = false; dataLoader.addEventListener(Event. ➥ COMPLETE, onDataLoaded); styleLoader.addEventListener(Event. ➥ COMPLETE, onStylesLoaded); styleLoader.load(new URLRequest( ➥ styleFile)); dataLoader.load(new URLRequest( ➥ configFile)); }
private function onDataLoaded(e:Event): ➥ void {
xml = new XML(e.target.data); generateMenu(); }
private function onStylesLoaded(e:Event): ➥ void {
stylesheet.parseCSS(e.target.data); description_mc.txt.styleSheet =
➥ stylesheet; }
private function generateMenu():void { var items:XMLList = xml.item; var itemY:Number = menuItemStart.y; for(var i:uint=0; i < items.length(); i++)
{ var mi:menuItem = new menuItem(); mi.x = menuItemStart.x; mi.y = itemY; mi.txt.text = items[i].@name; mi.index = i;
mi.addEventListener(MouseEvent.CLICK, ➥ onMenuItemClick);
addChild(mi); itemY += mi.height + menuItemSpacing;
Animation with Scripting for Adobe Flash Professional CS5 Studio Techniques
private function onMenuItemClick(e:MouseEvent): ➥ void {
currentMenuItem = e.currentTarget as ➥ MovieClip;
loadItem(currentMenuItem.index);
private function loadItem(n:uint):void { var xmlItem:XML = xml.item[n]; loadContent(xmlItem.@url); loadDescription(xmlItem.toString()); loadTitle(xmlItem.@name);
private function loadDescription(captionStr: ➥ String):void {
description_mc.txt.htmlText = captionStr;
private function loadTitle(titleStr:String): ➥ void {
title_mc.txt.text = titleStr;
private function loadContent(link:String):void
unloadContent(contentLoader); contentLoader = new Loader(); contentLoader.load(new URLRequest(link)); content_mc.addChild(contentLoader); contentLoader.contentLoaderInfo.
➥ addEventListener(Event.OPEN, onContentLoadStarted); contentLoader.contentLoaderInfo.
➥ addEventListener(Event.COMPLETE, onContentLoaded); contentLoader.contentLoaderInfo.
➥ addEventListener(ProgressEvent.PROGRESS, ➥ onContentLoadProgress);
contentLoader.contentLoaderInfo. ➥ addEventListener(IOErrorEvent.IO_ERROR,
➥ onContentLoaded); }
Chapter 5 Sharing Your Animation
private function onContentLoadStarted(e:Event): ➥ void {
preloader_mc.visible = true; preloader_mc.gotoAndStop(1); }
private function onContentLoadProgress( ➥ e:ProgressEvent):void {
var percent:uint = Math.ceil( ➥ (e.bytesLoaded/e.bytesTotal) * 100);
preloader_mc.gotoAndStop(percent); }
private function unloadContent(loader:Loader): ➥ void{
try { loader.close(); } catch (e:*) {} try { loader.unload(); } catch (e:*) {} try { removeChild(loader); } catch (e:*) {} try { loader = null; } catch (e:*) {}
private function onContentLoaded(e:*):void { preloader_mc.visible = false; if(e.type == IOErrorEvent.IO_ERROR){
trace(e.text); }else {
12. Save your script and test your movie. Click on each menu item. You should now see your content files
loaded into your portfolio (Figure 5.30 on the next page).
Animation with Scripting for Adobe Flash Professional CS5 Studio Techniques
Figure 5.30 The content is now successfully being loaded into the portfolio.
At this point, your content should be loading just fine, but since you’re loading files directly from your local machine, you may not have any indication that the pre- loader is working.