# Create a Responsive Image Scroller in ActionScript 3.0

This tutorial will demonstrate how to create a horizontally scrolling image viewer. It will cover xml parsing, loading and resizing external images, and creating intuitive and responsive scrolling!

## Quick Introduction

I’m a firm believer in learning by coding and tinkering. So in this tutorial, I’m stating what to do and then showing the equivalent code; please dig into the code, change things and tinker – I think that’s one of the best ways to learn! I expect that you have a basic understanding of ActionScript already and I won’t explain the fundamentals. I hope the descriptions will be helpful, but if I don’t explain something that you aren’t quite following, feel free to ask about it in the comments.

## Step 1: Set Up XML

We’ll want nodes of images included in our xml. Each node will represent an image with attributes. We can add anything we like here, I’ll stick to three attributes to each image node. The ‘src’ of the image (used to load it in), the title and the url we will link to from the scroller. I’ll go ahead and wrap them all within an images node (in case I want to include anything else in the xml later, such as customization options – hint).

Each image node will need a source image, a title and a url. The source (src) will be the image that gets loaded into the scroller, the title will be what we call it and the url will be the url that we load from the scroller when users click on the image (it can be a larger image or even a website). I’ve gotten some images from the envato asset library and resized them to be used as the thumbnails as well. I shrank the thumbnails to fit into a 140px by 105px area, this is not required but will help to optimize the experience since we won’t be loading in huge images. You’ll see soon that any size image will work because we’ll code it to resize any image that loads to fit into the scroller area!

<images>
<image src="images/tn/scottwills_underwater4.jpg" title="Jelly 4" url="images/scottwills_underwater4.jpg" />
<image src="images/tn/scottwills_cat.jpg" title="Cat" url="images/scottwills_cat.jpg" />
<image src="images/tn/scottwills_modern_sculpture.jpg" title="Statue" url="images/scottwills_modern_sculpture.jpg" />
<image src="images/tn/scottwills_penguin.jpg" title="Penguin" url="images/scottwills_penguin.jpg" />
<image src="images/tn/scottwills_horse.jpg" title="Jelly" url="images/scottwills_horse.jpg" />
<image src="images/tn/scottwills_modernsculpture2.jpg" title="Statue 2" url="images/scottwills_modernsculpture2.jpg" />
</images>

## Step 2: Set Up Flash

OK, now that we have our xml file finished, let’s get started in Flash. Open Flash and create a new file (ActionScript 3.0). Adjust the stage size to something around 600 wide and 150 tall, set the background to any color you like (I chose a dark color to help the images stand out a bit more – #000033 if you wanna follow along) and step up the frame rate to 30 frames per second to give us smoother animation. Then let’s go ahead and create a new layer calling it “ActionScript”. On the first frame in the timeline click to the actions panel and we’re ready to continue!

## Step 3: Load XML

We need to load the information from the xml file (created in step 1) into our Flash file. It’s a pretty simple step, but a foundation which can spring to many other creative applications. In just a few lines of code we initialize a URLLoader, an XML object to hold our data and a string to specify the path to the xml. Then we load the xml through the urlLoader object. That done, we need an Event listener to fire off when the file is fully loaded, we wouldn’t want to start messing with the xml data before it finishes loading. As specified in the docs, the complete event passes the loaded content as a the event target data property, so we access the actual xml as e.target.data and assign it to our xml object.

Let’s go ahead and double check that we’ve set that all up correctly and trace the image nodes of our xml to the output panel.

//load xml
var xmlData:XML = new XML();
var xmlPath:String = "image-scroller.xml";

xmlData = new XML(e.target.data);
trace(xmlData.image); //we'll see each image xml element listed in the output panel with this xmlList
}

/*
output window
///////////////
<image src="images/tn/scottwills_underwater4.jpg" title="Jelly 4" url="images/scottwills_underwater4.jpg"/>
<image src="images/tn/scottwills_cat.jpg" title="Cat" url="images/scottwills_cat.jpg"/>
<image src="images/tn/scottwills_modern_sculpture.jpg" title="Statue" url="images/scottwills_modern_sculpture.jpg"/>
<image src="images/tn/scottwills_penguin.jpg" title="Penguin" url="images/scottwills_penguin.jpg"/>
<image src="images/tn/scottwills_horse.jpg" title="Jelly" url="images/scottwills_horse.jpg"/>
<image src="images/tn/scottwills_modernsculpture2.jpg" title="Statue 2" url="images/scottwills_modernsculpture2.jpg"/>
*/


## Step 4: Parse XML

Loading the xml is great, but we also have to read it and let our code know what to do with the data. So rather than just tracing out the xmlList we’ll send it to another function that will take care of creating our scroller. The buildScroller function will accept an XMLList, so we’ll loop through it, creating movie clip objects for each image in the scroller and assigning them properties according to the xml node attributes title, url and src. Later we’ll build out this function to include much more so it will actually do what it is named for and build the scroller!

For now let’s just trace this info to make sure everything is working according to plan. We can even wrap the content buildScroller function with trace statements so we always know where we are.

//load xml
var xmlData:XML = new XML();
var xmlPath:String = "image-scroller.xml";

xmlData = new XML(e.target.data);
buildScroller(xmlData.image); //rather than trace the xmlList, we send it to our buildScroller function

}

//build scroller from xml
function buildScroller(imageList:XMLList):void{
trace("build Scroller");

for (var item:uint = 0; item < imageList.length(); item++ )  {
var thisOne:MovieClip = new MovieClip();

thisOne.itemNum = item;
thisOne.title = imageList[item].attribute("title");
thisOne.src = imageList[item].attribute("src");

trace(thisOne.itemNum, thisOne.title, thisOne.link, thisOne.src);
}

trace("termination of build scroller");
}

/*
output
///////
build Scroller
0 Jelly 4 images/scottwills_underwater4.jpg images/tn/scottwills_underwater4.jpg
1 Cat images/scottwills_cat.jpg images/tn/scottwills_cat.jpg
2 Statue images/scottwills_modern_sculpture.jpg images/tn/scottwills_modern_sculpture.jpg
4 Penguin images/scottwills_penguin.jpg images/tn/scottwills_penguin.jpg
5 Jelly images/scottwills_horse.jpg images/tn/scottwills_horse.jpg
6 Statue 2 images/scottwills_modernsculpture2.jpg images/tn/scottwills_modernsculpture2.jpg
termination of build scroller

*/

