LoaderMax Tips & Tricks
Although LoaderMax is intended to simplify loading in AS3, its rich feature set might make it a little intimidating at first. Most developers aren’t using it to its full potential. In addition to listing some tips and tricks here, I’ll also try to clear up a few common misperceptions. The list should grow over time, so keep checking back to learn more. If you have any tips to share, please do so in the comments section below. To get notified when new tips are added, feel free to follow @greensock on Twitter and make sure you sign up for a free GreenSock account. For some tweening tips & tricks, click here.
1) SWFLoader and ImageLoader “content” vs. “rawContent”
Need to reference the root of a subloaded swf? Or the Bitmap that was loaded with an ImageLoader? Make sure you use the loader’s “rawContent” instead of “content”. In general, it’s always best to use a loader’s “content” but for SWFLoaders and ImageLoaders, “content” refers to a ContentDisplay Sprite that gets created immediately and serves as a wrapper for the raw content. A SWFLoader will put the subloaded swf’s root into the ContentDisplay. Likewise, an ImageLoader puts the Bitmap into its ContentDisplay. Why? So that you don’t have to wait for the raw content to load before putting it into the display list or adding event listeners (rollovers/outs/clicks), etc. The rawContent could be an Image, a MovieClip, a Loader, or a Video, so the ContentDisplay wrapper also provides a consistent type of object across all of those loaders. And ContentDisplay provides some nifty resizing and cropping functionality. So in general, you should always use the “content” unless you must directly access the raw content of a SWFLoader or ImageLoader. Here’s an example for a SWFLoader that loads a swf whose root document class has a “myCustomFunction()” method that we can call:
var loader:SWFLoader = new SWFLoader("child.swf", {onComplete:onLoadSWF, width:200, height:100});
addChild(loader.content); //add the ContentDisplay to the display list even before raw content is loaded.
loader.load();
function onLoadSWF(event:LoaderEvent):void {
var mc:MovieClip = loader.rawContent; //the root of the child swf
mc.myCustomFunction();
}
2) Feel free to use standalone loaders
If, for example, you just want to load a single swf file, there’s no need to wrap the SWFLoader in a LoaderMax.
//this is perfectly acceptable:
var loader:SWFLoader = new SWFLoader("child.swf", {onComplete:completeHandler});
loader.load();
//you do NOT need to do this (although it works fine):
var queue:LoaderMax = new LoaderMax({onComplete:completeHandler});
queue.append( new SWFLoader("child.swf") );
queue.load();
The primary benefit of putting a loader into a LoaderMax is when you have multiple loaders – the LoaderMax handles managing the order in which they load and reporting on their progress as a whole.
3) Define your loaders in XML for easy updates
Did you know that XMLLoader automatically looks at the XML file it loads and tries to find LoaderMax-related data? It creates the corresponding instances for you and optionally starts loading them too. So, for example, let’s define some XML that loads 2 images automatically:
<?xml version="1.0" encoding="iso-8859-1"?> <data> <ImageLoader url="1.jpg" name="image1" load="true" /> <ImageLoader url="2.jpg" name="image2" load="true" /> </data>
The ActionScript to load the XML and images would look like:
LoaderMax.activate([ImageLoader]); //only necessary once - allows XMLLoader to recognize ImageLoader nodes inside the XML
var loader:XMLLoader = new XMLLoader("data.xml", {onComplete:completeHandler, estimatedBytes:50000});
loader.load();
function completeHandler(event:LoaderEvent):void {
var image1:Bitmap = LoaderMax.getLoader("image1").rawContent;
var image2:Bitmap = LoaderMax.getLoader("image2").rawContent;
}
But let’s take it a step further and create two LoaderMax nodes in the XML, one that loads immedaitely and one that doesn’t. Let’s also set more of the options on the ImageLoaders to make things easier once we get it into ActionScript and let’s utilize the prependURLs attribute so that we can make switching to another server very simple:
<?xml version="1.0" encoding="iso-8859-1"?>
<data>
<LoaderMax name="queue1" prependURLs="http://www.greensock.com/assets/images/" load="true">
<ImageLoader url="1.jpg" name="image1" width="200" height="150" scaleMode="proportionalInside" alpha="0" />
<ImageLoader url="2.jpg" name="image2" width="400" height="300" scaleMode="proportionalOutside" crop="true" />
</LoaderMax>
<LoaderMax name="queue2" prependURLs="http://www.greensock.com/assets/" load="false">
<SWFLoader url="swf/child.swf" name="child" autoPlay="false" />
<VideoLoader url="video/video.flv" name="video" width="400" height="300" scaleMode="stretch" autoPlay="false" />
</LoaderMax>
</data>
Now in ActionScript, the XMLLoader will automatically parse all the loaders but it will only load the FIRST LoaderMax contents because its “load” attribute was set to “true”. Then, when the XMLLoader completes, we know that our images are loaded, but then we want to load the SECOND LoaderMax’s contents (a swf and a video) in the background, so we’d do:
LoaderMax.activate([ImageLoader, SWFLoader, VideoLoader]);
var loader:XMLLoader = new XMLLoader("data.xml", {onComplete:completeHandler, estimatedBytes:50000});
loader.load();
function completeHandler(event:LoaderEvent):void {
trace("XML and queue1 loaded!");
addChild( LoaderMax.getContent("image1") );
addChild( LoaderMax.getContent("image2") );
//grab the LoaderMax named "queue2" that was defined in the XML and start loading it now
var queue2:LoaderMax = LoaderMax.getLoader("queue2");
queue2.addEventListener(LoaderEvent.COMPLETE, queue2CompleteHandler);
queue2.load();
}
function queue2CompleteHandler(event:LoaderEvent):void {
trace("queue2 loaded!");
}
Note: your XML file can contain other non-LoaderMax-related data too.
4) Easy preloader progress bars: scaleX = progress
Build your preloader’s progress bar so that its native size is exactly what it should be when loading finishes (100%) and then just use the LoaderMax “progress” property and assign it to your progress bar’s scaleX, like this:
var queue:LoaderMax = new LoaderMax({onProgress:progressHandler});
//...append various loaders...
queue.load();
function progressHandler(event:LoaderEvent):void {
myProgressBar.scaleX = event.target.progress;
}
5) Estimate bandwidth and/or how much time is left
Every loader has a “loadTime” property that tells you how many seconds elapsed while the loader was loading. So to estimate bandwidth, you can use loadTime and bytesLoaded like this:
var kbps:Number = (loader.bytesLoaded / loader.loadTime) / 1024;
And to estimate how many more seconds it will take to finish loading, you can do this:
var secondsLeft:Number = ((1 / loader.progress) - 1) * loader.loadTime;
6) Fit a video/image/swf into an area
It’s pretty common to have a particular area into which your image/video/swf must fit when it loads. For example, maybe you have a grid of thumbnails and the native size of each image file may not be consistent or predictable. No problem. Just set the width and height properties of your ImageLoader/SWFLoader/VideoLoader and it will scale the content to fit into that size.
var loader:ImageLoader = new ImageLoader("1.jpg", {width:200, height:100, container:this});
By default it will fit the content exactly (stretching if necessary), but if you prefer that the content scales proportionally to fit inside the area, simply set the scaleMode to “proportionalInside”. In that case, there may be extra space vertically or horizontally, so you can control the alignment inside the area with the “hAlign” and “vAlign” special properties (they’re both “center” by default). You can even fill the area in with a color using the “bgColor” special property. Here’s an example that loads an image into a 200×100 area with a red (0xFF0000) background, scaling it proportionally to fit inside and positioning the area at the coordinates x:50, y:70:
var loader:ImageLoader = new ImageLoader("1.jpg", {width:200, height:100, scaleMode:"proportionalInside", bgColor:0xFF0000, container:this, x:50, y:70});
The other nice thing is that the ContentDisplay object (a Sprite) into which the image will be loaded is created immediately, so you can position it on the stage wherever you want, add MouseEvent listeners, etc. even before (or while) it loads. For example, to add a CLICK listener to the image that’s loading in the example above, we’d simply do:
loader.content.addEventListener(MouseEvent.CLICK, clickHandler);
function clickHandler(event:MouseEvent):void {
trace("clicked image associated with loader: " + event.currentTarget.loader);
}
Bonus tip: If you’d like to change the area’s size into which the content is scaled to fit (after you create the loader), you can alter the ContentDisplay’s “fitWidth” and/or “fitHeight” properties.
7) Crop a video/image/swf within an area
Imagine a background image that you’d like to fill an area with, scaling it proportionally to fill, but instead of fitting all the pixels INSIDE the area, you want to allow them to spill out so that there is no empty space vertically or horizontally. No problem. Set the width and height properties of the loader and set the scaleMode to “proportionalOutside”. Then set the “crop” special property to true in order to slice off the overspill, like:
var loader:ImageLoader = new ImageLoader("1.jpg", {width:200, height:100, scaleMode:"proportionalOutside", crop:true, container:this, x:50, y:70});
8) “progress” vs. “rawProgress” – what’s the difference?
All loaders have a “progress” property that reports the bytesLoaded / bytesTotal ratio, but LoaderMax instances also have a more crude “rawProgress” that grants all child loaders equal weight in the calculation and doesn’t concern itself with file size at all. “rawProgress” can be useful in certain scenarios like if you’re getting a progress bar that “jumps” (see tip 9) or when you want to skip file size audits and also avoid defining estimatedBytes values for your loaders. In the interactive demo below, you can see how the “progress” and “rawProgress” values compare in various scenarios. Notice how “rawProgress” never jumps but it does change the speed at which it moves based on the size of the file that’s loading. Click load() and see how smooth and accurate the “progress” bar is. Then try changing the estimatedBytes to inaccurate values or deleteing them altogether to see how it works when you omit estimatedBytes on child loaders. Uncheck the “auditSize” checkbox too in order to watch what happens when you turn file size audits off. For a more full explaination of what causes the “jumping” in the “progress” property, see tip 9.
9) Avoid a jerky progress bar
Ever seen a progress bar that appears to suddenly jerk forwards or backwards unexpectedly? It doesn’t happen on individual loaders, but it can happen on a LoaderMax instance that is reporting the overall progress of multiple loaders (its children) in very particular scenarios. First let me explain the cause and then I’ll get to the solution.
In order to accurately calculate the overall progress of a group of loaders, it’s important to know the total file size (bytesTotal) of each child loader. But if some files haven’t started loading yet, how could we possibly know their sizes? LoaderMax tackles that challenge in two ways: First, it recognizes an “estimatedBytes” special property that you can optionally define when you create your loader(s) like this:
new ImageLoader("1.jpg", {estimatedBytes:26000});
If you define an estimatedBytes value for a loader, LoaderMax uses that in its “progress” calculations until the file starts loading at which point it swaps in the accurate bytesTotal. If your estimatedBytes value was very inaccurate, though, you’ll see that jerking behavior in the “progress” value when the size is corrected. If you underestimated the value quite a bit, the progress will jump backward at that point. If you overestimate, it will jump forward.
The other way LoaderMax tackles the challenge of accurately calculating progress is by auditing the real files. By default, when a LoaderMax begins loading it checks all of its child loaders and if it finds any that don’t have an “estimatedBytes” defined, it will quickly open up a URLStream for each one just long enough to determine the bytesTotal from the server at which point it terminates the connection and moves on to the next file. Once the auditing process is complete, the LoaderMax will begin loading the full files in the correct order. The great thing about the file audits is that they make progress reporting VERY accurate with minimal hassle for you. The down side is that it costs a little extra time initially. You can, of course, turn auditing off by passing auditSize:false into your LoaderMax’s vars parameter or set the default globally with the static defaultAuditSize property like this:
//turns auditing off for only this instance:
var queue:LoaderMax = new LoaderMax({auditSize:false});
//changes the default auditSize to false for all LoaderMax instances created after this point
LoaderMax.defaultAuditSize = false;
A default file size value (bytesTotal) of 20,000 bytes will be used initially for all loaders that don’t have an estimatedBytes defined. But again, this value will be corrected as soon as the file starts loading or is audited.
Phew! So now you understand the problem. Let’s get to the solution. Actually, there are several solutions to choose from:
- Minimal hassle, very accurate, slight delay (default): omit estimatedBytes from all (or some) of your loaders and let LoaderMax audit their size.
- Moderate hassle, accuracy varies, no delay: define an estimatedBytes value for your loaders in order to skip auditing and get maximum performance. The “progress” accuracy completely depends on your estimatedBytes values. The more you underestimate, the more the “progress” will jump backward when the real size is determined. Overestimating will cause it to jump forward.
- Minimal hassle, very inaccurate, no delay: turn auditing off in the LoaderMax instance by passing auditSize:false in the vars object (or set the static LoaderMax.defaultAuditSize = false). This will use a default size of 20,000 bytes for files that don’t have an “estimatedBytes” defined. The “progress” value will jump each time a child loader begins loading. If you don’t plan on reporting the overall progress, this option is perfectly acceptable.
- Minimal hassle, somewhat accurate, no delay: turn auditing off in the LoaderMax instance but instead of using the LoaderMax’s “progress”, use its “rawProgress”. As illustrated above in tip 8, rawProgress never jumps but it varies the speed at which it moves based on the size of the file that’s loading. If you plan to only use “rawProgress”, there is no reason to audit file sizes because “rawProgress” has nothing to do with bytesTotal – all child loaders are given equal weight in the calculation regardless of their file size. So a 20MB video would have the same relative weight in the calculation as a 15kb XML file.
10) Why are there 2 requests for each file?
One of the more common questions has to do with why 2 server requests are made for each file. This actually only happens on loaders that do not have an estimatedBytes value defined and auditSize wasn’t set to false on the parent LoaderMax. The “extra” request is simply the file size audit which greatly improves the accuracy of the LoaderMax’s “progress” value. Please read the more full explanation in tip 9.
11) Integrate the root swf into a LoaderMax’s progress
Let’s say you’ve got a large swf file that also loads a bunch of external assets and you’d like to report the overall loading progress of EVERYTHING (including the root swf). The SelfLoader class allows exactly that:
var queue:LoaderMax = new LoaderMax({onProgress:progressHandler, onComplete:completeHandler});
queue.append( new SelfLoader(this) ); //just to include the root swf in the progress calculations
queue.append( ...append your other loaders... );
queue.load();
12) parse() an entire array of URLs
Sometimes it’s convenient to be able to simply throw a bunch of URLs at LoaderMax and have it figure out what types of loaders are necessary and create them for you, wrapping them all in a parent LoaderMax queue. That’s what parse() is for:
var urls:Array = ["1.jpg","video.flv","child.swf","audio.mp3"];
//activate the types of loaders so that parse() can recognize the appropriate extensions (only necessary once)
LoaderMax.activate([ImageLoader, VideoLoader, SWFLoader, MP3Loader]);
var queue:LoaderMax = LoaderMax.parse(urls, {onComplete:completeHandler}, {autoPlay:false});
queue.prependURLs("http://www.greensock.com/assets/"); //saves us from having to include this in every URL in the array, and makes switching servers very easy.
queue.load();
Then you can use LoaderMax.getLoader() or LoaderMax.getContent() to get the loader or content associated with a particular URL. For example, in the completeHandler, we could get the video, add it to the stage, and start playing it like this:
function completeHandler(event:LoaderEvent):void {
var video:VideoLoader = LoaderMax.getLoader("http://www.greensock.com/assets/video.flv");
addChild( video.content );
video.playVideo();
}
13) Get code hinting and strict data typing
If you don’t mind a little extra file size and slightly longer code, you can use the various data classes in the com.greensock.loading.data package to define the vars object that you pass into the constructor instead of a generic {} object. These data classes (like LoaderMaxVars, SWFLoaderVars, ImageLoaderVars, etc.) deliver some yummy code hinting so that you don’t have to refer to the docs so much to remember the various special properties that are available. And of course this technique also gives you strict data typing for improved debugging. For example:
//using a variable (long syntax)
var config:LoaderMaxVars = new LoaderMaxVars();
config.name("queue1");
config.onComplete(completeHandler);
config.onProgress(progressHandler);
config.maxConnections(1);
var queue:LoaderMax = new LoaderMax(config);
Or you can do things inline with chaining (very convenient)
//chaining (much shorter syntax)
var queue:LoaderMax = new LoaderMax(new LoaderMaxVars().name("queue1").onComplete(completeHandler).onProgress(progressHandler).maxConnections(1));
Got a tip or trick?
Post it in the comments section below. If you have a question, it’s typically best to post it in the forums at http://forums.greensock.com
Comments (13)

