RSS

Extending the AS3/Flash9 Slideshow with XML

Wed, Sep 10, 2008

Effects, Flash, Interfaces, Latest, XML

Extending the AS3/Flash9 Slideshow with XML

In this second part tutorial we’re going to add some more features to the slideshow application.

Those would be forwarding and rewinding slides, play and pause the slideshow and linkable slides. If you haven’t read the first part tutorial yet, you should do it before continue. You can read it here.

Requirements

Adobe Flash CS3

Try / Buy

Sample files:

slideshowprt2.zip

Adjust XML structure

To store the link of each slide, we just add it as an attribute to the xml file, or to be more accurate, on the image nodes. We also set the target window of the link, which might be neccesary to set in some cases. So, our xml is looking now like this:

<slideshow>
	<image src="images/fly.jpg" desc="Fly" link="http://www.wikipedia.org" target="_self"/>
	<image src="images/mouse.jpg" desc="Computer mouse" link="http://www.google.com" target="_blank"/>
	<image src="images/country.jpg" desc="Country" link="http://www.thetechlabs.com" target="_self"/>
	<image src="images/rope.jpg" desc="Rope" link="http://www.amazon.com" target="_blank"/>
	<image src="images/flower.jpg" desc="Flower" link="http://www.adobe.com" target="_self"/>
</slideshow>

Adding new objects

Since we know, how the xml looks like, we can move on to the knew stuff on the stage. In the mcInfo movieclip we’ve added 4 new buttons. Pause/Play and Forward/Rewind, which will later be assigned to event listeners. On the main stage is a invisible button as big as the size of the slides which will be used to open the links defined in the xml.
Alright, that’s already enough to go on with the coding part.

Adding new variables

First of all, we need to add some new variables to our script.

To know, if the slideshow is currently playing or paused, we set a flag:

var bolPlaying:Boolean = true;

And we also store the current slide link and target window in a variable:

var strLink:String = "";
var strTarget:String = "";

Init function

This is all we need for the variable. Now let’s take a look about what’s changing in the init function of the slideshow. We added the following two lines at the beginning of the function to prevent the user to click any button as long as the xml file hasn’t been loaded completely:

	mcInfo.visible = false;
	btnLink.visible = false;

We’ve also changed the function that will be called once the slideTimer event is fired. Now the function nextSlide() will be called, which we’ll create later:

	slideTimer.addEventListener(TimerEvent.TIMER, nextSlide);

On the last line of the initSlideshow() function we add the event listeners for the buttons. The play and button pause event listeners will be assigned to the same function togglePause(). The next and previous button will be asssigned to the nextSlide() and previousSlide() function. And last of all, we connect the invisible link button that covers the slide area with the goToWebsite() function. And since our slideshow will automatically be playing at the beginning, we hide the play button.

	btnLink.addEventListener(MouseEvent.CLICK, goToWebsite);
	mcInfo.btnPlay.addEventListener(MouseEvent.CLICK, togglePause);
	mcInfo.btnPause.addEventListener(MouseEvent.CLICK, togglePause);
	mcInfo.btnNext.addEventListener(MouseEvent.CLICK, nextSlide);
	mcInfo.btnPrevious.addEventListener(MouseEvent.CLICK, previousSlide);
	mcInfo.btnPlay.visible = false;

onXMLLoadComplete function

Once the xml is completely loaded, we need to show the mcInfo and the button link again. So we add the following two line of code to the function onXMLLoadComplete()

	mcInfo.visible = true;
	btnLink.visible = true;

And since our switchSlide() function will now need to have the index number of the slide, we add a zero as the parameter. We’ll explain the changes in the switchSlide() function later.

	switchSlide(0);

NextSlide/PreviousSide function

Let’s take a look at the nextSlide() and previousSlide() functions. They are called when clicking the next and previous button and the nextSlide() function is also called when the Timer event of the sliderTimer has been fired.
The nextSlide() function checks, if there are any slides left to move on. If so, the current switchSlide() function will be called with the next slide index. If there are no more slides left, then the parameter will be zero standing for the first slide.
The previousSlide() function works the same way. If there are slide we can go back, then the switchSlide() function will be called with the previous slide index. If we’re already on the first slide, then we start the slideshow from the last slide with calling the switchSlide() function with the parameter of the total slide count minus one since the array count begins with zero.

function nextSlide(e:Event = null):void {
	if(intCurrentSlide + 1 < intSlideCount)
		switchSlide(intCurrentSlide + 1);
	else
		switchSlide(0);

}