## Step 5: Build Scroller MovieClip to Contain Each Image

Now that the build scroller function is created and that it creates objects for each node in the xml, let’s add them to the stage!

We’ll begin by creating a scroller MovieClip. This will be the container for all the objects we want to scroll, so each image node will have a movieclip within this scroller object. Let’s go ahead and add it to the stage, then set the y value to 30. We won’t yet see anything on the stage when we test, but we’re about to add items to the scroller for each image in the xmlList.

var scroller:MovieClip = new MovieClip();
scroller.y = 30;


## Step 6: Adding Items to Scroller

We already have the movie clips created with properties, but we need to create something we can see, so let’s create a box area to actually see these scroller items. Create a blackBox sprite and give it a shape with the graphics api. I’ve decided that I want my standard scroller item to be 140x105px so I’ll create the blackBox to fit that area and I’ll give it a 1px border on all sides. Move it up and to the left one pixel and give it 142×107 dimensions.

We add the blackbox sprite to the thisOne movieClip and also update the x value of the item. Since each will be 140 wide, I’ll add some padding (20) and lay them out horizontally. I’ll update the trace statement to output what is going on here.

var scroller:MovieClip = new MovieClip();
scroller.y = 30;
//build scroller from xml
function buildScroller(imageList:XMLList):void{
trace("build Scroller");
for (var item:uint = 0; item < imageList.length(); item++ )  {
var thisOne:MovieClip = new MovieClip();

//outline
var blackBox:Sprite = new Sprite();
blackBox.graphics.beginFill(0xFFFFFF);
blackBox.graphics.drawRect( -1, -1, 142, 107);

thisOne.x = (140 + 20) * item;
thisOne.itemNum = item;
thisOne.title = imageList[item].attribute("title");
thisOne.src = imageList[item].attribute("src");

trace(thisOne.itemNum, thisOne.title, " added to scroller");

}
trace("termination of build scroller");
}
/*
output
///////
build Scroller
0 Jelly 4  added to scroller
1 Cat  added to scroller
2 Statue  added to scroller
3 Arch 3  added to scroller
4 Penguin  added to scroller
5 Jelly  added to scroller
6 Statue 2  added to scroller
7 Arch 1  added to scroller
8 Arch 2  added to scroller
termination of build scroller
*/


## Step 7: Adding Click Listener to Items

Alright, this isn’t much yet because it just looks like a bunch of boxes that don’t do anything. Let’s add a listener to these boxes though, so that we can tell that they are each unique items in the scroller. Thinking of the final result, we’ll add a click listener because we want users to be able to click the item in the scroller and go to the link we put in the xml. Let’s make the clip buttonMode true, so that it’s perceived as something that is click-able. Then add an event Listener for the MouseEvent.CLICK. For now we’ll just have it listen for this click event and fire a function to trace the url we’re aiming at.

Through the output we can see that each box has properties sent to it from the xml.

//build scroller from xml
function buildScroller(imageList:XMLList):void{
trace("build Scroller");
for (var item:uint = 0; item < imageList.length(); item++ )  {
var thisOne:MovieClip = new MovieClip();

//outline
var blackBox:Sprite = new Sprite();
blackBox.graphics.beginFill(0xFFFFFF);
blackBox.graphics.drawRect( -1, -1, 142, 107);

thisOne.x = (140 + 20) * item;
thisOne.itemNum = item;
thisOne.title = imageList[item].attribute("title");
thisOne.src = imageList[item].attribute("src");

//create listeners for this item
thisOne.buttonMode = true;

}

trace("termination of build scroller");
}

function clickScrollerItem(e:MouseEvent):void {
trace("clicked item " + e.currentTarget.itemNum + " - visit url: " + e.currentTarget.link);
}

/*
output
//////
build Scroller
termination of build scroller
clicked item 2 - visit url: images/scottwills_modern_sculpture.jpg
clicked item 0 - visit url: images/scottwills_underwater4.jpg
clicked item 1 - visit url: images/scottwills_cat.jpg
clicked item 3 - visit url: images/madness_arch3.jpg
clicked item 1 - visit url: images/scottwills_cat.jpg
*/

## Step 8: Adding More Listeners to Scroller Items

Let’s finish off the event listeners! We’ll want to listen to each of these items to know when a user clicks, mouses over and mouses out.

//build scroller from xml
function buildScroller(imageList:XMLList):void{
trace("build Scroller");
for (var item:uint = 0; item < imageList.length(); item++ )  {
var thisOne:MovieClip = new MovieClip();

//outline
var blackBox:Sprite = new Sprite();
blackBox.graphics.beginFill(0xFFFFFF);
blackBox.graphics.drawRect( -1, -1, 142, 107);

thisOne.x = (140 + 20) * item;
thisOne.itemNum = item;
thisOne.title = imageList[item].attribute("title");
thisOne.src = imageList[item].attribute("src");

//create listeners for this thumb
thisOne.buttonMode = true;

}

trace("termination of build scroller");
}

function clickScrollerItem(e:MouseEvent):void {
trace("clicked item " + e.currentTarget.itemNum + " - visit url: " + e.currentTarget.link);
}
function overScrollerItem(e:MouseEvent):void {
trace("over " + e.currentTarget.title);
}
function outScrollerItem(e:MouseEvent):void {
trace("out " + e.currentTarget.title);
}
/* output
//////////////
build Scroller
termination of build scroller
over Jelly 4
out Jelly 4
over Cat
out Cat
over Statue
out Statue
over Arch 3
out Arch 3
over Arch 3
clicked item 3 - visit url: images/madness_arch3.jpg
out Arch 3
over Statue
clicked item 2 - visit url: images/scottwills_modern_sculpture.jpg
out Statue
*/


Now the part I’m sure you’ve been getting anxious about, let’s get the images loaded into the scroller items so we can see what they are! We’ll do this in the buildScroller function. Right after the blackbox is created and the properties are assigned for the current item let’s also create another sprite to contain the actual image.

