Simple AS3 Slideshow Widget: Part 3

This is the final post in a three part tutorial detailing the creation of a Flash slideshow widget using ActionScript 3.0. Have a look over Part 1 and Part 2 before moving ahead.

In this post, we are examining the two methods which actually handle image loading and display within our module.

1
2
3
4
5
6
7
8
9
10
11
12
private function switchImage(e:TimerEvent):void {
	imageBitmapData.draw(this);
	imageBitmap.bitmapData = imageBitmapData;
	imageBitmap.alpha = 1;
	if(currentImage < imageArray.length-1){
		currentImage++;
	}else{
		currentImage = 0;
	}
	urlRequ.url = appPath + "path/to/images/" + imageArray[currentImage];
	imageLoader.load(urlRequ);
}

“switchImage” is invoked by the Timer we established previously. The function this method is to set up our eventual transition from one image to the next, grab the next image from our Array and begin to load it into our Loader instance on the Stage, and keep track of what position we are at in our Array. To accomplish this, we first “draw()” the entire Stage to our “imageBitmapData” instance. This data is then assigned to the “imageBitmap” bitmapData property, effectively duplicating the visible data within our Loader instance. This switch from Loader to Bitmap is in no way apparent to the viewer. We also switch the alpha property of out Bitmap to 1, ensuring that it is completely visible.

We then manage our “currentPosition” variable by checking the current value against the Length of the Array. If we have reached the end, we simply revert to a value of “0” causing an infinite loop.

All we have to do then is change the “url” property of our URLRequest object and then invoke another load() upon “imageLoader”.

1
2
3
private function imageLoaded(e:Event):void {
	imageTween = new Tween(imageBitmap, "alpha", Regular.easeIn, 1, 0, 2, true)
}

This is the last method we have in our little widget. “imageLoaded” is fired by an Event.COMPLETE when a loading image is finally loaded up. At this point, we simply use Tweener to tween the alpha of our Bitmap (displaying the previous image) down to 0, revealing the freshly loaded image beneath.

I recommend using SWFObject to embed the module into your website.

Here is the full PHP code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php 
$firstrun = true;
$files = "";
$dir = opendir("front_images");
while (false !== ($file = readdir($dir))) {
	if (strpos($file, ".gif", 1) || strpos($file, ".jpg", 1) || strpos($file, ".png", 1)) {
		if($firstrun){
			$files = $files . "" . $file;
			$firstrun = false;
		}else{
			$files = $files . "," . $file;
		}
	}
}
echo $files;
?>

Here is the full ActionScript class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
package {
	import flash.display.Sprite;
	import flash.display.Loader;
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.events.Event;
	import flash.events.TimerEvent;
	import flash.utils.Timer;
	import flash.net.URLRequest;
	import flash.net.URLLoader;
	import fl.transitions.Tween;
	import fl.transitions.easing.*;
 
	public class SlideShow extends Sprite {
		private var appPath:String;
		private var imgDur:int;
		private var currentImage:int;
		private var urlRequ:URLRequest;
		private var urlLoad:URLLoader;
		private var imageArray:Array;
		private var imageBitmap:Bitmap;
		private var imageBitmapData:BitmapData;
		private var imageLoader:Loader;
		private var imageTimer:Timer;
		private var imageTween:Tween;
 
		public function SlideShow():void {
			if (root.loaderInfo.parameters.appPath != undefined) {
				appPath = root.loaderInfo.parameters.appPath;
			} else {
				appPath = "http://yourwebsite.com/";
			}
			if (root.loaderInfo.parameters.imgDur != undefined) {
				imgDur = root.loaderInfo.parameters.imgDur*1000;;
			} else {
				imgDur = 5*1000;
			}
			gatherFiles();
		}
 
		private function gatherFiles():void {
			urlRequ = new URLRequest();
			urlRequ.url = appPath + "gatherFrontImages.php";
			urlLoad = new URLLoader();
			urlLoad.dataFormat = flash.net.URLLoaderDataFormat.TEXT;
			urlLoad.addEventListener(Event.COMPLETE, urlComplete);
			urlLoad.load(urlRequ);
		}
 
		private function urlComplete(e:Event):void {
			imageArray = e.target.data.split(",");
			currentImage = imageArray.length-1;
			imageLoader = new Loader();
			imageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageLoaded);
			this.addChild(imageLoader);
			imageBitmapData = new BitmapData(stage.stageWidth, stage.stageHeight);
			imageBitmap = new Bitmap();
			this.addChild(imageBitmap);
			switchImage(new TimerEvent(TimerEvent.TIMER));
			imageTimer = new Timer(imgDur);
			imageTimer.addEventListener(TimerEvent.TIMER, switchImage);
			imageTimer.start();
		}
 
		private function switchImage(e:TimerEvent):void {
			imageBitmapData.draw(this);
			imageBitmap.bitmapData = imageBitmapData;
			imageBitmap.alpha = 1;
			if(currentImage < imageArray.length-1){
				currentImage++;
			}else{
				currentImage = 0;
			}
			urlRequ.url = appPath + "path/to/images/" + imageArray[currentImage];
			imageLoader.load(urlRequ);
		}
 
		private function imageLoaded(e:Event):void {
			imageTween = new Tween(imageBitmap, "alpha", Regular.easeIn, 1, 0, 2, true)
		}
 
	}
}