function previousSlide(e:Event = null):void {
	if(intCurrentSlide - 1 >= 0)
		switchSlide(intCurrentSlide - 1);
	else
		switchSlide(intSlideCount - 1);
}

SwitchSlide function

Since the nextSlide() and previousSlide() functions are now handling the checking for the slides, we can take out this part in the switchSlide() function.
To prevent the user from clicking too fast on the next and previous button, we check, if the tweener is still fading in the slides. If so, we just ignore the action. We’re doing this by adding the following if-statement to the first line of the switchSlide() function.

	if(!Tweener.isTweening(currentContainer)) {

Now we only need to set the new link and the target of it. This will be done exactly the same way as setting the description of the slide.

		strLink		= xmlSlideshow..image[intCurrentSlide].@link;
		strTarget	= xmlSlideshow..image[intCurrentSlide].@target;

FadeSideIn function

The fadeSlideIn() function has also a small addition. We check if the slideshow is currently playing and show the number of seconds to the next slide. If the slideshow is paused, we show a status message. The text will be assigned to the lbl_info label.

	if(bolPlaying) {
		mcInfo.lbl_loading.text = "Next slide in " + TIMER_DELAY / 1000 + " sec.";
	} else {
		mcInfo.lbl_loading.text = "Slideshow paused";
	}

OnSlideFadeIn function

On the onSlideFadeIn() function we now need to check, if the slideshow is playing. If so, we can start the timer again:

	if(bolPlaying && !slideTimer.running)
		slideTimer.start();

TogglePause function

The togglePause() function will be called when the user clicks on the play and pause button. First, we check, if the slideshow is playing, if so, we show the play button, set the bolPlaying variable to false, change the status message of the lbl_info label to “Slideshow paused” and stop the timer.
If the slideshow is currently paused, we show the pause button, set the bolPlaying variable to true again, show the time to the next slide and restart the timer.

function togglePause(e:MouseEvent):void {
	if(bolPlaying) {
		mcInfo.btnPlay.visible = true;
		mcInfo.btnPause.visible = false;

		bolPlaying = false;
		mcInfo.lbl_loading.text = "Slideshow paused";
		slideTimer.stop();
	} else {
		mcInfo.btnPlay.visible = false;
		mcInfo.btnPause.visible = true;

		bolPlaying = true;
		mcInfo.lbl_loading.text = "Next slide in " + TIMER_DELAY / 1000 + " sec.";
		slideTimer.reset();
		slideTimer.start();
	}
}

GotToWebsite function

The last function we need to define is the goToWebsite() function. This function will be called once the user clicks on the invisible button. It will check, if the strLink variable is empty or null. If not, the link will be opened.

function goToWebsite(e:MouseEvent):void {
	if(strLink != "" && strLink != null) {
		navigateToURL(new URLRequest(strLink), strTarget);
	}
}

We’ve already reached the end of the second part of the slideshow tutorial. We hope that you enjoyed reading it and we appreciate any kind of feedback.

Note

The feature for clicking the invisible button only works, when you’re running the flash on a webserver or in the flash sdk.

Full code with comments

// import tweener
import caurina.transitions.Tweener;

// delay between slides
const TIMER_DELAY:int = 5000;
// fade time between slides
const FADE_TIME:Number =	1;

// flag for knowing if slideshow is playing
var bolPlaying:Boolean = true;
// reference to the current slider container
var currentContainer:Sprite;
// index of the current slide
var intCurrentSlide:int = -1;
// total slides
var intSlideCount:int;
// timer for switching slides
var slideTimer:Timer;
// slides holder
var sprContainer1:Sprite;
var sprContainer2:Sprite;
// slides loader
var slideLoader:Loader;
// current slide link
var strLink:String = "";
// current slide link target
var strTarget:String = "";
// url to slideshow xml
var strXMLPath:String = "slideshow-data.xml";
// slideshow xml loader
var xmlLoader:URLLoader;
// slideshow xml
var xmlSlideshow:XML;

function initSlideshow():void {
	// hide buttons, labels and link
	mcInfo.visible = false;
	btnLink.visible = false;

	// create new urlloader for xml file
	xmlLoader = new URLLoader();
	// add listener for complete event
	xmlLoader.addEventListener(Event.COMPLETE, onXMLLoadComplete);
	// load xml file
	xmlLoader.load(new URLRequest(strXMLPath));

	// create new timer with delay from constant
	slideTimer = new Timer(TIMER_DELAY);
	// add event listener for timer event
	slideTimer.addEventListener(TimerEvent.TIMER, nextSlide);

	// create 2 container sprite which will hold the slides and
	// add them to the masked movieclip
	sprContainer1 = new Sprite();
	sprContainer2 = new Sprite();
	mcSlideHolder.addChild(sprContainer1);
	mcSlideHolder.addChild(sprContainer2);

	// keep a reference of the container which is currently
	// in the front
	currentContainer = sprContainer2;

	// add event listeners for buttons
	btnLink.addEventListener(MouseEvent.CLICK, goToWebsite);
	mcInfo.btnPlay.addEventListener(MouseEvent.CLICK, togglePause);
	mcInfo.btnPause.addEventListener(MouseEvent.CLICK, togglePause);
	mcInfo.btnNext.addEventListener(MouseEvent.CLICK, nextSlide);
	mcInfo.btnPrevious.addEventListener(MouseEvent.CLICK, previousSlide);

	// hide play button
	mcInfo.btnPlay.visible = false;
}

function onXMLLoadComplete(e:Event):void {
	// show buttons, labels and link
	mcInfo.visible = true;
	btnLink.visible = true;	

	// create new xml with the received data
	xmlSlideshow = new XML(e.target.data);
	// get total slide count
	intSlideCount = xmlSlideshow..image.length();
	// switch the first slide without a delay
	switchSlide(0);
}

function fadeSlideIn(e:Event):void {
	// add loaded slide from slide loader to the
	// current container
	currentContainer.addChild(slideLoader.content);
	// clear preloader text
	mcInfo.lbl_loading.text = "";

	// check if the slideshow is currently playing
	// if so, show time to the next slide. If not, show
	// a status message
	if(bolPlaying) {
		mcInfo.lbl_loading.text = "Next slide in " + TIMER_DELAY / 1000 + " sec.";
	} else {
		mcInfo.lbl_loading.text = "Slideshow paused";
	}

	// fade the current container in and start the slide timer
	// when the tween is finished
	Tweener.addTween(currentContainer, {alpha:1, time:FADE_TIME, onComplete:onSlideFadeIn});
}

function onSlideFadeIn():void {
	// check, if the slideshow is currently playing
	// if so, start the timer again
	if(bolPlaying && !slideTimer.running)
		slideTimer.start();
}

function togglePause(e:MouseEvent):void {
	// check if the slideshow is currently playing
	if(bolPlaying) {
		// show play button
		mcInfo.btnPlay.visible = true;
		mcInfo.btnPause.visible = false;

		// set playing flag to false
		bolPlaying = false;
		// set status message
		mcInfo.lbl_loading.text = "Slideshow paused";
		// stop the timer
		slideTimer.stop();
	} else {
		// show pause button
		mcInfo.btnPlay.visible = false;
		mcInfo.btnPause.visible = true;

		// set playing flag to true
		bolPlaying = true;
		// show time to next slide
		mcInfo.lbl_loading.text = "Next slide in " + TIMER_DELAY / 1000 + " sec.";
		// reset and start timer
		slideTimer.reset();
		slideTimer.start();
	}
}

function switchSlide(intSlide:int):void {
	// check if the last slide is still fading in
	if(!Tweener.isTweening(currentContainer)) {
		// check, if the timer is running (needed for the
		// very first switch of the slide)
		if(slideTimer.running)
			slideTimer.stop();

		// change slide index
		intCurrentSlide = intSlide;

		// check which container is currently in the front and
		// assign currentContainer to the one that's in the back with
		// the old slide
		if(currentContainer == sprContainer2)
			currentContainer = sprContainer1;
		else
			currentContainer = sprContainer2;

		// hide the old slide
		currentContainer.alpha = 0;
		// bring the old slide to the front
		mcSlideHolder.swapChildren(sprContainer2, sprContainer1);

		// create a new loader for the slide
		slideLoader = new Loader();
		// add event listener when slide is loaded
		slideLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, fadeSlideIn);
		// add event listener for the progress
		slideLoader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, showProgress);
		// load the next slide
		slideLoader.load(new URLRequest(xmlSlideshow..image[intCurrentSlide].@src));

		// show description of the next slide
		mcInfo.lbl_description.text = xmlSlideshow..image[intCurrentSlide].@desc;

		// set link and link target variable of the slide
		strLink		= xmlSlideshow..image[intCurrentSlide].@link;
		strTarget	= xmlSlideshow..image[intCurrentSlide].@target;

		// show current slide and total slides
		mcInfo.lbl_count.text = (intCurrentSlide + 1) + ” / ” + intSlideCount + ” Slides”;
	}
}