We’ll use a loader object and a URLRequest object to handle the loading of the image, which is newly standardized with ActionScript 3. We’ll pass the src of the image to the urlrequest object, then load the urlrequest with our loader object and finally we’ll add the loader to the thisThumb sprite adding that in turn to the thisOne movieClip. Whew.

It’s pretty self explanatory – and in just a couple of lines of code we’ve loaded the src images from our xml into Flash!

function buildScroller(imageList:XMLList):void{
trace("build Scroller");
for (var item:uint = 0; item < imageList.length(); item++ )  {
var thisOne:MovieClip = new MovieClip();

//outline
var blackBox:Sprite = new Sprite();
blackBox.graphics.beginFill(0xFFFFFF);
blackBox.graphics.drawRect( -1, -1, 142, 107);

thisOne.x = (140 + 20) * item;
thisOne.itemNum = item;
thisOne.title = imageList[item].attribute("title");
thisOne.src = imageList[item].attribute("src");

//image container
var thisThumb:Sprite = new Sprite();
var urlReq:URLRequest = new URLRequest(thisOne.src);
trace("loading thumbnail "+item+" into Scroller: " + thisOne.src);

//create listeners for this thumb
thisOne.buttonMode = true;

}

trace("termination of build scroller");
}


## Step 10: Adding Event Listeners to the Image Loading Process

When we load the images, we need to create some event listeners to tell us when the loading is complete. Best practice deal with any errors (in case there is a typo in the path to the image or we don’t have access or something). So just before we load the images let’s add an event listener for the loader’s contentLoaderInfo object for a complete event and also an i/o error. Then we’ll need to create the event handler functions.

For the completeHandler let’s just trace the image title for now, we’ll have to walk up the hierarchy of the event target’s parent’s parent’s title to find it, because of the way we nested our sprite within our scroller item objects (the thisOne Sprite).

trace("loading thumbnail "+item+" into Scroller: " + url);
//assign event listeners for Loader
...
function completeHandler(e:Event):void {
}
function errorHandler(e:IOErrorEvent):void {
trace("thumbnail error="+e);
}


## Step 11: Tweening the Images

I’m using Tweener for this tutorial, but there are various tweening engines. If you’re not familiar with it

Tweener (caurina.transitions.Tweener) is a Class used to create tweens and other transitions via ActionScript code for projects built on the Flash platform… In layman’s terms, Tweener helps you move things around on the screen using only code, instead of the timeline.

So first go download it from the google code repository (be sure to get the as3 version) unzip it and put the caurina folder into the same directory as your .fla file, then import the code into your project by placing this in the first line of code:

import caurina.transitions.*;

Then let’s have the images fade in once they’re loaded, instead of just popping like they are. First we’ll set the initial alpha value of the scroller item to 0, so it can fade in properly. Then jump back to our complete event listener handler function and add the Tweener code.

thisOne.alpha = 0;
...
function completeHandler(e:Event):void {
Tweener.addTween(e.target.loader.parent.parent, { alpha:1, time: .5 } );
}


## Step 12: Resizing the Images

Now, since I resized all my images and created thumbnails beforehand, this step is not as important, but is still great to include so that in case the dimensions change or I add another image later, the scroller will be able to handle it and resize it. The resize function will scale an image to fit within an area as I have explained before on my blog. Basically though, in the completeHandler we’ll resize the image to fit an area, even if the image is correctly sized, the resizeMe function will still center the image for us.

function completeHandler(e:Event):void {
//size image into scroller
resizeMe(e.target.loader.parent, 140, 105, true, true, false);
Tweener.addTween(e.target.loader.parent.parent, { alpha:1, time: .5 } );
}

//The resizing function
// parameters
// required: mc = the movieClip to resize
// required: maxW = either the size of the box to resize to, or just the maximum desired width
// optional: maxH = if desired resize area is not a square, the maximum desired height. default is to match to maxW (so if you want to resize to 200x200, just send 200 once, or resizeMe(image, 200);)
// optional: constrainProportions = boolean to determine if you want to constrain proportions or skew image. default true.
// optional: centerHor = centers the displayObject in the maxW area. default true.
// optional: centerVert = centers the displayObject in the maxH area. default true.
function resizeMe(mc:DisplayObject, maxW:Number, maxH:Number=0, constrainProportions:Boolean=true, centerHor:Boolean=true, centerVert:Boolean=true):void{
maxH = maxH == 0 ? maxW : maxH;
mc.width = maxW;
mc.height = maxH;
if (constrainProportions) {
mc.scaleX < mc.scaleY ? mc.scaleY = mc.scaleX : mc.scaleX = mc.scaleY;
}
if (centerHor) {
mc.x = (maxW - mc.width) / 2;
}
if (centerVert){
mc.y = (maxH - mc.height) / 2;
}
}


## Step 13: Adding Movement

We’ll start by just adding the basics. We want users to be able to intuitively control this scroller, so we’ll use their mouse position as direction only initially. If the mouse is positioned in the left half of the stage we want to move the scroller to the right, so the user moves in the direction they want the scroller to reveal itself. I prefer this to the direct relationship of moving the scroller the same way the mouse goes, but that’s a discussion for another day.

To implement this is pretty simple, we just add an event listener at the end of the buildScroller function, for every time we enter the frame to position the scroller. Then in the handler function we’ll create an if/else statement and set the new speed variable depending on mouse position. If the mouse x position is on the left half of the stage, we want the scroller to move one way and if it is on the right half of the stage we want it to move the other direction. Then we apply this speed to the x position of the scroller container. This is now starting to look like something useful because it is now interactive and responsive!

Essentially all we are doing is moving the scroller container clip to one direction of the other, but we’re doing it every frame, so it animates the position over time. Remember this scroller clip contains all the items we created, so it’s like putting things into a box and moving the box. The items don’t have to be moved, just the container! We move it either 5 pixels to the left or 5 pixels to the left every single frame (this 5 could be anything, I just chose 5 ’cause it looked right). This leaves a lot to be desired, but it’s the first step. We have our scroller moving and have given the end user the power to control this movement!

