Display Download Status In Your Flash Preloader

We’ve all heard the hype, but you and I both know that Flash is a powerful tool, and needn’t be a turn-off for users (yes, even those on dial-up connections).

You can spend a lot of time honing your sites and movies to make the Flash experience more enjoyable for your visitors. For instance, you can help smooth the playback of Flash movies by displaying a ‘loading’ graphic to the user while the files download, and programming the movie to start playing back only once it’s fully loaded.

However, these techniques can leave your visitors wondering ‘just how long is this going to take?’ Even worse, they may abandon your download before it’s completed — let alone beginning to play.

The solution? Keep your visitors informed!

Use a feedback mechanism to inform your users of the download’s progress. Providing feedback through your Flash preloader will keep your visitors much happier, and reduce the risk of download abandonment.

The feedback you provide to users could be numeric, visual, and/or display any of:

  • percentage loaded
  • bytes loaded
  • percentage remaining
  • bytes remaining
  • estimated time remaining

…or any combination of the above. Let’s see how it’s done.

The Basic Mechanism

When complete, our preloader will perform the following procedure:

  1. The movie starts. Stop the main timeline and display the preloader.
  2. Calculate and display file loading status.
  3. If the movie is still loading, return to Step 2, otherwise
  4. Continue to play the main timeline.

Firstly, we’ll need a blank frame at the start of your movie (on the main timeline). Insert this before there’s anything else on the stage.

I’ve also added a layer for the preloader just because I want to — this will help keep the movie organised.

Make the first frame of the preload layer a keyframe: click on it and press F6, or select Insert > Keyframe from the menu.

1119_pic1

Now, let’s create our preloader movie clip.

Select ‘New Symbol…’ from the ‘Insert’ menu. Name it something logical, and make sure it’s a Movie Clip, then click ok.

1119_pic2

You’ll now see a blank stage and timeline for the new clip. Add a new layer here. Our preloader only needs two layers in total: one for the actionScript, and one for the graphics.

The Script

This is the fun part! Our new ‘preloader’ clip is going to be 3 frames long, and each of these will contain actionScript.

Now, to add code to any particular frame, it must be a keyframe. So, add a new layer, click on the second frame, and choose ‘Insert > Keyframe’ from the menu (or press F6). Click on the third frame and make it a keyframe, too. We don’t need to do this for the first frame of our movie, as, by default, the first frame is always a keyframe.

1119_pic3

Ok. Now let’s take the process step by step, and see what we need to do to achieve in each

Step 1. The Movie Starts. Stop the Main Timeline and Display the Preloader.

In the actionScript layer, click on the first frame. If it’s not already open, bring up the ‘Actions’ window (you’ll find it under the ‘Windows’ menu).

The ‘Actions’ window has two modes, ‘Normal’ and ‘Expert’. For us to be able to type code directly into the window, it will need to be in ‘Expert’ mode. To change modes, click on the arrow in the top-right corner on the window, and select ‘Expert Mode’ from the drop-down list.

The Actions window will be empty. Enter the following into the actionScript window:

_parent.stop();

That’s all for frame 1 (simple, yet effective!). Let’s look at what this code does…

We use the ‘stop()‘ action, because we want to stop the main timeline. But, because we’re inside the preloader movie clip, just calling ‘stop()‘ is going to stop the preloader’s timeline (while the main timeline happily keeps playing).

What we need to do is send the ‘stop’ message to the main timeline. Notice the ‘.’ (dot/full stop or period) in the statement. The best way to pass messages between timelines and movieclips is to use this ‘dot syntax’. It works liked this:

target.message

(or target.property, as we’ll see later)

In our case, ‘_parent’ is the target (the parent object is the one that contains the referring clip).

So, _parent.stop(); sends the timeline we’re within (i.e. the main timeline), the ‘stop()’ command.

Step 2. The Preloader Calculates and Displays the Loading Status.

How do we calculate the values?

To calculate the loading progress, there are two main functions that we’ll need to use:

  1. getBytesLoaded()
  2. getBytesTotal()

These both return numerical values for:

  1. the number of bytes that have been downloaded (in the current movie)
  2. the total number of bytes (in the current movie)

Again, we’ll use ‘_parent.‘ to target the main timeline, because bytesLoaded and bytesTotal are properties of the entire ‘main’ movie.

Personally, I don’t really like bytes, they’re very small, slippery, and there are always a lot of them (moving pretty quickly).

To display something more friendly to our visitors, I’m going to turn them into kBytes, the value we usually see when waiting for data transfers and downloads.

There are 1024 bytes in a kByte, so, click on frame 2 and enter the following lines of code into the actionScript window…

kBytesLoaded = _parent.getBytesLoaded()/1024;  
kBytesTotal = _parent.getBytesTotal()/1024;

