Spinning Preloader - An All-Time Classic in Pure AS3
This tutorial may serve as a beginner exercise in AS3 coding. But before starting, let’s take a quick look at what we will be creating:
The spinning preloader animation is an all-time classic. Our implementation will be highly configurable. You will be able to set the number, size, color and fade-out duration of the rectangular segments, as well as the radius and the spinning speed.
Prerequisites
Since this is a pure AS3 project, you can choose whatever IDE you like. I use the open-source AS3 IDE FlashDevelop along with the free Flex 3 SDK. The only other thing we need is the AS3 animation kit TweenLite. This lightweight tweening engine is contained in a single class file. You can eiher copy and paste it into your project space, or you can store it somewhere else and add the path to your project’s classpaths settings.
I call the preloader class SpinningPreloader and use com.log2e.utils as package definition. So my FlashDevelop project panel looks like this:

The SpinningPreloader Class
Here’s the full class code (I will explain it below):
-
package com.log2e.utils
-
{
-
import flash.display.DisplayObjectContainer;
-
import flash.display.Sprite;
-
import flash.events.TimerEvent;
-
import flash.utils.Timer;
-
import gs.TweenLite;
-
-
public class SpinningPreloader extends Sprite
-
{
-
private var _target:DisplayObjectContainer;
-
private var _container:Sprite;
-
private var _centerX:uint;
-
private var _centerY:uint;
-
private var _radius:uint;
-
private var _steps:uint;
-
private var _rectWidth:uint;
-
private var _rectHeight:uint;
-
private var _color:uint;
-
private var _count:uint;
-
private var _timer:Timer;
-
private var _timerInterval:uint;
-
private var _fadeOutDuration:Number;
-
-
public function SpinningPreloader( target:DisplayObjectContainer,
-
centerX:uint = 0,
-
centerY:uint = 0,
-
radius:uint = 15,
-
steps:uint = 24,
-
rectWidth:uint = 4,
-
rectHeight:uint = 2,
-
color:uint = 0×0000FF,
-
timerInterval:uint = 20,
-
fadeOutDuration:Number = 1.5 )
-
{
-
_target = target;
-
_centerX = centerX;
-
_centerY = centerY;
-
_radius = radius;
-
_steps = steps;
-
_rectWidth = rectWidth;
-
_rectHeight = rectHeight;
-
_color = color;
-
_timerInterval = timerInterval;
-
_fadeOutDuration = fadeOutDuration;
-
}
-
-
public function start():void
-
{
-
_container = new Sprite();
-
_container.x = _centerX;
-
_container.y = _centerY;
-
_target.addChild(_container);
-
-
_count = 0;
-
_timer = new Timer(_timerInterval, 0);
-
_timer.addEventListener(TimerEvent.TIMER, drawRectangle);
-
_timer.start();
-
}
-
-
public function stop():void
-
{
-
if (_container)
-
{
-
TweenLite.to( _container, .5, { alpha:0, onComplete:onContainerFadeOutComplete } );
-
}
-
}
-
-
private function onContainerFadeOutComplete():void
-
{
-
_timer.stop();
-
_target.removeChild(_container);
-
}
-
-
private function onRectFadeOutComplete(rect:Sprite):void
-
{
-
_container.removeChild(rect);
-
}
-
-
private function drawRectangle(e:TimerEvent):void
-
{
-
var rot:Number = _count * 360 / _steps;
-
var rect:Sprite = filledRectangle(_rectWidth, _rectHeight, _color);
-
rect.x = _radius * Math.cos(rot * Math.PI/180);
-
rect.y = _radius * Math.sin(rot * Math.PI/180);
-
rect.rotation = rot;
-
_container.addChild(rect);
-
_count++;
-
-
TweenLite.to( rect, _fadeOutDuration, { alpha:0, onComplete:onRectFadeOutComplete, onCompleteParams:[rect] } );
-
e.updateAfterEvent();
-
-
if (_count == _steps)
-
{
-
_count = 0;
-
}
-
}
-
-
private function filledRectangle(width:uint, height:uint, color:uint):Sprite
-
{
-
var rect:Sprite = new Sprite();
-
rect.graphics.beginFill(color);
-
rect.graphics.drawRect(-width/2, -height/2, width, height);
-
rect.graphics.endFill();
-
return rect;
-
}
-
-
}
-
}
The Constructor
The constructor receives a list of parameters:
- target: The display object you want to attach the preloader animation to. The type is
DisplayObjectContainerso the target can be any object that inherits from this class (for exampleStage,MovieClip,Sprite). - centerX: The x position of the preloader’s center point.
- centerY: The y position of the preloader’s center point.
- radius: The radius of the preloader. Please note that this is not the outer radius of the resulting animation but the distance between the center point and the registration point of the rectangular segments.
- steps: The number of rectangles that are created in one full turn.
- rectWidth: The width of a single rectangular segment.
- rectHeight: The height of a single rectangular segment.
- color: The color of the rectangles.
- timerInterval (in ms): This parameter controls the speed of the rotation by setting the time interval after which a new rectangle is drawn.
- fadeOutInterval (in s): This parameter specifies the duration of the alpha tween that fades out it each segment.
The start() and stop() Methods
These two methods are the only interface between the SpinningPreloader class and the outside world.
The start() method creates a container for the animation and positions it on the target display object. It also initializes the _count property and starts the timer which repeatedly calls the drawRectangle() method.
The stop() method fades out the container sprite. Once the alpha value is 0 the timer is stopped and the container is removed from the display list. If you prefer to remove the animation immediately just replace the line of code that starts the tween with the two lines from the onContainerFadeOutComplete() event handler method.
The “Fading” Event Handlers
The method onContainerFadeOutComplete() is called after the container’s alpha value has reached 0.
The method onRectFadeOutComplete() is called whenever a single rectangle has finished its life cycle. As soon as the rectangle’s alpha value is 0 it is removed from the display list. This way we limit the maximum number of rectangles that are child objects of the container sprite at the same time.
Drawing the Rectangles
The angle that defines the position of each rectangle is calculated with the help of a counter variable (_count) which is incremented each time a rectangle is drawn. If the counter value is equal to the number of steps _count is reset to zero. The result from 360 divided by the number of steps muliplied with _count gives us the angle in degrees. This value is stored in the local variable rot.
In order to calculate the exact x and y coordinates we need a little trigonometry.