Notice that we’re using the stage properties to find the stage size even though we set the stage size earlier and know exactly what size it is. This is because it will help the code to be self containing and portable. If we were to use the actual values we would have to remember to update them if we ever changed the scroller size or wanted to use this in a different application. We’ll create more variables soon that will allow us to fully customize the scroll interaction.

scroller.addEventListener(Event.ENTER_FRAME, moveScrollerThumbs);
trace("termination of build scroller");
...
var speed:Number;
function moveScrollerThumbs(e:Event):void {
if (mouseX < stage.stageWidth/2) { //left half of stage
speed = 5;
}
else { //right half of stage
speed = -5;
}
scroller.x += speed;
}


## Step 14: Better Movement – Mouse Limits

You can see above that we still have a way to go with our movement controls of the scroller. There are boundaries to add to the mouse positions that cause the scrolling (we’d like it to only scroll when you are on the stage and over the scroller), limits we’d like to apply to the scroller (so that it doesn’t scroll off the page) and we want to make the scroller speed dynamic.

Let’s start first by adding a statement to check if we are over the scroller. To do this we’ll check the mouseY position, the scroller.y and scroller.height properties. Let’s also add a bit more to the mouseX statements, let’s ensure that it’s a bit more precise and only include the x values from 0 to the center of the stage (stage.stageWidth/2) and from the center to the edge.

function moveScrollerThumbs(e:Event):void {
if ( mouseY > scroller.y && mouseY < scroller.y + scroller.height) { //vertically over scroller
if (mouseX < stage.stageWidth/2 && mouseX > 0) { //left half of stage explicitly
speed = 5;
}
else if (mouseX > stage.stageWidth/2 && mouseX < stage.stageWidth) { //right half of stage explicitly
speed = -5;
}
scroller.x += speed;
}
}


## Step 15: Better Movement – Scroller Limits

Now we’ll want to apply boundaries to the scroller itself so that it doesn’t scroll off the page and leave us with a blank stage and a user who doesn’t know or remember which way the images went.

We need to watch the scroller x position and if it goes too far either way reset it to our limit. Remember that the scroller x position is found at its left edge, so when it is at a 0 x position it is flush with the left edge of the stage. So first off if the x position of the scroller is greater than 0 after the speed is calculated and applied, we want to set it back to our limit, 0. This will keep the scroller from moving too far into the stage. We can even add some padding to the stage and since we have the padding between each scroller item of 20, let’s make it consistent. Rather than using 0 here, let’s make it the same 20 value.

We want the scroller to stop moving left once it’s last item is fully on stage. This left limit can be found by finding the width of the scroller and the stage width. If the scroller is moved so far to the left that it’s x position is less than it’s own width (negative) but factor back in the stage width (plus stageWidth) we need to hold it right there. To add the padding on this end we subtract 20.

function moveScrollerThumbs(e:Event):void {
if ( mouseY > scroller.y && mouseY < scroller.y + scroller.height) {//vertically over scroller
if (mouseX < stage.stageWidth/2 && mouseX > 0) {//left of stage explicitly
speed = 5;
}
else if (mouseX > stage.stageWidth/2 && mouseX < stage.stageWidth) {//right of stage explicitly
speed = -5;
}
scroller.x += speed;

//scroller limits
if (scroller.x < -scroller.width + stage.stageWidth - 20) { //if scroller too far left
scroller.x = -scroller.width + stage.stageWidth - 20;
}
else if (scroller.x > 20) { //if scroller to far right
scroller.x = 20;
}
}
}


## Step 16: Dynamic Movement

To make the movement more fluid and dynamic we only need to update two lines of code. You guessed it, the two lines that set the speed need to be adjusted to determine the speed by the distance mouseX is from the center of the stage rather than a flat value of 5. We find the distance the mouse is horizontally from the center axis of the stage (stage.stageWidth/2), and we want the scroller to move to the right if we’re on the left side and vice versa. In both instances we find the negative difference between the two. Then we should scale it down by dividing it by, let’s try 8, because if we don’t, the scroller is way too fast (go ahead, try it).

function moveScrollerThumbs(e:Event):void {
if ( mouseY > scroller.y && mouseY < scroller.y + scroller.height) {//vertically over scroller
if (mouseX < stage.stageWidth/2 && mouseX > 0) {//left of stage explicitly
speed = -(mouseX - stage.stageWidth/2) / 8;
}
else if (mouseX > stage.stageWidth/2 && mouseX < stage.stageWidth) {//right of stage explicitly
speed = -(mouseX - stage.stageWidth/2) / 8;
}
scroller.x += speed;

//scroller limits
if (scroller.x < -scroller.width + stage.stageWidth - 20) { //if scrolled too far left
scroller.x = -scroller.width + stage.stageWidth - 20;
}
else if (scroller.x > 20) { //if scrolled to far right
scroller.x = 20;
}
}
}


## Step 17: User Friendly Movement

Now test this and think about your end user. You’ll be looking at this image scroller and maybe wanting to look a bit closer or focus in on an image that catches your eye. You want this scroller to stop moving, (if I move to the center of the stage it still drifts to one side of the other) and I focus more on fighting the scroller than I do on the image I want to look at.

This is an example of a non-transparent user control. We want the user to be able to intuitively use this scroller to the point that they don’t even think about it. If the user has to think about it, or even worse, fight your app to get it to do something, you lose and they will look elsewhere for their content. So let’s avoid the struggle and give the scroller a dead area at the center of the stage. Then they can rest at ease by moving to the center of the scroller to inspect something or stop the motion sickness. It’s a really easy thing to do and has a big payoff, making the scroller easier to use. Rather than using the center of the stage for all our calculations we’ll give it some padding.

