A couple of days ago, in the flash.sitedesign forum, someone asked about creating a flashing random thumbnail gallery – and cited http://www.stevenlippman.com/ as what they had in mind. Lucky for you, I thought it would make for a good tutorial.
If you look at that site long enough, you’ll see it’s not actually random at all and its not even dynamic. Probably it’s hand placed movie clips with time line animation. That’s what I call the hard way. The easy way is programmatic, dynamic, and easily modified.
Here’s an example of the finished product
First let’s consider the various components:
- Get a list images to use
- Create grid of MovieClips to load these images into
- Each clip loads images in random order with random timing
Get a list of images to use:
There are a few ways this could be handled. For this tutorial I have chosen to use XML to define the images. XML files are nice because they are human readable and modified by anyone.
Create grid of MovieClips:
A little bit of math will make easy work out of creating a grid of movie clips in any combination of columns and rows.
Each clip randomly loads and displays images:
An ActionScript class that extends MovieClip will allow you to easily hang custom code off of all your script created grid clips.
Part A/2 – Init
First, create a folder for this tutorial. Name it something like ‘flashingThumbs’ and use that as the project folder to place all the files in. Within this folder also create an ‘images’ folder – to house the thumbnails that will be displayed.
Part A – The XML
Copy the following XML, paste into a text file, and save it in your project folder as gallery.xml
<gallery>
<image title="Title a">a.jpg</image>
<image title="Title b">b.jpg</image>
<image title="Title c">c.jpg</image>
<image title="Title d">d.jpg</image>
<image title="Title e">e.jpg</image>
<image title="Title f">f.jpg</image>
<image title="Title g">g.jpg</image>
</gallery>
Although it’s simple – it could be made even simpler by leaving out the title attribute. However, I added this on purpose, both to show reading of attributes, and to make expansion in the future more straight forward. More on that later.
Don’t worry about the images themselves, you can get all of them in the project .zip file at the end of the tutorial. I even stole them from the Steven Lippman site. Of course you can, and should, use your own thumbs – just make sure they’re all 40×40 like the ones supplied.
In Flash, start a new AS 2.0 movie, set it’s size to 730 x 400, and give it a black background. Add the following script to the first frame of the default layer, Layer 1:
var theXML = new XML();
theXML.ignoreWhite = true;
//an array of image objects populated from xml
var gallery:Array;
//folder containing the images that are defined in the xml
var thumbFolder = "images/";
//called automatically when the xml is done loading
theXML.onLoad = function(success)
{
if (success) {
gallery = new Array();
theXML.parseXML();
var len = theXML.firstChild.childNodes.length;
trace(len);
for (var i = 0; i < len; i++) {
var item = new Object();
item.title = theXML.firstChild.childNodes[i].attributes.title;
item.image = theXML.firstChild.childNodes[i].firstChild.nodeValue;
gallery.push(item);
}
buildGallery(135);
}
};
theXML.load("gallery.xml");
stop();
Save the movie as gallery.fla in your project folder and compile and run the movie. You should see ‘7′ appear in the output window – the number of images defined in the xml file. if you run the movie without saving first, you’ll get an error about the gallery.xml file not being found. Both the Flash file and the xml file need to reside in the same folder – since no path is specified – just ‘gallery.xml’.
First the gallery.xml file is loaded and when complete the onLoad method of the xml object is called. If success, then no error occured and the remainder of the function executes. The returned xml is parsed and a for loop is used to iterate the nodes. For each node an object ‘item’ is created and given two properties title, and image – their values being fed from the xml. The item is then pushed onto the gallery array and the loop continues.
When complete you have an array ‘gallery’ with as many items as there are images defined in the xml. Each item in the array is an object with title and image properties. It would look something like:
gallery = [{title:"Title a", image:"a.jpg"}, {title:"Title b", image:"b.jpg"}, {title:"Title c", image:"c.jpg"}, ...{}]
If you want the first image in the array you merely need do:
firstImage = gallery[0].image;
This is the reason I added the title attribute to the xml file. If the xml had contained only the image listing, and no attributes, an array would’ve sufficed. With the title attribute defined, it warranted a more complex data type – an array of objects. Also nice because it gives you the ability to select data by name. If you add more attributes to the xml, simply add them to the object as well, inside the for loop. The underlying gallery array, and any code that consumes it, need not change at all – unless you want to make use of the newly expanded data within the objects.
Don’t worry about the call to buildGallery() – we’ll get to that momentarily.
PS – you can remove the trace from the onLoad as you know it’s working properly.
Part B – Create a grid of clips
First, you’ll need an empty movie clip that will be used as a place holder to load the images into. We’ll use a clip from the library as opposed to creating a clip from code, so that a custom class can easily be linked to each of the clips.
On the Flash stage press Ctrl-F8 – to open the create symbol dialog. Press the advanced button at lower right to display the full dialog:

Give your clip the same settings as is shown – be sure to differentiate between ‘thumb’ and ‘Thumb’ in the identifier and class fields.
Click OK, to close the dialog.
Select the script icon on frame 1, and open the script editor. Near the top of the script, Immediately after the declaration for the gallery array and right before the onLoad definition, add the following:
var thumbsPerRow = 15;
var thumbWidth = 40;
var thumbHeight = 40;
var thumbSpace = 8;
var startX = 10;
var startY = 10;
function calcPosition(ind:Number):Array
{
var whichCol = ind % thumbsPerRow;
var whichRow = Math.floor(ind / thumbsPerRow);
var curThumbX = startX + (whichCol * (thumbWidth + thumbSpace));
var curThumbY = startY + (whichRow * (thumbHeight + thumbSpace));
return [curThumbX, curThumbY];
}
This is the little bit of math I alluded to earlier. The variable usage should be pretty self evident by their naming. As in the example, we’ll use 15 thumbs per row, and each thumb will be 40×40. If you do want to use a different thumb size, this is the place to change it. There will be eight pixels between thumbs, and the grid will begin at 10, 10. Simple enough. Using that information the calcPosition function will return the x,y point where any thumbnail should be – given the thumbnails number: 0 – n.
First, the column is found by using the mod operator: % – which returns the remainder of integer division. Dividing the thumb number by how many thumbs per row there are, and then seeing how many are left, gives the column. For example, take the whole first row, thumbs 0 – 14 – you can’t divide any of those by 15 with integer math. What’s left is the number itself: 0 – 14. In the second row, thumbs 15 – 29, it goes like so: 15 goes into 15 evenly, with no remainder – so 0 is returned. 15 goes into 16, with 1 as the remainder. etc, etc. If you create 135 thumbs (0 – 134) then the last thumb goes into column: 134 % 15 = 14. Nifty. From there, getting the x position of the thumb is a bit of simple math.
To get the row, we again divide the thumb number by the number of thumbs per row, but this time we use regular division. If we’re at thumb 134 then 134 / 15 = 8.93333. The floor method is used to get the closest integer less than, or equal to, the target. The floor of 8.9 = 8. So, thumb 134 goes into row 8 – given the 0 based system – that is really row 9. Again, with a bit of math, it’s now easy to find the y value where the thumb should go.
The x,y value is then returned in an array. All we need now is a function that will attach n clips from the library, and position them using calcPosition(). Enter buildGallery(). Paste the following right after the calcPosition() function:
function buildGallery(numThumbs:Number)
{
//uses the records in the gallery array
for (var i = 0; i < numThumbs; i++) {
var p = calcPosition(i);
var aThumb = this.attachMovie("thumb", "thumb" + i, 10 + i, {_x:p[0], _y:p[1]});
aThumb.init(gallery, thumbFolder);
}
}
As you noticed earlier, buildGallery(135) is called once the xml is loaded and the gallery array is built. All buildGallery does is attach the empty thumb clip you created earlier, at the position indicated by calling calcPosition().
Additionally, an init method is called on every thumb created – and both the gallery array, and the thumb folder are passed in. The init method is located in the Thumb class, the class attached to all instances of the thumb clip.
You should save your Flash movie. If you compile and run the movie now, your grid will be created – you just won’t be able to tell since all the attached clips are blank.
At this point, if you’d like to see the grid, you can double-click the empty clip in the library to edit it, add a 40×40 gray rectangle (at 0,0) and then run the movie. You should see a grid of gray clips now. Be sure to remove the rectangle when you’re done.
Part C – Each clip loads images in random order, with random timing
With the grid working, and the gallery xml loading properly the final thing to do is create the Thumb class. This class will extend the MovieClip class, and bestow our empty thumb clips with additional powers. Specifically, they will randomize and store their own copy of the gallery array, and then load the images one after another, at random intervals.
To create the class (Thumb.as) you can use Flash, or any number of external editors. I prefer FlashDevelop myself, which you can find here:
If you’re using Flash, just select File > New > ActionScript File
Add the following:
class Thumb extends MovieClip
{
private var imageFolder:String; //user defined, used by onLoad to load images from the folder
private var myArray:Array; //the thumbs own randomized copy of the gallery array
private var curIndex:Number; //the current index within the gallery array - the current thumb
private var myMCL:MovieClipLoader;
private var myLis:Object; //listener for the movie clip loader
private var myTimer:Number; //random timer that calls doLoad() when it times out
private var usedClips:Array; //used image clips - used to be able to delete old images
//CONSTRUCTOR
function Thumb()
{
myMCL = new MovieClipLoader();
myLis = new Object();
myLis.classRef = this;
myLis.onLoadInit = function(){
this['classRef'].oli();
}
myMCL.addListener(myLis);
}
//local onLoadInit
function oli(){
if(usedClips.length > 1){
var d = usedClips.shift();
var i = curIndex;
d.unloadClip();
d.removeMovieClip();
}
curIndex++;
if(curIndex >= myArray.length){
curIndex = 0;
}
myTimer = _global.setTimeout(doLoad, Math.ceil(Math.random() * 3000) + 500, this);
}
//called by code that attaches thumb
function init(gallery:Array, fold:String)
{
imageFolder = fold;
myArray = new Array();
usedClips = new Array();
var tempArray:Array = gallery.slice(); //duplicate gallery
while(tempArray.length > 0){
var it = tempArray.splice(Math.floor(Math.random() * tempArray.length), 1);
myArray.push(it[0]);
}
curIndex = 0;
doLoad();
}
//internal class method that loads the current image into a new movieClip
private function doLoad(scope)
{
var cScope = scope == undefined ? this : scope;
var lastRef = cScope.createEmptyMovieClip("pic" + cScope.curIndex, 10 + cScope.curIndex);
cScope.usedClips.push(lastRef);
cScope.myMCL.loadClip(cScope.imageFolder + cScope.myArray[cScope.curIndex].image, lastRef);
}
}
OK, that’s it for the code. Save the ActionScript as Thumb.as – within your project folder. Now, every time an instance of the thumb clip is attached, this class’s constructor (the Thumb() function) will be executed. You don’t have to call it, it runs automatically. The constructor simply initializes a MovieClipLoader so that the thumb can load images. A listener is also created, which calls the class method oli() whenever a new image is loaded.
Recall that the buildGallery() function calls each thumbs init() method as it is attached. The init() method is passed the main gallery array, and a string giving the name of the folder containing the images. It stores the passed in folder name in a local class variable (so it can be used in doLoad), initializes the two arrays to empty and begins the task of randomizing the passed in gallery array. First, the array.slice method is used, which when passed no parameters returns a duplicate of the original array. You want a duplicate because arrays are passed by reference and you don’t want to alter the original. A while loops is used to iteratively get items at random places in the array, and build myArray. The array.splice method is used to return the random item, and delete it from tempArray. The item is then pushed onto myArray. The while loop continues to execute as long as there items remaining in tempArray. This suffices to shuffle the original array, storing the items in the class variable myArray. The curIndex variable is then reset to 0 and an initial call to doLoad() is made.
The doLoad method first tests the scope variable, and if undefined sets cScope to ‘this’ – class scope. If it is defined then cScope is set to it. This is done because doLoad is also called from the timeOut object and when it is ‘this’ references that object – and not the class. I solved it by passing a class reference to the method, from the timeout object. There are other ways to deal with scope issues in AS2, including the use of the Delegate class, but I chose this method. Note that doLoad is defined to be private because it shouldn’t be called from outside the class.
So, using the cScope variable a new movieClip is created within the empty thumbnail, both its new name and depth are functions of the currentIndex. A reference to the clip is pushed onto the usedClips array and then the loadClip method is called, loading the current image into the new clip.
When the image is loaded the onLoadInit method the MovieClipLoader class will be invoked, and a call to the oli() (short for onLoadInit) class method will be made. I call oli() from onLoadInit in order to invoke it in the class’ scope – otherwise the code within the oli() method would need references to any class variables or methods – because again ‘this’ within onLoadInit will refer to the loader and not the class.
The oli() method is quite simple really, it’s main function is to simply increment curIndex and then set a timeout to call onLoad after some random interval. The other thing it does is process the usedClips array. Whenever the array has more than one clip reference, the first item is removed (using array.shift), the image is unloaded and the clip is deleted. This prevents a stack of ‘pic’ clips from forming, and frees memory as well. Note that the removal of old clips works because new clip references are ‘pushed’ onto the usedClips array, and old clips are removed from the array using shift. Push adds an object to the end of the array, while shift removes an object from the beginning. The result of this push/shift is sometimes known as a LIFO, or Last In First Out.
Calling setTimeout in the _global object space is required from within a class file. It prevents the compiler from complaining that the setTimeout method is not defined.
The movie should now compile and run without problem. If you don’t have a group of thumbnails to use you can use those included in the source zip file below.
Download the source files, as well as thumbnail images here.