function showProgress(e:ProgressEvent):void {
	// show percentage of the bytes loaded from the current slide
	mcInfo.lbl_loading.text = “Loading…” + Math.ceil(e.bytesLoaded * 100 / e.bytesTotal) + “%”;
}

function goToWebsite(e:MouseEvent):void {
	// check if the strLink is not empty and open the link in the
	// defined target window
	if(strLink != “” && strLink != null) {
		navigateToURL(new URLRequest(strLink), strTarget);
	}
}

function nextSlide(e:Event = null):void {
	// check, if there are any slides left, if so, increment slide
	// index
	if(intCurrentSlide + 1 < intSlideCount)
		switchSlide(intCurrentSlide + 1);
	// if not, start slideshow from beginning
	else
		switchSlide(0);

}

function previousSlide(e:Event = null):void {
	// check, if there are any slides left, if so, decrement slide
	// index
	if(intCurrentSlide - 1 >= 0)
		switchSlide(intCurrentSlide - 1);
	// if not, start slideshow from the last slide
	else
		switchSlide(intSlideCount - 1);
}

// init slideshow
initSlideshow();

Share/Save/Bookmark

, , , , , , , , ,

This post was written by:

Rafael Nuenlist - who has written 6 posts on The Tech Labs.

Rafael Nünlist is currently working at orange8 as a Richmedia Developer. He will complete his apprenticeship with a swiss federal vocational diploma in information technology this summer. His strengths are Flash, Flex, Actionscript, Php/MySQL and AIR. He is also a member of the dreaminginflash team.