function moveScrollerThumbs(e:Event):void {
if ( mouseY > scroller.y && mouseY < scroller.y + scroller.height) {//vertically over scroller
if (mouseX < stage.stageWidth/2 - 40 && mouseX > 0) {//left of stage explicitly
speed = -(mouseX - (stage.stageWidth/2 - 40)) / 8;
}
else if (mouseX > stage.stageWidth/2 + 40 && mouseX < stage.stageWidth) {//right of stage explicitly
speed = -(mouseX - (stage.stageWidth/2 + 40)) / 8;
}
else {
speed = 0; //if in the center area, clear the speed to 0 so we don't have any roll over effect from the last frame.
}
scroller.x += speed;

//scroller limits
if (scroller.x < -scroller.width + stage.stageWidth - 20) { //if scrolled too far left
scroller.x = -scroller.width + stage.stageWidth - 20;
}
else if (scroller.x > 20) { //if scrolled to far right
scroller.x = 20;
}
}
}


## Step 18: Abstracting Movement More

Let’s abstract this out a bit. We have multiple places where we are adding padding to values or measurements. It’d be best practice to create a variable to hold our padding value and apply the same value easily by applying the variable every time we want padding. This would help us update if a client later says “I like it, but can we spread it out some?” or the dreaded… “Something’s off about this…”, then we’d just update the variable and it would be ready to go. I always try to create controls for myself, the programmer, to make it easy to customize a project.

I’ve created a variable named “padding” here and am applying it everywhere that makes sense. Notice that in a couple places I multiply it by 2, use your own judgment here – if you want more padding give it more, of course we could take it further and have a “padding_small” variable and another “padding_large” variable, but one will do justice for the purpose of this tutorial. You get the idea. This doesn’t really change the end file, but it can help to make your life much easier and your code simpler, more understandable or readable.

import caurina.transitions.*;

var xmlData:XML = new XML();

var xmlPath:String = "image-scroller.xml";

xmlData = new XML(e.target.data);
//trace(xmlData.image);
buildScroller(xmlData.image);
}

var scroller:MovieClip = new MovieClip();
var speed:Number;
var padding:Number = 20;

scroller.y = scroller.x = padding;
//build scroller from xml
function buildScroller(imageList:XMLList):void{
trace("build Scroller");
for (var item:uint = 0; item < imageList.length(); item++ )  {
var thisOne:MovieClip = new MovieClip();

//outline
var blackBox:Sprite = new Sprite();
blackBox.graphics.beginFill(0xFFFFFF);
blackBox.graphics.drawRect( -1, -1, 142, 107);

thisOne.x = (140 + padding) * item;
thisOne.itemNum = item;
thisOne.title = imageList[item].attribute("title");
thisOne.src = imageList[item].attribute("src");

//image container
var thisThumb:Sprite = new Sprite();
var urlReq:URLRequest = new URLRequest(thisOne.src);
trace("loading thumbnail "+item+" into Scroller: " + thisOne.src);
//assign event listeners for Loader

//create listeners for this thumb
thisOne.buttonMode = true;

}

trace("termination of build scroller");
}

function overScrollerItem(e:MouseEvent):void {
trace("over" + e.currentTarget.name);
}
function outScrollerItem(e:MouseEvent):void {
trace("out" + e.currentTarget.name);
}
function clickScrollerItem(e:MouseEvent):void {
trace("clicked item " + e.currentTarget.itemNum + " - visit url: " + e.currentTarget.link);
}
function completeHandler(e:Event):void {
//size image into scroller
resizeMe(e.target.loader.parent, 140, 105, true, true, false);
Tweener.addTween(e.target.loader.parent.parent, { alpha:1, time: .5 } );
}
function errorHandler(e:IOErrorEvent):void {
trace("thumbnail error="+e);
}

//The resizing function
// parameters
// required: mc = the movieClip to resize
// required: maxW = either the size of the box to resize to, or just the maximum desired width
// optional: maxH = if desired resize area is not a square, the maximum desired height. default is to match to maxW (so if you want to resize to 200x200, just send 200 once)
// optional: constrainProportions = boolean to determine if you want to constrain proportions or skew image. default true.
function resizeMe(mc:DisplayObject, maxW:Number, maxH:Number=0, constrainProportions:Boolean=true, centerHor:Boolean=true, centerVert:Boolean=true):void{
maxH = maxH == 0 ? maxW : maxH;
mc.width = maxW;
mc.height = maxH;
if (constrainProportions) {
mc.scaleX < mc.scaleY ? mc.scaleY = mc.scaleX : mc.scaleX = mc.scaleY;
}
if (centerHor) {
mc.x = (maxW - mc.width) / 2;
}
if (centerVert){
mc.y = (maxH - mc.height) / 2;
}
}

function moveScrollerThumbs(e:Event):void {
if ( mouseY > scroller.y && mouseY < scroller.y + scroller.height) {//vertically over scroller
if (mouseX < stage.stageWidth/2 - padding*2 && mouseX > 0) {//left of stage explicitly
speed = -(mouseX - (stage.stageWidth/2 - padding*2)) / 8;
}
else if (mouseX > stage.stageWidth/2 + padding*2 && mouseX < stage.stageWidth) {//right of stage explicitly
speed = -(mouseX - (stage.stageWidth/2 + padding*2)) / 8;
}
else {
speed = 0;
}
scroller.x += speed;

//scroller limits
if (scroller.x < -scroller.width + stage.stageWidth - padding) { //if scrolled too far left
scroller.x = -scroller.width + stage.stageWidth - padding;
}
else if (scroller.x > padding) { //if scrolled to far right
}
}
}


## Step 19: Adding Scale Tweens

With this idea of using variables to customize our file, let’s add some bling with the Tweener library we already added. It’s great to call out the item in the scroller the user rolls over, so let’s have it scale a bit larger to help it stand out. This is where the beauty of Tweening comes in. Just one line of code, some variables and we can tell it to tween the scaleX and scaleY of the scroll item. If we’re scaling the item we’ll want to also translate its coordinates a bit so the item is still centered, this looks like tricky math, but it’s actually pretty simple.

First, we add a variable to each object to store it’s starting x position, we can just call it myx and put it on the same line where we calculate the x (we do this so we can reliably move the item back to it’s rightful place when we need to). We need to move it so the item is still centered, so we find its current width and factor it by half the scale we are applying. We do this for x and y. Then we need to tween it back to its starting size and coordinates on the mouse out event handler.