I’M FIRST?! ![]()
THIS IS A JACKPOT! This is a fantastic set of tricks/tips. I’m especially fond of #8 and #9…Thanks again Jack!
Yeahh ! Thank you for these tips & Tricks ! Greensocks Rocks !
Excellent idea, these tips! Great job, keep on increasing these tips and tricks because they are very helpful
Great stuff Jack! Keep it up
Great tips, THANKS~~~~!
Thanks. I have always been interested in learning loaderMax. Thank you for posting the tips.
Wow, awesome work man. These examples REALLY help. Love the preloader example. Keep it up and thanks again.
Jack, great work of course. Minor criticism as there is often confusion about bytes and bits.
var kbps:Number = (loader.bytesLoaded / loader.loadTime) / 1024;
techincially shouldn’t it be kBps, to indicate Bytes , not Bits?
So to determine kilobits take the above calculation and multiply by 8. Am I correct here?
eco_bach, sure, I suppose if you want kilobits instead of kilobytes that would be accurate but I assumed most people would be concerned about bytes since that’s what everything else is measured with in LoaderMax (bytesLoaded, bytesTotal, etc.)
It’s also a little confusing because of the whole camel case thing (you capitalized “B” to indicate bytes but it looks kinda weird with only that being capitalized).
Anyway, thanks for chiming in and clarifying.
Hi,
I think there is a general problem with flash loading a child SWF that tries to access external files. So flash thinks child is in same path as parent and a file reference not given as a full URL in the child will fail.
I tried your loader very simply and was wondering if you have found anyway around this ? So path for child SWF external files should be same path at which SWF was loaded from.
Thanks,
Don
Correct, DonMoir, Flash always treats relative URLs as relative to the root/parent swf (actually, for HTML pages, it’s relative to the HTML page itself). That’s just a Flash thing and has nothing to do with LoaderMax. Oh, and the one exception (which I’d consider an Adobe bug) is that NetStreams are relative to the child swf. Of course one solution is to simply use absolute URLs (like ones that start with http://).
Thanks for responding Jack. LoaderMax is a nice package and very easy to use but with Flash of course there are just some things that irritate the hell out of you.
The SWF files are being run on the local file system and can come from anywhere so its not possible for me to fix the URL by any normal means that I have found.
Another problem I am looking for a solution for is when a child SWF attempts to access the stage in its document class constructor. In this case stage will be null and then error.
DonMoir, these are questions that are better suited for the forums at http://forums.greensock.com. That topic has been covered a few times there actually. Just make sure you define a “container” for your SWFLoader (or manually addChild() its content before you load()) so that the stage isn’t null. Or put some conditional logic in your constructor to delay processing of your stage-related code until it is added to the stage (wait for the ADDED_TO_STAGE event to be dispatched). And for the record, this isn’t a LoaderMax-related thing – you’d run into the same issue with Adobe’s Loader. Oh, and make sure you’re using the latest version of LoaderMax.
















