In this sample, we've taken the example in Easing Slider 4 and changed it to use XML as the data source (instead of hard-coding the information into the fla). We also added one more piece of information to each location: a blurb about that location, including html links, to display in a scrollable textfield.
Because we'll be using an XML file as the data source, we can replace the array we used previously:
var groupinfo:Array = [
{placename:"Sunset Beach", myphoto:slider_mc.pic0, xloc:178, yloc:85, xtext:146, ytext:64},
{placename:"Kailua", myphoto:slider_mc.pic1, xloc:347, yloc:245, xtext:352, ytext:230},
{placename:"Hanauma Bay", myphoto:slider_mc.pic2, xloc:367, yloc:318, xtext:355, ytext:324},
{placename:"Waikiki", myphoto:slider_mc.pic3, xloc:282, yloc:306, xtext:249, ytext:309},
{placename:"Pearl Harbor", myphoto:slider_mc.pic4, xloc:217, yloc:273, xtext:189, ytext:294}
];
with a blank groupinfo array that will be populated with data from the XML file. Each of the properties previously in groupinfo can be replicated in the XML file as attributes of a node. We'll structure the XML file to have one main places node, and as many individual place nodes as there are locations to be shown. Here is what that implementation of the XML file would look like:
oahumap.xml, initial version
<?xml version="1.0" encoding="utf-8"?> <places> <place placename="Sunset Beach" xloc="178" yloc="85" xtext="146" ytext="64" /> <place placename="Kailua" xloc="347" yloc="245" xtext="352" ytext="230" /> <place placename="Hanauma Bay" xloc="367" yloc="318" xtext="355" ytext="324" /> <place placename="Waikiki" xloc="282" yloc="306" xtext="249" ytext="309" /> <place placename="Pearl Harbor" xloc="217" yloc="273" xtext="189" ytext="294" /> </places>
You can see the resemblance between the xml file and the original groupinfo array, which perhaps provides a hint about how each node in the XML file might be read and its data saved in an element of groupinfo. What we need to do is store each attribute of the place tags in the corresponding property of a groupinfo array element. Here's the code to create an XML object mapxml and a blank groupinfo array, define a function to read and put data in mapxml into groupinfo, assign that function to the onLoad property of mapxml, and start loading the XML file:
// import the Delegate class to use for assigning the XML onload function
import mx.utils.Delegate;
// create a new XML instance (a variable of type XML)
var mapxml:XML = new XML();
// create a blank groupinfo array to be filled in by onXmlRead
var groupinfo:Array = [];
function onXmlRead(ok:Boolean) {
if (ok) {
var places:Array = mapxml.firstChild.childNodes;
for (var i=0; i < places.length; i++) {
groupinfo.push({
placename:places[i].attributes.placename,
xloc:Number(places[i].attributes.xloc),
yloc:Number(places[i].attributes.yloc),
xtext:Number(places[i].attributes.xtext),
ytext:Number(places[i].attributes.ytext)
});
}
} else {
trace('problem reading xml file');
}
}
function init() {
mapxml.ignoreWhite = true;
mapxml.onLoad = Delegate.create(this, onXmlRead);
mapxml.load("oahumap.xml");
}
init();
When the code above executes, init is called first. The first line tells Flash to ignore carriage returns, tabs and any other whitespace between nodes in the xml file. Then it assigns the onXmlRead function to the onLoad event property of mapxml, retaining the main timeline as the scope for that function. Lastly, a call is made to the web server to download the XML file (or get it from cache if it has been previously downloaded). When the download is complete, onXmlRead will be called.
Within onXmlRead, a variable places is created to refer to the array of childNodes within the main place node in the XML file (the array of childNodes is just the collection of place tags that exist within the main places tag). onXmlRead then loops over that array of childNodes, creating a new element in groupinfo for each place tag and saving each attribute of the place node in the corresponding property of that newly created element of groupinfo. Got that?
Notice, if you haven't already, that the init function is completely different from the one in the previous example because now the thing that we need to do first of all on start up is to read the XML file and put its contents into a format (the groupinfo array) useable by our program. Only when that is complete can we do the things we did previously in init: assign event handlers and attach the dot movieclips and fill in their textfields. Because the XML file is now providing the information about where to attach each dot and each dot label, and what placename to use in the dot label, we can't set up that information til the data is ready to use. The place where that happens (the data being ready to use) is inside function onXmlRead, so that's where we'll add a line to call function setup, which will now contain everything that used to be in function init:
function onXmlRead(ok:Boolean) {
if (ok) {
var places:Array = mapxml.firstChild.childNodes;
for (var i=0; i < places.length; i++) {
groupinfo.push({
placename:places[i].attributes.placename,
xloc:Number(places[i].attributes.xloc),
yloc:Number(places[i].attributes.yloc),
xtext:Number(places[i].attributes.xtext),
ytext:Number(places[i].attributes.ytext)
});
}
setup(); // call the setup function to assign event handlers and build the map
} else {
trace('problem reading xml file');
}
}
There's one more change that needs to be made to the code from our previous example. The associated picture movieclip information is no longer stored in the groupinfo array (or in the XML file). Because the naming scheme of the pictures (pic0-picn) follows a pattern that can easily be applied in a loop, there is no reason to store that information separately. We can just create the correspondence directly in the setup loop:
for (var i:Number=0; i < groupinfo.length; i++) {
ctrl = this.attachMovie("dot", "p"+i, i, {
_x:groupinfo[i].xloc,
_y:groupinfo[i].yloc,
placename:groupinfo[i].placename,
myphoto:slider_mc["pic"+i]
});
// etc
}
The myphoto property is now assigned based on the corresponding photo having the same index in its name in the control (instead of from a property of the groupinfo array). Those are all the changes necessary to make the previous example work from an XML file instead of a hardcoded array.
One more change was made to this fla from the previous example to show an example of including scrollable html-formatted text read from the XML file. As mentioned on the XML page, any text in an XML file which needs to contain tags that are to be read in as is (eg, HTML-formatted text) instead of as subnodes of the node they appear under should be surrounded by special CDATA formatting. Specifically, the text should be preceded by <![CDATA[ and followed by ]]>. As an example, the Sunset Beach place tag now looks like this in the XML file:
<place placename="Sunset Beach"xloc="225" yloc="86" xtext="192" ytext="64"> <![CDATA[On the North Shore of Oahu, <a href="http://surfing.about.com/cs/epicsurfspots/a/072303sunset.htm" target="_blank">Sunset Beach</a> is known for big wave surfing during the winter season and home to the Duke Kahanamoku Classic surfing competition and the O'Neill World Cup of Surfing competition and occasionally the site of the Quiksilver In Memory of Eddie Aikau big wave competition.]]></place>
The CDATA itself is not read as part of the tag -- it simply serves to indicate that the subsequent text should be read as a big text string (until the "]]>" is encountered). So the onXmlRead function now looks like:
function onXmlRead(ok:Boolean) {
if (ok) {
var places:Array = mapxml.firstChild.childNodes;
for (var i=0; i < places.length; i++) {
groupinfo.push({
placename:places[i].attributes.placename,
xloc:Number(places[i].attributes.xloc),
yloc:Number(places[i].attributes.yloc),
xtext:Number(places[i].attributes.xtext),
ytext:Number(places[i].attributes.ytext),
descrip:places[i].firstChild.nodeValue
});
}
setup();
} else {
trace('problem reading xml file');
}
}
Notice that the description text is read as the firstChild of the place tag (node), and its .nodeValue property is used to access it (in much the same way that a textfield's .text property is used to access the textfield's content).
I hope you can guess what the next step is, based on the steps we've followed previously: the descrip property of the groupinfo array has to be assigned to a property of the button, so it will be available for use in the rollover, rollout, and onrelease functions.
function setup() {
var ctrl:MovieClip;
for (var i:Number=0; i < groupinfo.length; i++) {
ctrl = this.attachMovie("dot", "p"+i, i, {
_x:groupinfo[i].xloc,
_y:groupinfo[i].yloc,
placename:groupinfo[i].placename,
myphoto:slider_mc["pic"+i],
descrip:groupinfo[i].descrip
});
// etc
}
Now it's available as a property of the button, so when the button is clicked, that property can be used to set the content of textfield descrip on stage. We'll display it at the same time we display the new caption -- once the tween is complete (ie, in the showName function):
function showName() {
caption.text = this.placename;
descrip.text = this.descrip;
descrip.scroll = 1;
up._visible = down._visible = true;
}
We also set the textfield's scroll property to 1 in case it was scrolled down on a previous click and unhid the up and down scroll buttons (hidden in init and doClick). The only thing left to add to the code is the text formatting, which we can do with either css styling (using the StyleSheet class) or the TextFormat class, both of which are shown on the Easing Slider 4 page. Since we already have a StyleSheet set up, we'll just add formatting for a tags (including hover) and use that for links in the the descrip field. Here's the change to the StyleSheet and its assignment to descrip:
var mapcss = new TextField.StyleSheet();
mapcss.setStyle(".caption", {fontFamily: "Verdana", fontSize: "10px", color:"#000000"});
mapcss.setStyle("a", {color: '#0000cc', textDecoration:'underline'})
mapcss.setStyle("a:hover", {color:"#006600", textDecoration:'underline'})
...
function init() {
descrip.styleSheet = mapcss;
mapxml.ignoreWhite = true;
mapxml.onLoad = Delegate.create(this, onXmlRead);
mapxml.load("oahumap.xml");
}
And the functions and assignments to handle single-click scrolling:
function scrollTextUp() {
if (descrip.scroll > 0) {
descrip.scroll--;
}
}
function scrollTextDown() {
if (descrip.scroll < descrip.maxscroll) {
descrip.scroll++;
}
}
function setup() {
...
// set up the textfield button handlers for continuous scroll when pressed
up.onRelease = scrollTextUp;
down.onRelease = scrollTextDown;
}
For other scrolling options (click-and-hold buttons, eased scrollbar) and/or how to format text without css, see the scroll text page. The complete code for the example above may be found in oahumap_slider5.as and oahumap_slider5.fla, available via the link at right. The final example in this series will show how to create the slider and load the jpgs in it dynamically.
last update: 25 Mar 2006
Discussed on this page:
easing slider example with xml as data source, including html-formatted text with links, css styling for a tags, use of cdata, single-click scrollable textfield
Files:
oahumap_slider5.as
oahumap_slider5.fla
In oahumap.zip, password required
Subscription:
A password may be obtained by subscription ($20 for one month)
An access password will be emailed to the address you specify within 24 hours of receipt of payment, and will remain active for 30 days thereafter. A list of all files currently available at the site may be viewed here.