thisOne.x = thisOne.myx = (140 + padding) * item;
...
var thumbSmall:Number = 1;
var thumbLarge:Number = 1.1;
function overScrollerItem(e:MouseEvent):void {
//trace("over" + e.currentTarget.name);
Tweener.addTween(e.currentTarget, { scaleX:thumbLarge, scaleY:thumbLarge, x:e.currentTarget.myx - e.currentTarget.width * Math.abs(thumbSmall - thumbLarge)/2, y: -e.currentTarget.width * Math.abs(thumbSmall - thumbLarge)/2, time:1 } );
}
function outScrollerItem(e:MouseEvent):void {
//trace("out" + e.currentTarget.name);
Tweener.addTween(e.currentTarget, { scaleX:thumbSmall, scaleY:thumbSmall, x:e.currentTarget.myx, y:0, time:1 } );
}


## Step 20: Adding Border Tweens

Let’s make them stand out even more by fading the white ‘blackBox’ around the thumbnails (just realizing that I named the white box black =) ). This one is easier than the previous step. Just add a couple of variables for the fade in and out values (alpha) and add the Tweens to both the over and out event listener handler function. We’ll also need to ensure that we can address the blackBox sprite so when we initialize it let’s explicitly name it. While we’re at it we can set the initial alpha of the box to equal the thumbFadeOut variable.

//outline
var thumbFadeOut:Number = .2;
var thumbFadeIn:Number = 1;
var thumbSmall:Number = 1;
var thumbLarge:Number = 1.1;
...
var blackBox:Sprite = new Sprite();
blackBox.graphics.beginFill(0xFFFFFF);
blackBox.graphics.drawRect( -1, -1, 142, 107);
thisOne.blackBox = blackBox;
...
function overScrollerItem(e:MouseEvent):void {
//trace("over" + e.currentTarget.name);
Tweener.addTween(e.currentTarget, { scaleX:thumbLarge, scaleY:thumbLarge, x:e.currentTarget.myx - e.currentTarget.width * Math.abs(thumbSmall - thumbLarge)/2, y: -e.currentTarget.width * Math.abs(thumbSmall - thumbLarge)/2, time:1 } );
Tweener.addTween(e.currentTarget.blackBox, { alpha:thumbFadeIn, time: 1 } );
}
function outScrollerItem(e:MouseEvent):void {
//trace("out" + e.currentTarget.name);
Tweener.addTween(e.currentTarget, { scaleX:thumbSmall, scaleY:thumbSmall, x:e.currentTarget.myx, y:0, time:1 } );
Tweener.addTween(e.currentTarget.blackBox, { alpha:thumbFadeOut, time: 1 } );
}


## Step 21: Adding Link on Click

Speaking of all the event listeners, we still haven’t finished coding the click event. We want to have the click basically be a link click and link the user to the url specified in the xml. For this, we just pass the link value from the event’s target that we are currently tracing, to a URLRequest object and try to navigate to it with our friend navigateToURL. There we have it.

function clickScrollerItem(e:MouseEvent):void {
//trace("clicked item " + e.currentTarget.itemNum + " - visit url: " + e.currentTarget.link);
var urlRequest:URLRequest = new URLRequest(e.currentTarget.link);
try {
navigateToURL(urlRequest);
}
catch (e:Error) {
// handle error here
trace(e);
}
}


## Conclusion

I hope you enjoyed this tutorial and that you learned something. You should now have a pretty good grasp on AS3 and xml, loading and resizing images, easy animating with tweening, mouse event listeners, scrolling and user friendly interactive design!

Was it easy to follow? I usually do tutorials in open source examples so I don’t know if I droned on too much here.. Feel free to let me know in the comments. This tutorial is meant to be a spring board for ideas; there are tons of other things we could to with this file and get many other effects going, but this should get you started!

Evan Mullins is circlecube on Activeden
• Moh

Great tutorial!

would that be possible if I use this scripts to do the scrolling effect which not have the xml supported image but a single movie clip like “scroller” in which a big image has been inserted.

What I made is a big image bigger than my stage size. Whenever I go to the edge it will scroll the image as same as it is. I belive I made it pretty clear…. any solution….would be very helpfull…i am new and i need this very awefully…

• Camello

How to increment, preloaders into objects?

• kishan patel

Really very nice tutorial,
It gives a fundamental things which are newbee to as3..

• justin

How can I make this a vertical slider?

• ville

Hi, I tried putting text in the image, as mouseover the image enlarged the text seemed blur or distorted. Do you experienced this?

Can I load the images into a different X and Y coordinates besides 0:0?

Basically I would like to center everything.

thanks!

• Angie

I would like to take a moment and thank you for the great tutorial! There are several places where I can just go and download the FLA file and make it work (and not learn much) but I’d rather go through tutorials, such as yours, where it’s broken down into steps. So, maybe, the next time I need to complete a project I will have a basic understanding of the concepts. Well done on a great tutorial! I love the explanations and the comments in the code. I look forward to other tutorials that you have created.

• Cata

Very nice tut guys. I did some change to the code and it works supper. I am trying to integrate a reflection (pixelfumes) to my mc and I’m having a hard time. Can you please help?

• Cata

This is my source code.
thanks

import caurina.transitions.*;
import ASWC.*;
import com.pixelfumes.Reflect;

var xmlData:XML = new XML();

var xmlPath:String = “image-scroller.xml”;

xmlData = new XML(e.target.data);
//trace(xmlData.image);
buildScroller(xmlData.image);
}

var scroller:MovieClip = new MovieClip();
var speed:Number;
var padding:Number = 10;
var thumbFadeOut:Number = .2;
var thumbFadeIn:Number = 1;
var thumbSmall:Number = 1;
var thumbLarge:Number = 1.1;
scroller.y = 221.5;
//build scroller from xml
function buildScroller(imageList:XMLList):void{
trace(“build Scroller”);
for (var item:uint = 0; item < imageList.length(); item++ ) {
var thisOne:MovieClip = new MovieClip();

//outline
var blackBox:Sprite = new Sprite();
blackBox.graphics.beginFill(0xFFFFFF);
blackBox.graphics.drawRect( -1, -1, 142, 107);

thisOne.x = thisOne.myx = (140 + padding) * item;
thisOne.itemNum = item;
thisOne.title = imageList[item].attribute("title");
thisOne.src = imageList[item].attribute("src");

//image container
var thisThumb:Sprite = new Sprite();
var urlReq:URLRequest = new URLRequest(thisOne.src);
trace("loading thumbnail "+item+" into Scroller: " + thisOne.src);
//assign event listeners for Loader

// by Damien
// this initializes the alpha value for each movie clip

//create listeners for this thumb
thisOne.buttonMode = true;

}

trace("termination of build scroller");
}