22 Comments For This Post

  1. Magici1 Says:

    I can’t download the source files (404 error).
    Could you repair it ?

    Thanks

  2. Carlos Pinho Says:

    Hi Magic,

    Thank you for pointing the broken link. I’ve fixed it.

    Cheers,
    Carlos

  3. Ronald Says:

    In this second version the memory leak still isn’t addressed properly. When using 200kb images, the browser goes from 40mb to 250mb in like 5 minutes. This is a really big problem when using it for normal slideshow purposes.

    Except for the memleak it’s a pretty cool slideshow with nice features.

  4. John Says:

    Thanks for the great tutorial. One thing I noticed is when for example, slide 3 is transitioning to slide 4, slide 2 pops up during the transition. Any idea what could be causing that?

  5. andreb Says:

    Hi, i was wondering if this gallery could be a video gallery instead of an image gallery! And if so, what do i have to change? Probably the timer event?

    Thansk for this tutorial…very usefulL!

  6. andreb Says:

    When i say the timer event has to change i mean that the swf file can only switch when de movie ends!! How can i do that?

    Sorry for 2 posts..

  7. andreb Says:

    Hi again :) I figured out how maybe i can change this to load swf video files. My problem is that the TIMER_DELAY can´t always be the same because of the lenght of the swf’s, so i need to change that var for each new swf. I created a new xml tag called time=”" and tried to pass it to the TIMER_DELAY in the switchSlide function like tis:

    TIMER_DELAY = xmlSlideshow..file[intCurrentSlide].@time;

    But since i had to determine the TIMER_DELAY at the beginning as a value (2000 for ex) the timer keeps that value and doesnt change for the value time from xml!

    What am i doing wrong? plz help

  8. Rafael Nünlist Says:

    @andreb: i was also thinking of adding this feature to this version but i really missed that one.

    You can change it this way:

    function onSlideFadeIn():void {
    slideTimer.removeEventListener(TimerEvent.TIMER, nextSlide);
    slideTimer = new Timer(xmlSlideshow..file[intCurrentSlide].@time);
    slideTimer.addEventListener(TimerEvent.TIMER, nextSlide);
    if(bolPlaying && !slideTimer.running)
    slideTimer.start();
    }

  9. jtomm Says:

    This is awesome, however I have noticed the memory leak as well. Has there been any steps made to address this?

  10. Rafael Nünlist Says:

    @all on the memory leak complaining: Please check back later. The zip file contains a version that doesn’t fix that problem. Carlos will upload the right version in the coming time.

  11. Carlos Pinho Says:

    I’m sorry for my late update on the right file.

  12. Derrick Bradley Says:

    @Carlos

    Any idea when we will see this fix? I would love to start using this slideshow.

  13. Carlos Pinho Says:

    @ Derrick, the file was already updated. Pls go ahead and download it.

  14. nathaniel Says:

    Was just wondering if we could have a tilelist on there and and link the xml file to that list so we can get a small preview of what is coming b4 we see it.

    Really good tutorial. I’ll definitely link back 2 this from my site.

  15. nathaniel Says:

    oh please pardon me, I am new to AS and Flash…

  16. Adam Says:

    I’ve used a version on this type of slideshow for a few projects now…I’ve also been trying to extend it a little bit so that it can also show numbered thumbnails that can be clicked and fade to the appropriate picture in the sequence…

    here’s my code…
    private function onXMLLoadComplete(e:Event):void {
    xmlSlideshow = new XML(e.target.data);
    slideCount = xmlSlideshow..image.length();
    switchSlide(null);

    for (var i:int = 0; i < slideCount; i++) {

    var thumb = this.addChild(new Thumb());
    thumb.name = “thumb” + i;
    thumb.x = X + (SPACE * i);
    thumb.y = Y;

    thumb.theNum.text = i + 1;
    thumb.buttonMode = true;
    thumb.mouseChildren = false;
    thumb.addEventListener(MouseEvent.CLICK, onClick);
    }
    }

    private function onClick(e:MouseEvent):void {
    var currentBtnName:String = e.currentTarget.name;
    var splitName:Array = currentBtnName.split(”b”);
    var btnNumber:int = splitName[1];

    switchSlide(null);
    }

    this just adds Thumb movieClips to the movie and puts an onClick event on them to call the same function as the switchSlide function…how can I get this to switch to the corresponding picture?

    Thanks in advance…

  17. Adam Says:

    Actually I changed my onClick code to this…

    private function onClick(e:MouseEvent):void {
    if(slideTimer.running) {
    slideTimer.stop();
    }

    var currentBtnName:String = e.currentTarget.name;
    var splitName:Array = currentBtnName.split(”b”);
    var btnNumber:int = splitName[1];

    slideLoader = new Loader();
    slideLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, fadeSlideIn);
    slideLoader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, showProgress);
    slideLoader.load(new URLRequest(xmlSlideshow..image[btnNumber].@src));
    }

    This changes the picture but it doesn’t fade like the other ones.

  18. Audrey Says:

    Hi - great tutorial! This will help for the base of a lot of projects. I’m just learning AS3, and I’m a cross between a designer/programmer, so it’s taking me awhile to get the hang of things. If I wanted to change up the tween a bit, how would I do this? I would like to do a solarized effect. I can do this on the timeline using filters, but not sure how to do in code. Generally I just change the Brightness, Contrast on the Adjust Color filter from 0 to 100 during the tween. Any ideas?

  19. Audrey Says:

    Also, when you change the Fade time -

    // fade time between slides
    const FADE_TIME:int = 1;

    The descriptions pop up before the photos. I’m using the first version of the gallery you put up without the extra features.

  20. kopetkai Says:

    can this be made to go to a random image?

  21. Stephanie Says:

    Great slideshow! I’m new to AS3 and XML but this tutorial is the only one I’ve been able to understand thanks to the comments! However, I’m wanting to make some tweaks to do the following (I know I’m picky, but I know there’s ways to do this since I’ve seen it before in finished shows):

    1. Fade the non-current container out so if different sized images are used you don’t see what was just shown (using the removeChild script from the first part, it works once the 3rd image is shown, but not on the 2nd)

    2. I’d rather use a randomization of images so the slideshow is not always in the same sequence. Is this possible?

    3. Is there a way to link to pages not yet published online (still building the site I want to link images to) so that they work correctly when uploaded to the web etc without having to re-write the XML data to reflect such?

    4. What would be the best way to center the images (not all the same size)?

    I appreciate everything you can help with now and already! Thanks!

  22. Balaji Says:

    Great thanks…. for a nice work..
    Is it possible to add external SWF file, instead of JPG images….
    if possible,Can anybody help me…..

1 Trackbacks For This Post

  1. Tecinfor » Blog Archive » Slideshow XML /AS3 Says:

    [...] Se você ainda não leu a primeira parte tutorial ainda, você deve fazê-lo antes de continuar. Você pode lê-lo aqui. Start Slide Show with PicLens Lite Tags: adobe, as3, flash, Slideshow, [...]

Leave a Reply