Analog clocks have always fascinated me, not just because they look great (think sports watches) but the challenge they present. How do we animate an analog clock using a computer? Well I decided to once and for all answer this question and prove to myself I can do it. Here I will explain to you how I solved this little brain teaser using trigonometry.
Initial Analysis
The first thing we need to do is look at what an analog clock is. If we look at it mathematically we see that a circle with a radius, being the clock hand, rotated 360 degrees for a value of t between 0 and 59. The different hands can be represented by using a different radius size, but we will not worry about it for now. So lets consider just one hand of the clock, the seconds hand, all we need to do is make it rotate 360 degrees in a minute. We could just use the flash rotation property, but in order to make it more portable to other languages like C/C++ or Java we will only use a simple line drawing method. So we will limit ourselves to just using a line and calculating its end point everytime.
Calculating Clock Hand End Points
Note: A math coordinate system will be used until noted otherwise.
A line can be used to represent the clock hands, and by modifying the end point to represent movement of the clock hands. We do not need to worry about the start point, since it will just be the origin of our circle and will never change. But to calculate the position of the end point of the line (the point on the circle), cos() and sin() are what we will use.
P = (r * cos(angle), r * sin(angle))
This gives us our basic equation, now lets think of it in terms of computer graphics. Since the angle is relative to the Y axis and not the X axis like it is in the math world, we will flip the sin and cos functions to be:
P = (r * sin(angle), r * cos(angle))
Now, it is time to switch to graphics coordinates system, since Y positive in our new system points down instead of up like it does in the math system we do this:
P = (r * sin(angle), -r * cos(angle))
And add r to both in order to center it in the middle of the screen
P = (r + r * sin(angle), r - r * cos(angle))
Putting it all together
Now that we got all the math figured out lets put it all together. First thing to do, is to make a new scene and draw our clock using flash, everything except the clock hands. Next, lets write our code ClockHand class:
import flash.geom.Point;
class ClockHand
{
var angle:Number;
var radius:Number;
var endPoint:Point;
var startPoint:Point;
var thickness:Number;
public function ClockHand(angle, radius, startPoint, thickness)
{
this.angle = angle;
this.radius = radius;
this.startPoint = startPoint;
computeEndPoint();
this.thickness = thickness;
}
/**
* Computes a new end point for the clock hand and assigns the new clock hand as the current end point.
*/
public function computeEndPoint()
{
endPoint = calculatePointOnCircle(this.angle, this.radius, this.startPoint);
}
// Calculates the new point on the circle
private function calculatePointOnCircle(angle:Number, radius:Number, origin:Point):Point
{
var point:Point = new Point();
// since our angle is relative to the Y-axis and not X-axis we flip the sin and cos calls
point.x = origin.x + Math.ceil(radius * Math.sin(degreesToRadians(angle)));
point.y = origin.y - Math.ceil(radius * Math.cos(degreesToRadians(angle)));
return point;
}
private function degreesToRadians(degrees:Number):Number
{
return degrees * (Math.PI / 180);
}
}
And our main code:
import flash.geom.Point;
import ClockHand;
var clockRadius:Number = 100;
var date:Date = new Date;
var secondsAngle:Number = 6 * date.getSeconds();
var minutesAngle:Number = 6 * date.getMinutes();
var hoursAngle:Number = 30 * (date.getHours() > 12 ? date.getHours() - 12 : date.getHours()) + Math.floor(minutesAngle / 90) * 7.5;
var secondsHand:ClockHand = new ClockHand(secondsAngle, clockRadius, new Point(clockRadius + 20, clockRadius + 20), 1);
var minutesHand:ClockHand = new ClockHand(minutesAngle, 80, new Point(clockRadius + 20, clockRadius + 20), 3);
var hoursHand:ClockHand = new ClockHand(hoursAngle, 50, new Point(clockRadius + 20, clockRadius + 20), 6);
secondsHand.computeEndPoint();
minutesHand.computeEndPoint();
hoursHand.computeEndPoint();
_root.createEmptyMovieClip("holder",1);
drawClock();
// Draws the clock hands and updates the digital display
function drawClock()
{
holder.clear();
drawLine(hoursHand.startPoint.x, hoursHand.startPoint.y, hoursHand.endPoint.x, hoursHand.endPoint.y, hoursHand.thickness, 0x880000);
drawLine(minutesHand.startPoint.x, minutesHand.startPoint.y, minutesHand.endPoint.x, minutesHand.endPoint.y, minutesHand.thickness, 0xFF0000);
drawLine(secondsHand.startPoint.x, secondsHand.startPoint.y, secondsHand.endPoint.x, secondsHand.endPoint.y, secondsHand.thickness, 0x000000);
digitalTime.text = (date.getHours() < 10 ? "0" + date.getHours() : date.getHours()) + ":" +
(date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes()) + ":" +
(date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds());
}
function drawLine(srcX:Number, srcY:Number, dstX:Number, dstY:Number, thickness:Number, color:Number)
{
holder.lineStyle(thickness, color, 100);
holder.moveTo(srcX, srcY);
holder.lineTo(dstX, dstY);
}
The final step is to make sure you have at least 2 frames in your main program in order for it to run continually and update our clock. On my initial attempt I have tried using setInterval() with an interval of 1000 (1 second) and incrementing the clock myself. However I quickly learned that setInterval does not gurantee the function will be called exactly every 1 second, and thus should not be used like that. We can use a setInterval shorter than 1 second, but relying on the play-head in flash is simpler.
Here is the final result:
Add this page to your favorite Social Bookmarking websites
Last Updated on Thursday, 14 April 2011 22:10
More articles :
» Getting Reliable z-index Cross-Browser
Turns out it is not as easy as one might think to get thecorrect z-index of an element using a javascript call like $(element).css(‘z-index’). The problem is how browser vendors apply the z-indexto an element. But, no worries I have created a...
This article will walk you through creating a python script to download all files on a web-page as fast as possible. The same script can then be used to download all sorts of content on the web, especially when combining the code with a web crawler....
OpenGL is a very powerful graphics library that is more commonly used for 3D graphics, but what about 2D graphics? Well there is little to no documentation on how to use it for a pure 2D application. This is exactly where this article comes-in.
If you ever tried inserting javascript into a Joomla article you may find it is a very difficult task; so, I went a head and made a plug-in to make this fast and easy. The reason why joomla makes it so difficult is because cross site scripting...
Pop-up window management poses a challenge in itself, but with an elusive Firefox bug effecting this process, it may seem impossible to do it well. I will present you with an account of my struggle with this issue and the simple solution I found for...
Comments
RSS feed for comments to this post.