Easy XML-driven Cross-fading Slide Show (AS2)
A few months back I wrote up a post explaining how to create your own cross-fading slide show using embedded images. I received some requests to see an XML version so I put one together. As I wrote the code for this it occurred to me that, in addition to demonstrating how to create a cross-fade, this small app also demonstrates many other frequently asked-about processes, including:
- Importing XML with attributes
- Assigning HTML links from XML to buttons
- The correct way to utilize dynamic variables in a function
- Using aliased names for objects to simplify coding
- Variable toggling
- Utilizing the MovieClipLoader class (loadClip) for image load status
So, all in all, in addition to being a pretty decent cross-fading slideshow tutorial, it’s also a pretty good reference for some other handy coding tricks.
The finished product:
Click here to download the source
In my first post, the second frame was used to preload all of the embedded images from the library. In the new source I use that frame to import my XML, which, by the way, looks like this:
<?xml version="1.0" encoding="utf-8"?>
<slides imgpath="images/">
<slide img="jacko1.jpg" source="bbc.co.uk" owner="Christopher Watters" link="http://images.google.com/imgres?imgurl=http://www.bbc.co.uk/cumbria/content/images/2005/10/28/jackolantern_christopher_walters_470x353.jpg&imgrefurl=http://www.bbc.co.uk/cumbria/content/image_galleries/halloween_pumpkins.shtml%3F72&h=353&w=470&sz=15&hl=en&start=1&sig2=_Rv-oVuW38R0lb-yem-_hg&um=1&tbnid=50EOuyczGqTXbM:&tbnh=97&tbnw=129&ei=l5INR_DuIoSaeN_6hI8M&prev=/images%3Fq%3Djackolantern%26svnum%3D10%26um%3D1%26hl%3Den%26client%3Dfirefox-a%26rls%3Dorg.mozilla:en-US:official%26hs%3DuZT%26sa%3DX" />
<slide img="jacko2.jpg" source="Flickr" owner="agoodveilsays" link="http://www.flickr.com/photos/74704734@N00/281001060/"/>
<slide img="jacko3.jpg" source="Flickr" owner="Bennett 4 Senate" link="http://www.flickr.com/photos/bennett4senate/279269395/" />
<slide img="jacko4.jpg" source="Flickr" owner="89AKurt" link="http://www.flickr.com/photos/53074154@N00/97794559/" />
<slide img="jacko5.jpg" source="Flickr" owner="BluePail" link="http://www.flickr.com/photos/bluepail/161181588/" />
</slides>
…and the AS code that imports it:
stop();
var picArray:Array = new Array(); //array to hold the image and all of its attributes
var imagePath:String = new String();
var imageXML:XML = new XML();
imageXML.ignoreWhite = true;
imageXML.onLoad = function(success:Boolean) {
var thisNode:XMLNode = new XMLNode();
imagePath = imageXML.firstChild.attributes.imgpath;
for(var i:Number = 0;i<imageXML.firstChild.childNodes.length;i++) {
thisNode = imageXML.firstChild.childNodes[i];
picArray.push([thisNode.attributes.img,thisNode.attributes.source,thisNode.attributes.owner,thisNode.attributes.link]);
}
delete imageXML;
play();
}
imageXML.load("slides.xml");
I start frame 2 with a stop() so that my slideshow, which begins on frame 3, doesn’t begin playing without images. Next I define the variables that I’ll be using in the slide show: picArray and imagePath. picArray will be a multi-dimensional array holding all of the the slide information and imagePath will be the path to my images. I keep the path separate just to make things smaller, cleaner, and easier to maintain. If your images will not all be in the same folder you can just prefix your image names in the XML with the path and forget about imagePath altogether.
Next I define the variable that will hold my XML, imageXML, and tell it to ignore any extra whitespace it finds in the XML. If you’ve worked with any dynamically created XML, you probably know that ignoreWhite is a life saver!
My onLoad function is short and sweet (though not as sweet as importing XML with AS3 – WOW, that’s easy! But that’s a topic for another post). I start off defining a variable named thisNode which will serve as an alias name, or shortcut, to the current xml node as I iterate through it. Then I read in the image path which is an attribute in the root node of my XML.
Next, I iterate through all of the slide nodes and populate picArray by assigning the information from each node to a position in the array. So picArray[0][0] will be the image name of the image in the first slide node, picArray[0][1] will be the ’source’ of the first slide node (which is where I found the image), etc.
Notice that, before I push the node, I assign a value of imageXML.firstChild.childNodes[i] to the thisNode variable. This is just to simplify the writing and reading of the code. If I didn’t do that my push line would look like this:
picArray.push([imageXML.firstChild.childNodes[i].attributes.img,imageXML.firstChild.childNodes[i].attributes.source,...);
…pretty long and ugly.
After I populate my array with all of the data from the xml, I really have no need to keep the xml in memory so I delete it and then initiate a play() to proceed to my slide show.
The last line on frame 2, imageXML.load(“slides.xml”);, is the line that kicks off the process of loading the XML.
And that’s it for the XML. Pretty easy! Now, on to the show (frame 3, that is)…
After initiating another stop() and loading the easing classes for Tweening, I define some more aliases:
stop();
import mx.transitions.*;
import mx.transitions.easing.*;
var pic1:MovieClip = slides_mc.slide1;
var pic2:MovieClip = slides_mc.slide2;
var source1:TextField = pic1.source_txt;
var source2:TextField = pic2.source_txt;
var owner1:TextField = pic1.owner_txt;
var owner2:TextField = pic2.owner_txt;
var button1:Object = pic1.source_btn;
var button2:Object = pic2.source_btn;
Again, the aliases are just shortcuts to objects so I don’t have to keep typing the full path to the target objects over and over again. For example, instead of having to type ’slides_mc.slide1.source_btn’ throughout the code, I’ll only have to type ‘button1′.
I will be incorporating one image, two text fields (source and owner), and one link button into each slide and I’d like them to tween gracefully together so I place all of the objects into one movie clip slide (mcSlide in the library). To perform the cross-fade I utilized two instances of mcSlide which I named slide1 and slide2. I then placed the two slide clips into one containing clip named slides_mc.
One problem I had with this sample is that, since I used the same ’slide’ for both images in the cross-fade, there was no way of knowing which button was active…the one fading out or the one fading in. To avoid confusion I decided to make the buttons invisible until the image completely faded in, which brings me to the next line of code:
button2._visible = false;
That will prevent the link button from the second slide from appearing until it finishes fading in and I toggle it to true (crossfade function).
Next I set the initial values of the variables I’ll be using.
var currClip:MovieClip = pic1; //tracks which clip is being viewed
var arrPosition:Number = -1; //tracks where the code is in the picture array
var showpicTime:Number = 7; //number of seconds to display the pic between fades
var tweenTime:Number = 3; //number of seconds to complete tween
var initialImage:Boolean = true; //used in onLoadInit for first image
Another potential issue I had to overcome was to prevent the cross-fade from initiating before the next image was done loading. To ensure that didn’t happen I added a property to the slide clips named picLoaded. This property is toggled to true when the image finishes loading and then back to false for the next image. This way, I can check to see whether the next image is ready, and if not, wait until the next time the crossfade function fires. Since no images are loaded when we first enter the slide show frame I set the property of both slides to false to start. I also set the alpha of each slide to 0 to start with so I can fade the first image in gracefully:
pic1.picLoaded = false;
pic2.picLoaded = false;
pic1._alpha = pic2._alpha = 0;
Next, I define the loader and listener for loading my images. By using loadClip and a Listener instead of loadMovie I can easily implement an onLoadInit event function that will fire when an image has finished loading. Without onLoadInit I wouldn’t be able to tell if the next image was ready to fade in.
var mcLoader:MovieClipLoader = new MovieClipLoader();
var mcListener:Object = new Object();
mcLoader.addListener(mcListener);
mcListener.onLoadInit = function(mc:MovieClip) {
mc._parent.picLoaded = true;
if (initialImage) {
initialImage = false;
var firstTween = new Tween(pic1, "_alpha", Regular.easeIn, 1, 100 , tweenTime, true);
picInt = setInterval(crossfade,showpicTime*1000);
};
};
As I mentioned earlier in this post, my onLoadInit function sets the slide’s picLoaded property to true which will lets the crossfunction function know that the next image is ready. Also included in the onLoadInit is code to fade the initial image in and start the interval which will fire the crossfade function every ’showpicTime’ seconds.
Next, I load my initial two images:
mcLoader.loadClip(imagePath + picArray[++arrPosition][0],pic1.image_mc);
source1.text = picArray[arrPosition][1];
owner1.text = picArray[arrPosition][2];
button1.link = picArray[arrPosition][3];
button1.onRelease = function() {
getURL(this.link,"_blank");
}
mcLoader.loadClip(imagePath + picArray[++arrPosition][0],pic2.image_mc);
source2.text = picArray[arrPosition][1];
owner2.text = picArray[arrPosition][2];
button2.link = picArray[arrPosition][3];
button2.onRelease = function() {
getURL(this.link,"_blank");
}
This code loads the image using loadClip and sets all of the image-related objects to the values appropriate to their image. The button code gets a bit tricky. You may think that you can simply place getURL(picArray[arrPosition][3],”_blank”); in the onRelease code but you can’t. The reason is that the ‘arrPosition’ variable will evaluate to the the next image’s value by the time the function fires so you would always be loading the next image’s link. To get around this I assign ‘link’ as a property to the button and use this.link inside my button’s onRelease code.
Finally comes the code that takes care of all of the crossfades subsequent to the first:
function crossfade() {
if (currClip == pic1 && pic2.picLoaded) {
var tween1:Tween = new Tween(pic2, "_alpha", Regular.easeIn, 1, 100 , tweenTime, true);
var tween2:Tween = new Tween(pic1, "_alpha", Regular.easeIn, 100, 1 , tweenTime, true);
if(++arrPosition >= picArray.length) {arrPosition = 0;}
tween2.onMotionFinished = function() {
button2._visible = true;
button1._visible = false;
pic1.picLoaded = false;
mcLoader.loadClip(imagePath + picArray[arrPosition][0],pic1.image_mc);
source1.text = picArray[arrPosition][1];
owner1.text = picArray[arrPosition][2];
button1.link = picArray[arrPosition][3];
button1.onRelease = function() {
getURL(this.link,"_blank");
};
};
currClip = pic2;
} else {
if(pic2.picLoaded) {
var tween1 = new Tween(pic1, "_alpha", Regular.easeIn, 1, 100 , tweenTime, true);
var tween2 = new Tween(pic2, "_alpha", Regular.easeIn, 100, 1 , tweenTime, true);
if(++arrPosition >= picArray.length) {arrPosition = 0;}
tween2.onMotionFinished = function() {
button1._visible = true;
button2._visible = false;
pic2.picLoaded = false;
mcLoader.loadClip(imagePath + picArray[arrPosition][0],pic2.image_mc);
source2.text = picArray[arrPosition][1];
owner2.text = picArray[arrPosition][2];
button2.link = picArray[arrPosition][3];
button2.onRelease = function() {
getURL(this.link,"_blank");
};
};
currClip = pic1;
};
};
};
The top and bottom of the crossfade function are almost identical. The only difference is that in the top portion, slide2 is fading in and slide1 is fading out, and vice versa in the bottom.
The function starts off by checking which clip is currently at 100 alpha (currClip) and whether the next image has been fully loaded using the picLoaded property I discussed earlier. It then tweens the active image out at the same time it tweens the next image in. When the tween is finished, the onMotionFinished function fires and gets the next image ready to be faded in.
Finally I set currClip to the currently viewable clip so the next time corssfade fires it knows which clip to fade in and out.
Whew, this was a long post. But I assure you, if you remove the comments you’ll have just about 100 lines of code total. That’s not bad for an xml-driven cross-fading slideshow!
-rG
If you enjoyed this post, please consider to leave a comment or subscribe to the feed and get future articles delivered to your feed reader.



Hi Martin, Glad you figured it out and thanks for posting your solution for others to see!
Glenn
thanks for the great xml slideshow.
but i have a question. i am trying it on a site and if i navigate away with another button and then come back to it, the images load and transition erratically. is there a script to clear the previously loaded image to fix that?
thanks so much
Just wanted to say thanks.
I needed only a simple AS2 crossfade, and my ActionScripting skills are rusty. This was the ticket. Removed the frame and button, took out some of the parameters, included a caption parameter, along with X and Y coordinates to specify where over the image the caption should be placed, and voila : )
Thank you very much for sharing!
Is it possible to integrate a shuffle function? (Is it possible to arrange the order of appearance of the images randomly?)
thanks for sharing this . i need to ask if i would use the random images , what code i should use and where ?