function overScrollerItem(e:MouseEvent):void {
//trace("over" + e.currentTarget.name);
Tweener.addTween(e.currentTarget, { scaleX:thumbLarge, scaleY:thumbLarge, x:e.currentTarget.myx – e.currentTarget.width * Math.abs(thumbSmall – thumbLarge)/2, y: -e.currentTarget.width * Math.abs(thumbSmall – thumbLarge)/2, time:1 } );
//Tweener.addTween(e.currentTarget.blackBox, { alpha:thumbFadeIn, time: 1 } );
Tweener.addTween(e.currentTarget, { alpha:thumbFadeIn, time: 1 } );
}
function outScrollerItem(e:MouseEvent):void {
//trace("out" + e.currentTarget.name);
Tweener.addTween(e.currentTarget, { scaleX:thumbSmall, scaleY:thumbSmall, x:e.currentTarget.myx, y:0, time:1 } );
//Tweener.addTween(e.currentTarget.blackBox, { alpha:thumbFadeOut, time: 1 } );
Tweener.addTween(e.currentTarget, { alpha:thumbFadeOut, time: 1 } );
}
function clickScrollerItem(e:MouseEvent):void {
trace("clicked item " + e.currentTarget.itemNum + " loadImage: " + e.currentTarget.link);

// creates a uiloader object
// when images are loaded, maintain there aspect ratio
// scales the image to the size of the uiloader object
// set the uiloader source property to the link value from the xml document
// create a clicked event for the uiloader object
// set the location of the uiloader object to the top left of the screen
// set the size of the uiloader object
// add the uiloader object to the stage
}

function closeImage(e:MouseEvent):void {
}

function completeHandler(e:Event):void {
//size image into scroller
resizeMe(e.target.loader.parent, 140, 105, true, true, false);
// I commented this out as I initialized the alpha when it was added to the scroller
//Tweener.addTween(e.target.loader.parent.parent, { alpha:1, time: .5 } );
var image:Bitmap=Bitmap(e.target.content);
image.smoothing=true;
//this should smooth the image when they resize
}

function errorHandler(e:IOErrorEvent):void {
trace("thumbnail error="+e);
}

//The resizing function
// parameters
// required: mc = the movieClip to resize
// required: maxW = either the size of the box to resize to, or just the maximum desired width
// optional: maxH = if desired resize area is not a square, the maximum desired height. default is to match to maxW (so if you want to resize to 200×200, just send 200 once)
// optional: constrainProportions = boolean to determine if you want to constrain proportions or skew image. default true.
function resizeMe(mc:DisplayObject, maxW:Number, maxH:Number=0, constrainProportions:Boolean=true, centerHor:Boolean=true, centerVert:Boolean=true):void{
maxH = maxH == 0 ? maxW : maxH;
mc.width = maxW;
mc.height = maxH;
if (constrainProportions) {
mc.scaleX scroller.y && mouseY < scroller.y + scroller.height) {//vertically over scroller
if (mouseX 0) {//left of stage explicitly
speed = -(mouseX – (stage.stageWidth/2 – padding*2)) / 8;
}
else if (mouseX > stage.stageWidth/2 + padding*2 && mouseX < stage.stageWidth) {//right of stage explicitly
speed = -(mouseX – (stage.stageWidth/2 + padding*2)) / 8;
}
else {
speed = 0;
}
scroller.x += speed;

//scroller limits
if (scroller.x padding) { //if scrolled to far right
}
}
}

• Matt

First as always thank you for putting this up.

I have a question though, how would I change this so that, when an image is clicked, instead of it going to a larger version, it goes to a webpage with in my site. How would I do that, and how would I do it on a wordpress site?

• Matt

How can I change the XML file so that instead of going to the picture when the image is clicked it goes to a page with in my website? I’ve tried url=”http://www.website.com” and it doesn’t work. How can I change this?

• Rolf

This helped a lot! thanks.
the gallery works great into flash but if i publish it it gives an error.

Error #2044: Unhandled ioError:. text=Error #2032: Stream Error. URL: gallery.xml
at site_fla::contentvillabeschrijving_61/frame1()
at flash.display::MovieClip/gotoAndStop()
at site_fla::site_1/clickSection()

annybody a clue what could couse this error becouse the path of the xml file is correct.

• Pingback: XML Gallerie - Flashforum

• Jimbob

Thanks for doing a great tutorial. Not many good ones about on this subject.

• http:www Jota

Hi! Great work!

I’ve changed the thisOne.myx so that each mc appears over the next one, but i want to give the highest depth to the mc with mouse over. How do i make this?

Thank you.

• maria porto

Does anyone knows how to load this into a movieclip? I’ve tried and I can’t make it load at all!

Thanks.

• Dan M

Awesome work. Thanks a lot.

• ejfin

Amazing walk-through, thank you! Manipulation question here: Is there any way to make the image gallery begin scrolling automatically (after loading completes) without using a frame interaction (ENTER_FRAME) based on users mouse coordinates? And then, is there any way to make the automatically scrolling images loop continuously (ie; image [0], [1], [2], [3], [0], [1], [2], [3], [0]….). Is it possible? Would it require creating an Array? and would that Array need to replace parts of step 7? Obviously, I am not expecting anyone to write me the code, but a point in the right direction would be wonderful. I have run out of ideas to try.

• Anna

I need that same effect but that images movement will continuous to reach the last image appear again all from the first image.

• Vivek_Yoganand

hey how to run the scrolling at bottom 0f the stage now it running at top of the stage.
plz reply to my mail…