Armed with this information, we can calculate some more exciting values…

kBytesRemaining = kBytesTotal - kBytesLoaded;  
percentLoaded = 100 * kBytesLoaded / kBytesTotal;  
percentRemaining = 100 - percentLoaded;

Enter these lines of code also.

1119_pic4

Ok, enough of that for the moment, let’s look at Step 3.

Step 3. If Still Loading, Return to Step 2, Otherwise Continue Playing the Main Timeline.

In the timeline, click on the third frame of the actionScript layer. Again, the Actions window is empty.

Now our procedure says, “If the movie is still loading, return to step 2″ — frame 2, where our information will be calculated all over again.

Hmm, ‘if still loading’… Well, we’ve got some useful info from our calculations in frame 1, how about:

if (percentLoaded < 100){  
 gotoAndPlay(2);  
}

That is, if whatever is in the brackets (percentLoaded < 100) is true, then do whatever is in the curly brackets {gotoAndPlay(2);}

That looks pretty good...

But I don't like it! The computer's doing its best to perform all the calculations, and it does a pretty good job, but sometimes, instead of getting to 100% you may actually end up with 99.9999999999%.

This value would leave the visitor stuck in the loader until the computer decides that 99.9999999999 is not less than 100, and personally, I don't think it's going to happen.

So let's change the code to:

if (percentLoaded < 99){  
 gotoAndPlay(2);  
}

...otherwise continue playing the main timeline.

Modify the code again so that it looks like this:

if (percentLoaded < 99){  
 gotoAndPlay(2);  
 
} else {  
 
 _parent.play();  
 stop();  
}

Here,

'_parent.play()' sends the 'play' command to the main timeline, which we stopped it earlier using '_parent.stop();'

'stop();' will stop the current (preloader) timeline

And we're done! (See, I told you it was the fun bit)

Test it Out

Before we try this out, we need obviously need to have our preloader in the movie (and not just in the library where it currently is).

So, go to the main timeline, click on the first frame, and drag our 'preloader' movie clip from the library to the stage. If you can't find the library, select it from the 'Windows' menu.

1119_pic5

Note that if you started out with a blank movie, you'll need to add some content to it now, otherwise we can't tell if the preloader is working. Import an image or something else that will increase the movie's filesize, and place it on frame 2 (or some later frame) in the main timeline.

Ok, test your movie, and make sure you turn on 'show streaming' (under the 'view' menu) when the preview runs. It should wait on frame 1 until loading is complete, and then continue to play.

Brilliant!

"Ummm, yeah, but there's nothing on stage," you're thinking. "I thought this was all about feedback?"

Alright, alright, I'm getting to it!

Providing Feedback

All of the following changes must be made within the 'preloader' movie clip, so if you're not already there, double click 'preloader' in the library.

Before we look at representing the preloader's progress visually, let's start by displaying a numerical percentage loaded indicator.

Click on the graphics layer, and draw a text box in the center of the stage. In the 'Text Options' panel, select 'Dynamic Text' and type 'progress' as the name for the variable.

In FlashMX, click the Characters... button and select 'Only', then select 'Numerals' and type a '%' into the 'and these characters' field.

If you're using Flash5, under the font embedding options, click the button marked '123' and type a percentage sign (%) into the field on the right.

This will only embed outlines for numerical characters and the '%'. By only embedding some characters, we reduce the bytesize of the font definition, and minimize any potential lag while the font loads.

Note that, if you wish to avoid font loading altogether, choose a system font and don't select any embedding options. This will cause the movie to use a font on the user's system rather than requiring downloaded outlines. Note however, that you will lose control over some of the display properties. System fonts are not able to be rotated, skewed, scaled disproportionately or have alpha values applied.

That's all we need on stage, but if you test your movie now, you still won't see anything!

What we have to do is get a message from our calculations in frame 2 into the dynamic text field we've just created.

Click on frame 2 in the actionScript layer, and if you've closed it, open the actions window again.

What we want to do now is set the variable 'progress' (our dynamic text field) to display something like '75%'. Well, not really 75, but whatever is calculated by the 'percentRemaining' code, which will be updated repeatedly as the movie loops through frame 1.

After the existing code, enter the following...

progress = percentRemaining add '%';

1119_pic6

This will add a '%' character to the end of 'percentRemaining', and put the result into the 'progress' text field.

Test again it now!

Chances are you don't like it. I don't, either. The code we entered will display numbers like 27.568793256432%. In fact, because we didn't embed a decimal point with our characters, it will probably display figures like 27568793256432% which is just silly.

Although we're about to get rid of all these numbers, go back to the character embedding options and add a full stop/period/decimal point (or whatever you'd like to call it) into the field with the '%'. You might want it later.

Now, we need to chop all those decimal places off the end of our number. And there's a nice simple way to do it.