Simple AS3 Slideshow Widget: Part 2

In Part 1, we had a look at the basic structure of what we are working toward, including a PHP file to read images from a directory and return a list of images to Flash, the setup of our FLA, and the basic construction of our document class. This widget, being so simple, will only require the document class.

We will now go through each method and describe what is happening…

1
2
3
4
5
6
7
8
9
10
11
12
13
public function SlideShow():void {
	if (root.loaderInfo.parameters.appPath != undefined) {
		appPath = root.loaderInfo.parameters.appPath;
	} else {
		appPath = "http://yourwebsite.com/";
	}
	if (root.loaderInfo.parameters.imgDur != undefined) {
		imgDur = root.loaderInfo.parameters.imgDur*1000;;
	} else {
		imgDur = 5*1000;
	}
	gatherFiles();
}

There are a few things to set up in our constructor function. These values can be passed in through flashvars or hard-coded into your class. We are being super flexible and allowing the user to input these values upon embed. For a short explanation of what is going on here, have a look at my previous post.

We now assign values to the “appPath” and “imgDur” variables. “appPath” is simply the path to our actual application or website. We will use this to construct both calls to the PHP file and also the images themselves. “imgDur” is a setting that specifies how long each image should persist on the screen before fetching another. We then call “gatherFiles()” after these values are established.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package {
	import flash.display.Sprite;
	import flash.display.Loader;
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.events.Event;
	import flash.events.TimerEvent;
	import flash.utils.Timer;
	import flash.net.URLRequest;
	import flash.net.URLLoader;
	import fl.transitions.Tween;
	import fl.transitions.easing.*;
 
	public class SlideShow extends Sprite {
		private var appPath:String;
		private var imgDur:int;
		private var currentImage:int;
		private var urlRequ:URLRequest;
		private var urlLoad:URLLoader;
		private var imageArray:Array;
		private var imageBitmap:Bitmap;
		private var imageBitmapData:BitmapData;
		private var imageLoader:Loader;
		private var imageTimer:Timer;
		private var imageTween:Tween;

As we step through this and encounter new variables, they will of course need to be defined and datatyped properly at the beginning of our class. We will also need to import any other classes we need within our package. The full list of import statements and variable declarations is included here for the sake of overview.

An important thing to note here, is that we are importing classes that are native to Flash, but are also importing the excellent “Tweener” packages which can be found at Google Code. You could use the build in tween classes, but Tweener is a lot more flexible and provides much more control.

Now, on to our data loading methods!

1
2
3
4
5
6
7
8
private function gatherFiles():void {
	urlRequ = new URLRequest();
	urlRequ.url = appPath + "gatherFrontImages.php";
	urlLoad = new URLLoader();
	urlLoad.dataFormat = flash.net.URLLoaderDataFormat.TEXT;
	urlLoad.addEventListener(Event.COMPLETE, urlComplete);
	urlLoad.load(urlRequ);
}

Our goal with this method is to create a connection to the PHP file and establish a handler for the results. In order to do this, we will use the “URLLoader” class. URLLoader has a method called “load” which requires a “URLRequest” object. URLRequest has a “url” property which we set using a combination of the “appPath” variable defined upon initialization and the location and name of our PHP file. We also set the “dataFormat” property of the URLLoader to “flash.net.URLLoaderDataFormat.TEXT”. This will ensure that the data we receive is properly interpreted as text. Finally, we add an event listener to watch for an “Event.COMPLETE” to our URLLoader and invoke the “load()” method.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
private function urlComplete(e:Event):void {
	imageArray = e.target.data.split(",");
	currentImage = imageArray.length-1;
	imageLoader = new Loader();
	imageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageLoaded);
	this.addChild(imageLoader);
	imageBitmapData = new BitmapData(stage.stageWidth, stage.stageHeight);
	imageBitmap = new Bitmap();
	this.addChild(imageBitmap);
	switchImage(new TimerEvent(TimerEvent.TIMER));
	imageTimer = new Timer(imgDur);
	imageTimer.addEventListener(TimerEvent.TIMER, switchImage);
	imageTimer.start();
}

“urlComplete” is the method that fires off once our URLLoader request is returned to Flash. We are doing four main things here for the final setup of our slideshow.

  1. First, we use the “split()” method to assign each file name to an Array called “imageArray”. We access the returned data (comma-delimited string) through the data property of the event target. The “currentImage” variable keeps track of which image is being displayed later on. We now set this to the Array length minus one. This provides us with the final index of our Array.
  2. Next, we will set up our display objects and add them to the display list. We create a Loader instance “imageLoader” to hold our loaded image and display it upon the Stage. We also add an event listener to the “contentLoaderInfo” property of our Loader instance. This will enable us to detect when the load has completed so that we can safely display the next image.
  3. Similar to the Loader instance, we now create a new BitmapData object “imageBitmapData” matching the size of our Stage. This will be used later on during image transitions and will feed a Bitmap object “imageBitmap” that we now create and add to the Stage.
  4. Finally, we set up a Timer to run based off of the “imgDur” variable set upon initialization. We just need to add an event listener to the Timer to handle each new image load and then invoke the “start()” method to get things rolling. Note that I am also manually triggering the “switchImage” method so we do not have to wait a full tick before our first image is shown.

Now we have our data imported and arranged nicely. Our structures and display list are all established. Everything is set up to begin actually displaying these images upon the Stage. In Part 3, we will examine the two remaining methods and have a look at the full, completed class structure.

Simple AS3 Slideshow Widget: Part 1

This is a simple example of how to build a dynamic slideshow widget in Flash using ActionScript 3.0 such as the one seen here.

The first thing you’ll need to do is set up an FLA with the properties you’d like to exhibit. Stage resolution is set to 500×300 with a black background. This will vary depending on the size of your generated images. Be sure that your FLA is set to use ActionScript 3.0 and declare your document class, in this case “SlideShow”.

Let’s set up a PHP file to read from the directory of our choosing and return a list of images to us.

1
2
3
$firstrun = true;
$files = "";
$dir = opendir("images");

So, here we declare some variables. “$firstrun” to determine where we are in our loop, and “$files” to hold the comma-delimited list the loop will produce. “$dir” is a directory reference for our image directory.

1
2
3
4
5
6
7
8
9
10
11
while (false !== ($file = readdir($dir))) {
	if (strpos($file, ".gif", 1) || strpos($file, ".jpg", 1) || strpos($file, ".png", 1)) {
		if($firstrun){
			$files = $files . "" . $file;
			$firstrun = false;
		}else{
			$files = $files . "," . $file;
		}
	}
}
echo $files;

The next part is pretty simple as well. We create “$files” and populate it with all of the files in our directory. Next, we simply loop over each item and look for certain character sequences to determine whether we should include a particular file in our list of images. You can see that the “$firstrun” Boolean is used here to determine comma placement for each item.

It is assumed at this point that we have also generated a set of images to use in our slide show and have dumped them into our “images” directory on the server.

So now it’s time to create an ActionScript class to use as the FLA document class. We called this class “SlideShow” in our FLA so this is the exact name we will need to give the file “SlideShow.as”.

1
2
3
4
5
6
package {
	import flash.display.Sprite;
	public class SlideShow extends Sprite {
		public function SlideShow():void {}
	}
}

Here is the basic setup for our SlideShow class. It extends flash.display.Sprite so we have to be sure to import that in our package. Planning our class, we are going to need to define a few different methods:

gatherFiles()
This will be used to create a connection to the server and run the PHP code we previously created.

urlComplete()
Will handle the processing of the comma-delimited String which is returned by PHP and the setup of our display objects on the Stage.

switchImage()
Will handle the image management and loading features.

imageLoaded()
This will serve to process our image transitions and is triggered as each image load completes.

In Part 2, we will look at each of these methods in detail.

Testing Flash Projects w/ Dynamic Variables

Many of the Flash modules and widgets I write are part of a larger system. Normally, some sort of ID or other variable piece of data will need to be passed in as flashvars upon initialization to allow the SWF to function correctly, making the appropriate data calls and so forth. When testing in the IDE, however, you are separated from the larger application and that data does not exist.

A simple way to test such items in the standalone Flash Player is to check whether those variables are being passed in… if not- simply use your test variables.

1
2
3
4
5
if (root.loaderInfo.parameters.appPath != undefined) {
	appPath = root.loaderInfo.parameters.appPath;
} else {
	appPath = "http://yourwebsite.com/somepath/";
}

This, for example, might be included within the document class constructor function. Easy and flexible!