(Just on a side note, we use the three o’clock position as starting point because that’s where the 0 degree angle is situated in Flash.) The sine and cosine in the above diagram are calculated by sin(A) = y/r and cos(A) = x/r. This trigonometric relation is used in the drawRectangle() method:
rect.x = _radius * Math.cos(rot * Math.PI/180);
rect.y = _radius * Math.sin(rot * Math.PI/180);
Please note that the Math.sin() and Math.cos() functions expect the angle to be in radians, that’s why we have to multiply rot with Math.PI/180.
The rectangles themselves are created in the filledRectangle() method which receives the width, height and color as parameters. The sprite instance is returned to drawRectangle() where the x, y and rotation values are set and the rectangle is added to the display list. As soon as the rectangle is visible it starts to fade out. Invoking e.updateAfterEvent() causes the Flash Player to update the screen immediately after a rectangle has been added (instead of relying on the next scheduled screen update that is governed by the frame rate).
Using the SpinningPreloader Class
The animations shown on this page were created by instantiating three preloader objects with different parameters:
-
package
-
{
-
import flash.display.Sprite;
-
import com.log2e.utils.SpinningPreloader;
-
-
public class Main extends Sprite
-
{
-
public function Main():void
-
{
-
var pl1:SpinningPreloader = new SpinningPreloader(this, 50, 70, 15, 24, 4, 2, 0×0000FF, 20, 1.5);
-
pl1.start();
-
-
var pl2:SpinningPreloader = new SpinningPreloader(this, 180, 70, 40, 48, 8, 3, 0xFF0000, 30, 2);
-
pl2.start();
-
-
var pl3:SpinningPreloader = new SpinningPreloader(this, 330, 70, 30, 32, 12, 4, 0×999999, 15, 1);
-
pl3.start();
-
}
-
}
-
}
Room for Improvement
Where to go from here? There are several options for improving the class. For example, you could add a text field at the center of the preloader and an update function that receives the loading progress value. Or you could use a circle or a small bitmap instead of the rectangle. I will leave this as an exercise to you.
If you have any questions or suggestions leave a comment or drop me a message.
Tags: ActionScript, Flash, FlashDevelop, Preloader
August 10th, 2008 at 8:49 am
This is the most usefull tutorial I’ve ever read. I’m a newby in flash, and the DisplayObjectContainer was like finding gold for my intent of making a reusable preloader. Thanks so much.
August 23rd, 2008 at 7:44 pm
I am trying out your tutorial but I’m getting an error.
Line 32: 1084: Syntax error: expecting rightparen before 0000.
Any ideas?
August 23rd, 2008 at 8:41 pm
@Steve: Well, it’s just a syntax error, so take a closer look at your code again. It’s probably a missing closing brace or an omitted parenthesis.
August 23rd, 2008 at 9:50 pm
I too am trying to figure out what bracket or parenthesis is missing….
August 24th, 2008 at 10:18 pm
I’m having a hard time getting this to work. Is there any way you could post the .fla for download?
I’m also having difficulty dealing with the package call.
August 27th, 2008 at 10:12 pm
There isn’t a bracket or parenthesis missing, the webpage changed a lowercase x to alt+0215 “×” in the color code.
August 30th, 2008 at 9:57 am
Uenuku,
That was It! Thank you
September 11th, 2008 at 4:34 am
How do you go about integrating this with loading an image or something so that all the lines are shown? The way I have it right now it skips most of them since the image loads fast and doesn’t have time to count each percent number.
September 21st, 2008 at 3:41 am
I’d really like to add this to my library but I’m not getting the final step for implementation. I guess I’m below “beginner.” Without a sample .fla, I’ll just have to store this away for another day.
October 2nd, 2008 at 10:28 pm
I appreciate this tutorial but really need to agree with the others who mention the final step is puzzling. I’m completely new to AS3 and OOP, and while I appreciate a good challenge, it would be cool to have some closure on this awesome class!
November 27th, 2008 at 2:55 pm
Thanks man, this is superb!