Flash contains a whole bunch of math-related functions, one of which is 'floor()'.

Give the floor function a number, and it will find the integer (whole number) that is immediately below it. That's exactly what we want! '87.568793256432' becomes '87'.

So, change the last line to...

progress = Math.floor(percentRemaining) add '%';

Test it again... Beautiful!

Ok, that was percent remaining to load, but you might want something else, and, chances are, it's just as easy.

How about those messages that say things like '125 of 200 kBytes loaded'

The message is a little lengthy, but let's do it anyway -- it'll give those waiting users something to read.

progress = Math.floor(kBytesLoaded) add ' of '    
add Math.floor(kBytesTotal) add ' kBytes loaded';

Easy, huh?

No! Wait a minute, we've just added a whole bunch of characters that we didn't include, and they may not display on a machine that doesn't have your font installed. Click on the 'progress' text field and in the font embedding options add 'ofkByteslad' into the field to embed these characters as well.

Getting Graphic

Ok, enough with the text messages. How do you do one of those snazzy, progress-indicating loading bars?

Well, it's really simple.

Draw a solid rectangle on the stage underneath your text field (or wherever you want it to appear, really).

With the selection tool, single click on the rectangle's fill (this will select the fill, but not the stroke). I'm going to only scale the fill and leave behind the stroke as an indicator of the total size.

Convert the selected fill into a symbol (menu: 'Insert' > 'Convert to Symbol...' or press F8). The Symbol Properties dialog box appears. Enter a symbol name and click 'OK'.

1119_pic7

Note that if you're using FlashMX, you must select a registration point option on the left in the little grid. If you're using Flash5, we'll need to fix something else in just a minute.

Now, when you create or place a movieClip on the stage, you may have noticed that you can give it an 'instance' name (this is on the 'Properties' panel in MX and on the 'Instance' panel in 5). This name allows the clip to be identified by actionScript, and various clip properties can inspected and controlled.

On the 'Properties' / 'Instance' (FlashMX / Flash5) panel, enter 'loadBar' as the instance name.

Just as we used our calculated variables to set the text in our text field, we'll now use them to set the scale of our 'loadBar'.

To help you differentiate them from functions and variables, property names start with the underscore character '_'.

The property we will set is '_xScale'. There's also a '_width' property, but they differ slightly. '_width' sets the actual width of a clip in pixels, whereas '_xScale' sets the width as a percentage of the clip's defined size.

_xScale is the best choice in this case, as we've just defined the clip at a size that fits perfectly into the stroke we left on the stage (when it has a scale of 100%). Our 'percentLoaded' value also ranges from 0% to 100%, so they should be very happy together.

Note that you could also use the width property, however, unless you wanted to scale from 0 to 100 pixels width, there would be a tiny bit more maths involved. In this situation, xScale is easier.

Now, to set the properties of a movieClip, we must tell Flash which movie we're talking about. This is the instance name we entered before (loadBar). This is how it looks...

loadBar._xScale = percentLoaded;

It's dot syntax again, but this time we're using it to set a property, rather than calling a function.

Go ahead and add it to the script on frame 2. Now it looks like ...

kBytesLoaded = _parent.getBytesLoaded()/1024;    
kBytesTotal = _parent.getBytesTotal()/1024;    
kBytesRemaining - kBytesTotal - kBytesLoaded;    
percentLoaded = 100 * kBytesLoaded / kBytesTotal;    
percentRemaining = 100 - percentLoaded;    
progress = Math.floor(kBytesLoaded) add ' of '    
add Math.floor(kBytesTotal) add 'kBytes loaded';    
loadBar._xScale = percentLoaded;

Flash 5 Note
When you test your movie, it may not appear exactly as you expected. Rather than growing from one side of the display to the other, loadBar grows out from the center. This is because the scaling of the clip is based around its 'registration point'.

Select the loadBar symbol, and you'll see a cross in the center. This is the registration point.

Let's move the registration point to the left hand edge of the rectangle. This will make the scaling clip stretch out to the right.

Double-click the clip to enter edit mode, and click once on the rectangle to select it.

In the 'info' panel (menu, Window > Panels > Info), the position of the shape relative to the clip's registration point is shown in the fields marked X and Y. Next to this is a little set of boxes, some are grey, one is white, one is black. Here, you set whether the X,Y values are relative to the center of the shape, or to the top-left corner. In the following image, the X,Y values are 0.0 relative to the center.

1119_pic8

Click on the corner box and notice that the X,Y values change. Enter 0 (zero) into the X value, and hit the tab key to set it. The rectangle on the stage jumps to the right, so that its left hand edge is aligned with the registration point.

Well that's good, but it's a bit annoying that our clip is now in the wrong position.