• http://www.wildskydesigns.com/mcguinnFarms/index.html zeroqs

Hi and thanks for this excellent tutorial.

I apologize, AS3 is new to me. I am trying to get the image link to jump to a position number in a scrolling window instead of an image or a new URL. I’d like to know what needs to be altered to make this happen.

I have attached a link to a test site. The home page works OK with the exception of it opening a new window or tab. When you click on the scrolling menu you jump to a new page. Now a new menu should appear. If it was there you would click on an image in the new menu and the page content would scroll to the item you selected. I have place temporary buttons just above the area to be scrolled so you can see what should happen.

http://www.wildskydesigns.com/mcguinnFarms/index.html

Any help would greatly be appreciated.

Zeroqs

• Patrik

Excellent tutorial!
Is it possible to load the thumbnails with dynamic width? (i dont want to resize them to the same size)

Thanks

• Patrik

Kinda sorted it out by adding thumbnail-width to the xml
Would be nice without having to put width in xml tho.. =)

• Vanderknot

finally!!! a great tutorial explaining step by step. I just have some doubts but I think I’ll manage trough.
THX!

• http://www.alkoty.com Al Koty

How could I take this vertical scroller and contain it in another MovieClip, and mask it off for dragging it around and placing it on the stage of another .fla file?

How would I need to go about modifying this example tutorial code?

• http://www.eloanguiano.com EloAnguiano

This is PURE GOLD!!!!! A Relief in the days of darkness with the LIMIT DATE getting closer and closer aaaahhh!! Thank u very much. And i apreciate a lot that u took the time to divide the code into STEPS, that makes is easier to understand. :D

Hi thank you very much for ur tutorial.i made vertical scroller with image slide show from this tutorial.if anybody interest i can share it.cheers…!

• Niek

im interrested in the vertical scroller, can u share it with me.

thx

• Suzieq

This is great..thanks for posting. But what if there were multiple or more than one xml files? How would you go about that? Please answer ASAP

• fandhie

great tutorial.
I’m new in flash, may I ask how to add image title below every image?

thanks,
fandhie

• closey

Thank you for the fantastic tutorial, has been a great foundation to build on.

I have used this image scroller to open the full size image above the thumbnails, instead of a url. I am looking to use the full size images as the thumbnails so the user didn’t have to load each large image as they click it. However, while the images are all added sequentially, they will appear based on whichever one is loaded first. I would like them to actually appear/load sequentially, so the user can start clicking through the images while the others continue to load.

I am pretty new to AS3, is there a way to do this?

Thanks again.

• http://viagravillage.com/ viagra

excellent article. But I need more written

• bibson

Hi guys,
Nice tuto, Anybody know how to put the xml title on the thumbnails ?

• Richer

I found this Image Scroller http://www.flashxml.net/image-scroller.html and it’s probably the best thing that is found for my needs. I gladly recommend you this product. It is very easy to use and you can customize a lot of it. Good luck, hope it will help somebody.

• Karl

Thanks, you link helped me a lot. Got all lost in the code [i'm not the best programmer this world has seen] and was staring stupid at the computer screen. I thought I’d see the comments, and voila, you link. Now it’s set up and looks nice!
So, thanks a lot… and you were right, looks like one of the best scrollers on the net.

• rob

Your tutorial is one of the most comprehensive tutorials I ever seen but I am a novice when it comes about programming and I couldn’t make it to work. Richer shared a link in a comment above, it’s about flashxml.net, I have visited that website and I was really impressed. Their flash components are very customizable, using just the xml files, I recommend it, too.

• Nikolai

I am going through your tutorial and have a question. In your example it is assumed that images are uniformly scaled at 140x105px.
In my set up I have various image width and identical height. How would I alter the code to accommodate that each image has a different width?
As I understand it has to be altered in the step 6 which contains the code below:

var scroller:MovieClip = new MovieClip();
scroller.y = 30;
//build scroller from xml
function buildScroller(imageList:XMLList):void{
trace(“build Scroller”);
for (var item:uint = 0; item < imageList.length(); item++ ) {
var thisOne:MovieClip = new MovieClip();

//outline
var blackBox:Sprite = new Sprite();
blackBox.graphics.beginFill(0xFFFFFF);
blackBox.graphics.drawRect( -1, -1, 142, 107);

thisOne.x = (140 + 20) * item;
thisOne.itemNum = item;
thisOne.title = imageList[item].attribute("title");
thisOne.src = imageList[item].attribute("src");

trace(thisOne.itemNum, thisOne.title, " added to scroller");

}
trace("termination of build scroller");
}

• http://circlecube.com Evan Mullins

Hey Nikolai,

Sorry for the slow response, I don’t follow the comments on that tutorial very closely anymore. But I see what you’re getting at. If you’ve got variable widths then you can either read the image width once it loads and use that width in the calculations (which would be difficult because you would have to wait for the image to load and then continue) or you could add the width property to the xml file that is passed in. Then you can access that property just as the others and use it in your calculations. So if there was a width attribute in the xml (like width=”145″) you could do something like the following (code from step 6) (disclaimer: untested code):

var scroller:MovieClip = new MovieClip();
scroller.y = 30;
//build scroller from xml
function buildScroller(imageList:XMLList):void{
trace(“build Scroller”);
var scroller_x:int = 0;
for (var item:uint = 0; item < imageList.length(); item++ ) {
var thisOne:MovieClip = new MovieClip();
thisOne.img_width = imageList[item].attribute("width");
//outline
var blackBox:Sprite = new Sprite();
blackBox.graphics.beginFill(0xFFFFFF);
blackBox.graphics.drawRect( -1, -1, thisOne.img_width + 2, 107);
scroller_x += thisOne.img_width + 20;
thisOne.x = scroller_x;
thisOne.itemNum = item;
thisOne.title = imageList[item].attribute("title");
thisOne.src = imageList[item].attribute("src");
trace(thisOne.itemNum, thisOne.title, " added to scroller");
}
trace("termination of build scroller");
}

• nayyer

hi.. very tanks
this tutorials nice
but i want when clicked on picture that dont open on the web page
i want to open in to flash into movei clip
but i dont know do it