Creating an analog clock with ActionScript using no design
tools whatsoever!
I am most pleased to be able to show you how to create an analog clock in
Flash using ActionScript only.
You won't be touching any tools whatsoever. This is just about programming in
Flash. Also, there is no timeline animation involved and no layers. And, this
works in Flash MX, Flash MX 2004 and Flash 8.
Just look at the flash example below to see what is possible with
actionscripting only.
That's right, even the shine on the left side of the clock frame was made
with actionscript, just like the lines marking the hours and the minutes, and
the clock hands too.
In this tutorial, you will make a simpler clock (but completely functional
like the one above). At the end, I will briefly explain you how the stylish
details were made and you will have the source for both clocks available for
download.
Setting up the base movie clip for the clock
1. Open a new Flash document. Save it immediately so that
you can just press CTRL+S later.
2. Name the first layer (and only one in this project)
actions.
3. Select the first keyframe. This will be the only one, too
- remember, there is no timeline animation here.
Select Window > Actions to open up the Actions panel for
the frame you just selected. If you are new to actionscripting, know that all
actions placed on this (first) keyframe will be executed immediately upon
loading of this movie.
The above piece of code creates a new movie clip out of nothing. The keyword
this designates the object this piece of code is placed upon. As in
this particular case the code is placed on the main timeline, the keyword
this denotes the main timeline - this means the flash movie
itself.
The createEmptyMovieClip command creates a new movie clip,
obviously. There are two parameters between the parentheses which must be
included if everything is to function as intended.
The first one is the instance name - "clock". That means the
name of the movie clip you are creating. You need to specify it, because you
wouldn't be able to manipulate the movie clip later if it has no name by which
you can reference it. And, you have to put the name between quotation marks,
otherwise flash will think that it is a variable and not an instance name you
are talking about.
The second parameter is the depth of the movie clip. Think of that as a layer
created with actionscript. The bigger the number, the higher the stack position
of the movie clip. It means that the movie clip with, say, a depth of 50, will
be in front of (on the screen) a movie clip with a lesser depth, like 40 or 6,
or 11, etc. I put the depth 3 arbitrarily.
REMEMBER When creating a movie clip with the
createEmptyMovieClip method, always give it a unique depth
parameter. If you were to create a new movie clip after that, with the same
depth as the previous one, that new movie clip would erase completely the
previous one. Also, if any of the two parameters are missing (instance name or
depth, or both), the creation of the movie clip will fail completely.
The next two lines are positioning the newly made movie clip on the stage.
This is necessary because when you create a new movie clip using the
createEmptyMovieClip method, it is by default positioned in the
upper left corner of the stage, with the coordinates (0,0).
So the clock._x = 150; line positions the clock movie
clip 150 pixels to the right from the left stage edge. The second one positions
it 150 pixels down from the top edge of stage (the positive Y coordinates are
below the top stage edge in flash). There is no this keyword at the
beginning of the two lines because the movie clip was created on the main, or
root, timeline in the first line of code, so you just write its name
(clock) and flash will look for it on the root timeline.
If you test your movie at this point, you won't see anything, but the movie
clip is created and positioned on stage. If you are still not convinced :) then
select Debug > List Objects while in the test movie mode.
Flash will nicely list the movie clip.
Making the circle - the clock's frame
5. Add this actionscript code after the existing one:
Test your movie. You should have a circle drawn by flash like the one
below showing up.
Looks nice, huh? :) And how does this work? Let me explain you.
First, you created a new movie clip using the
createEmptyMovieClip command. This new movie clip is created inside
the clock movie clip. Now why do that instead of repeating the same
thing as you did in the beginning, using the this keyword?
Because if you move the original, the base movie clip clock, to
another position on the stage (let's say you changed the layout of your flash
site), the newly created circle would stay on the old position.
But, when you create the circle movie clip
inside the clock movie clip by using the
line
clock.createEmptyMovieClip("circle", 1);
this problem is solved. Now, if you decide to move the clock, the
circle will follow it. In that way, you have all things situated inside
the clock movie clip.
The line
clock.circle.lineStyle(4, 0x000066, 100);
sets the style of the line before the drawing starts. You
always have to do this. If you're not familiar with actionscript drawing
commands, I suggest you go and read the basic
drawing with actionscript tutorial.
The line clock.circle.moveTo(100, 0); moves the circle
movie clip's starting position for drawing. Note that the starting position of
drawing for a movie clip is its registration point, which is the zero point of
its own coordinate system. The stage is no longer used as a reference.
Why did you have to move the starting position for drawing? I will explain it
in a moment.
The line circleRadius = 100; is where the
circleRadius variable is defined and its value is 100. This value
defines the radius of your clock's frame.
Now comes a for loop that actually draws the circular frame for
your clock.
This loop repeats 360 times. That's because there are 360 degrees in a circle
and this piece of code is drawing the circle from point to point.
The first line inside the loop defines the radAngle variable.
This variable's purpose is to store the angle for calculating the drawing points
of the circle, in radians. This is necessary since the
next two lines of code use flash's built-in math trigonometric functions which
work with radians instead of
degree values.
So the expression a*Math.PI/180 is a
simple mathematical formula used to convert degree values into radians. Here is
a little basic math reminder:
This angle increases every time as the loop increments. It stops when it
comes full circle (pardon the pun) from 0 to 360 degrees.
Now comes the interesting part in which I will explain to you how the
trigonometrical functions are used to draw the circle.
The actionscript trigonometric functions used to find the coordinates for
drawing explained
The X coordinate is found with this piece of actionscript:
xCoord = Math.cos(radAngle)*circleRadius;
It is stored in a variable called xCoord.
What does the right side of the expression do? I'll explain a little bit of
high school math now. Wait. Wait! Don't run away :) It IS easy. And it is fun
once you see the possibilities and creativity it offers you. I pretty much
shunned away all the math after my studies, but once I lay my hands on Flash and
saw that I had to implement it if I wanted to do some advanced actionscripting,
I quickly remembered and looked up what I needed. So will you! Continue and
you'll see how interesting and cool math is!
So, you need to know the coordinates of every point on the circle to draw it.
How do you find a point on a circle? Simple, with two pieces of data you already
have. The angle and the radius. Look at the diagram below.
I took an angle of 30 degrees arbitrarily for the purpose of
explaining this calculation. So, you're looking for the X and Y coordinates of
the T point on the circle.
The X coordinate of the T point equals to the
distance a on the diagram, which is the distance from
the starting point (0,0) to the
x point on the diagram. How to find the value of this
distance? With trigonometry.
The triangle formed with the sides a,
b and c in the diagram is a
right triangle. It means there is a right angle (90°)
inside it. It is found between the sides a and
b. There are some great trigonometrical functions that
can be used with this kind of triangle.
The cosine of an angle (the angle is marked with
the greek letter lambda - λ) is the ratio of the
length of the triangle side adjacent to the angle (a
in the diagram) to the length of the hypotenuse (the hypotenuse being the side
opposite the right angle, c in the diagram). So, the
formula goes like this:
Written in a single line it goes like this:
cos λ = adjacent side / hypotenuse
If you apply the distances from the diagram to the formula, it would turn out
this way:
cos λ = a / c
In your actionscript code, the angle λ is defined
in the variable radAngle and the hypotenuse
c is the radius of the circle, defined in the variable
circleRadius. What is left is the adjacent side
a, which is the X coordinate of the T point you're
looking for. That coordinate is named xCoord in your code. So, the
formula turned into actionscript looks like this:
Math.cos(radAngle) = xCoord / circleRadius;
But you're looking for the T point's X coordinate, right? So, the final line
of code you need looks like this:
xCoord = Math.cos(radAngle) * circleRadius;
And that's it! The similar explanation goes for the Y coordinate. You're
smart so just look at the diagram and apply the same logic to discover the
explanation for finding the Y coordinate value.
So after finding both coordinates for each point (360 points in total because
that's the number of iterations the loop is going through),
flash finally draws the line by executing the following code:
clock.circle.lineTo(xCoord, yCoord);
OK, the method lineTo draws the line to the coordinates
specified within the parentheses. But where does the line start? Where is it
drawn from?
This was defined in the line
clock.circle.moveTo(100, 0);
before the loop. After that first line is drawn, the loop passes to the next
iteration and draws from the last point (as drawing in flash is set up to do, if
there was no moveTo command in between) to the next one, which is
again calculated with the aid of the cosine and sine functions.
But, you ask again, why did I used the moveTo command to move to
the point (100, 0) and not some other point?
Because the calculation for the first angle is for the 0
degree angle, which is situated at three o'clock in flash. That's why you need
to move the starting point for drawing here, so that it continues naturally
following the circle.
Look at this diagram explaining it.
I put a lot of distance between the three marked points to make the diagram
more easy to read. In reality, these points are right next to one another.
So, the first point (100, 0) is right on the horizontal axis of the circle.
This is where the drawing will begin, this was done with the moveTo
command explained above.
Soon after this line of code, the loop begins and the first point on the
circle (T1) is calculated. A line is drawn from (100, 0) to
(T1) with the lineTo command which follows the
calculation of the point. The loop goes through the next iteration and
calculates the coordinates for the second point (T2). A line is drawn
from the previous point (T1) to this one (T2).
And this goes on until the loop ends, that is, after 358 more iterations. So,
I suppose you got the trick by now: the circle is in fact a 360-sided polygon!
But the sides of the polygon are so close that it look like a circle. Cool, no?
Absolutely cool! :)
Creating the markings for the hours and the minutes
The circle with the main concept of advanced drawing with actionscript being
thoroughly explained, it's time for you to create the markings for the hours and
the minutes.
The method used is the same, with some differences and catches.
6. Type in the following lines right after all the code you
entered so far:
Test your movie. The markings for the hours will appear. Let me quickly
explain you how this is done.
The first line changes the style of the drawing line, so that it appears
thicker. You can make it any color and thickness that you want, but the
important thing is to make it more prominent than the minutes' markings.
Remember, the time must be easily redable from the clock. Be nice to your
users!
There is the circleRadius variable again, which is listed here
for easier comprehension. There is also a new addition,
smallerCircleRadius. These two circle radiuses will make it
possible to draw a line from the outer circle to the inner circle.
The loop has only 12 iterations now, which makes sense because this is the
number of the hours' markings on a standard analog clock.
Inside the loop, the first line of code defines the angle at which the
calculations are made. This angle is the loop's iteration multiplied by 30.
I hear you asking: why? :)
Because a full circle has 360 degrees, and there are 12 hours on an analog
clock. So by multiplying each iteration number (0, 1, 2... till 11) with 30, you
obtain the angles at which the markings for the hours must be positioned.
After the conversion of the angle from degrees to radians (the same formula
as in the previous step), there are two pairs of coordinates calculated,
followed by a moveTo command that defines a new starting drawing
point for each iteration, and then drawing with the lineTo
command.
Look at the diagram on the left
to see how easy it is to understand this.
I put the points on another part of the circle, but this is applicable on all
of it.
After placing the drawing position on B1, it draws the line to
S1, which is found on the inner, smaller circle. The lines are drawn
perfectly pointing at the center of the circle because the angle calculated is
the same for the small and the big circle in each iteration. Then flash moves
the starting drawing position again, this time to B2, and draws the
line to S2.
It is easy once the main concept is grasped, isn't it?
You should create the markings for the minutes now, using a thinner line this
time.
7. Place the following actionscript at the end of your
current code:
The only thing that needs to be noted at this step is that
I changed the radiuses for both circles, so that the minutes' markings are a
little bit shorter than the hours' markings.
This loop goes through 60 iterations because there are 60 minutes in an hour.
Inside the loop, this number is multiplied by 6, to get the right angle for each
minute's marking. Similar calculation as before: 360 degrees in a circle, 60
minutes in an hour. 360 divided by 60 yields 6. The rest (moving and drawing) is
as same as for the hours' markings.
Test your movie. Cool! You should have the same result as in the image on the
left (the screenshot on the image is scaled down).
Drawing the seconds, minutes and hours hands
You'll now proceed to make the clock's hands. This is a little bit simpler
than circle drawing with actionscript :)
Test your movie. You should see the hours hand appear.
This is simple, you only need to be careful about some details. At first, the
movie clip is created. Its depth is set above the circle movie clip's
hand, because you want all the hands to be above the circle and other
drawings.
A thicker line is chosen for drawing style. Next, the beginning of the
drawing is moved to (0, 0). This is very important. This is the registration
point of the hours hand movie clip and it is around this point that the hand
will rotate.
This is the code to create the minutes and the seconds hand.
Note that each hand movie clip's depth is bigger than the previous one. In
that way, the clock hands are stacked one on top of another. I chose the depths
20, 30 and 40. It could have been 11, 12 and 13 or any other three numbers. But
it is always wise to let some "space" between the depths. You never know, you
might decide to add something in between later and then you'll be glad you did
this.
Test the movie and you'll see the hands stacked one on top of another.
Setting the clock in motion
Yes! Finally, you get to start the clock! Just a liiiiittle bit more!
Test your movie. The seconds hand should tick! This is the best way to check
if your clock is working.
This portion of code creates a function assigned to the circle movie
clip's onEnterFrame event. This means that the function will get
executed as many times per second as there are frames per second set in your
movie's speed (fps option in your document's properties).
Inside the function, there is a new date object created. This is obligatory
if you want flash to tell you what time or date it is. The lines
The this keyword points to the clock movie clip, since
it is situated in a function which is assigned to this same movie clip's
onEnterFrame event. So, this.secondsHand points to the
movie clip secondsHand which is placed inside the clock movie
clip. Just simple actionscript paths.
Now, the _rotation property of these movie clips is what is
found on the right side of these code lines. The _rotation property
value is expressed in degrees.
Why are the minutes and seconds multiplied by 6?
For example, let's say that flash just read the time which said it is exactly
15 seconds now. This means the secondsHand movie clip should be
pointing at 3 o'clock. This is 90 degrees in relation to its starting position
of 0 degrees. That's why you have to multiply by 6. This is what happens at
runtime:
this.secondsHand._rotation = seconds * 6;
this.secondsHand._rotation = 15 * 6;
this.secondsHand._rotation = 90;
NOTE The initial value for the
_rotation property of any movie clip is 0 degrees, which is
pointing straight upwards, in contrast with the sine and cosine values discussed
in previous steps of this tutorial, which point at the right side, horizontally.
OK? Don't confuse these two values, who have nothing to do with one another.
The same is with the clock's minutes hand.
But there is a difference with the hours hand. Its code says
it would work, but in a misleading way. The result of the equation on the
right side of the expression would be the following: let's say it's 11:50 now.
11 multiplied by 30 would yield 330, which means 330 degrees, which points right
to 11 o'clock. This is ok, right?
No. It is not good! The hours hand would point
straight at 11 o'clock, while it is 11:50. This means
the hours hand should be pointing almost at 12 o'clock at this time. Just look
at the image below to see what I mean.
Imagine you have to be somewhere at noon. This particular clock makes you
think it's almost 11 o'clock, instead of 12. Now you would miss that great
movie, blind date or work interview (hopefully in the web design field). OK. How
to correct this?
So, when it's, let's say, 11:30 (I'm not using 11:50 because 11:30 is easier
to understand), the hours hand should be positioned right between 11 and 12 hour
markings. So that's why you add the minutes divided in half.
Imagine it is 11:30. The calculation would go like this:
That's it - with this addition you get just the small increment you need to
make the hours hand point to the right place.
You just finished the actionscript clock! Whoaaaa! Cool!
The advantages of the actionscript-only clock
Just so that you know, the SWF generated from this flash document has a
filesize of only 760 bytes!!! Do you realize what this means?
This means you can place this clock in an intro, preloader or in a banner!
And it will load instantly, even on slower connections! Now that is radical!
With this clock, you rule. Your site rules. Your client's site rules.
And, what's completely cool, this is written in ActionScript 1.0 and
compatible with flash player 6 and above. So be sure to set the ActionScript
version to 1.0 and the Flash player version to 6.0 in the Publish settings
dialog if you are working in Flash 8 or Flash MX 2004.
You can also change the line thickness, colors and alpha of all the elements
of the clock with just a few keystrokes. No re-editing or re-drawing. Just
change the code! This lesson's source files (both the simple clock and the one
with the shining frame) can be downloaded below.