Exit the clip's edit by clicking the 'Scene 1' link in the top-left of the window (just above the timeline). Click and drag the clip back to the left, so that it fits within the stroke again.

Test the movie again and you'll see a more 'traditional' progress bar.

You may have noticed that, before there's any movement, the bar is very briefly displayed at 100% width. This is because, before it has a chance to do any calculations in frame 1, the bar is shown as it is placed on the timeline. But there's an easy fix! Select the clip, and, in the info panel, enter 1 into the width field. Hit the tab key to set it.

Test the movie again... it's fixed!

A Little Bit Extra

Well, at the very start, I said that one of the possible feedback displays we could use was the estimated time remaining. It will require just a little more code, so let's do it.

Another handy function in Flash is 'getTimer()' which returns the number of milliseconds since the movie started. Just as I'm not rapt in bytes, I'm also not that fond of milliseconds. I'm going to use (getTimer()/1000), which will give the value in seconds instead.

In the frame 2 code, let's calculate the number of kBytes per second -- you could display that, too, if you like.

kBytesSec = kBytesLoaded/(getTimer()/1000);

It's that's simple: the number of kBytes loaded, divided by the number of seconds it's taken.

And now, the time remaining:

timeRemaining = kBytesRemaining / kBytesSec;

Another simple one. We divide the amount remaining by the newly calculated download speed.

So our display message might be ...

progress = Math.floor(timeRemaining) add " seconds remaining";

Hey that's cool! Now your visitors know if there really is enough time to put the kettle on before your movie starts!

So, don't leave your visitors twiddling their thumbs, grinding their teeth, and potentially abandoning the download altogether. Tell them what's going on -- it's that easy! Keep them informed, keep them happy.

And that's just the beginning. There's so much more you could do. Check out other movieClip properties you can access, play with the rotation or position values, get in there and mess around, and have some fun!

Problems, Workarounds, Other Bits 'n' Pieces

The preloader we've built here will work well for most Flash movies. However, there are situations where it will not perform as you might like.

Loaded Submovies

The values returned by getBytesLoaded and getBytesTotal only apply to the main movie.
If you're loading movies and sounds into your main movie, these bytes are not counted by the preloader, and as soon as the main movie is loaded, it will continue regardless of any external files that are still loading.

If you had a submovie being loaded into level 1 and wanted it, as well as the main movie, to preload, you could do something along the following lines...

kBytesLoaded = (_parent.getBytesLoaded() +      
_level1.getBytesLoaded()) / 1024;    
kBytesTotal = (_parent.getBytesTotal () +    
_level1.getBytesTotal ()) / 1024;

Linked Assets

When a movie's library contains items with linkage, the linked objects, and any objects they depend on, are exported in the first frame (this can be avoided in MX -- see below).

As Flash doesn't display a frame until it has loaded, this can produce a 'stalled' effect when loading the movie (because the first frame can obviously get quite large).

Files using 'attachSound()' and 'attachMovie()' have linked assets. Linkage can also be common in Flash components.

Flash MX introduced a way of linking assets that does not place them in frame 1 of your movie. By default, linked assets are still written into frame one, but this can be avoided.

Uncheck the 'export in first frame' option for the linked asset(s). Doing this will prevent the item from being exported, unless it's manually placed on the stage. You'll then need to manually place the item in a frame after your preloader and before any actionScript that calls the attach function.

Chances are, you don't want these items manually placed, which is why you're using attach functions in the first place, so you'll probably want to place them somewhere offscreen, or on a frame that doesn't ever get played.

This can all get a little laborious (particularly if you're using components) as these often have numerous exported subelements, which you will also have to adjust and manually relocate.

Resources and Links

Got problems? Here are some links that could ease your troubles.

ActionScript.org Flash community forums, movies, tutorials.
http://www.actionscripts.org

'AssetMover'. Utility that moves linked assets to a specified frame.
http://www.flexidev.com

Flashcoders/Flashnewbie (and other lists). Some great mailing lists. Things can get pretty hardcore on the Flashcoders list (and will fill up your inbox. You might want to subscribe to the digest!).
http://chattyfig.figleaf.com

FlashKit. Flash community sites, forums, tutorials, movies. Stuff for everyone, from designers to code junkies.
http://www.flashkit.com

Neave's Webgames. Completely off-topic, but when you need to kill some time, this site has some classic games recreated in Flash (completely free -- downloadable .fla's and all). Hey, wait a minute, don't get distracted -- make your preloader first!
http://www.neave.com/webgames/

And, on my desk, amongst other volumes, is "ActionScript for Flash MX – The Definitive Guide – 2nd Edition" by Colin Moock. Over a thousand pages of ActionScript information. It's not really a tutorial/how-to book, but it's a very solid reference.

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

No Reader comments

Comments on this post are closed.