
Tutorial: How to build an analog clock
Greetings,
As promised, I'm posting a simple tutorial on how to build an analog clock. As opposed to digital clocks, analog clocks don't display digits but rotate hands. Nevertheless, the steps for building an analog clock are the same.
Step 1: Create your images
An analog clock needs a background image and three hand images: for the hour, minute and second hands. The background is usually round while the hand images are thin and long; the minute hand is longer than the hour hand. Let's say you created the images below:
Step 2: Position your images
In order to make your clock tick, you need to position the three hands in the center of the round background. This is not difficult, but you need to be a bit more careful than with a digital clock. Because you'll be rotating the hands around this position, there are a couple of things to keep in mind to make your life simpler:
* Create your hand images vertical pointing up. This will allow you to correlate the rotation angle directly with the hour (i.e. have a 0 degrees rotation at 00:00:00)
* Create your round background with an odd number of pixels. This will cause the background to have the center in a pixel (and not between two pixels). For instance, a 105x105 pixels background is OK and will have the center at position 53x53, but 100x100 is not OK (see picture below).
* The same applies for the hand widths. Create hands 1, 3, 5 etc. pixels wide rather than 2, 4, 6 etc. Determine the rotation point for each of the three hands as the offset from the upper left corner of the image. Take a look at the image below and observe how these offsets are calculated.
Step 3. Write the widget code
Your widget needs to display the background and the three hands centered with the background. You will also need to specify the rotation point for each hand. This step will probably take the most time in building your widget.
<?xml version="1.0" encoding="utf-8"?>
<widget version="1.0">
<debug>on</debug>
<window title="clock">
<image src="background.png" />
<image src="hour.png" hRegistrationPoint="3" vRegistrationPoint="33"
hOffset="53" vOffset="53" name="hourhand" />
<image src="min.png" hRegistrationPoint="3" vRegistrationPoint="42"
hOffset="53" vOffset="53" name="minhand" />
<image src="sec.png" hRegistrationPoint="1" vRegistrationPoint="42"
hOffset="53" vOffset="53" name="sechand" />
</window>
</widget>
The rotation point is specified with the hRegistrationPoint and vRegistrationPoint attributes. You will need to give the hand images names in order to move them from your code.
Step 4. Start the clock
And now, the fun part. Translating the hour into rotation angles requires a tiny bit of trigonometry. The simplest way to make the clock tick is to add a function that updates all the hands based on the current time. Then, call the function when the widget starts (in the onLoad action) and every second (in the onTimer action).
<action trigger="onLoad"><![CDATA[
function updateClock() {
var now = new Date();
var hour = now.getHours();
var min = now.getMinutes();
var sec = now.getSeconds();
hourhand.rotation = (hour + min / 60) * 360 / 12;
minhand.rotation = min * 360 / 60;
sechand.rotation = sec * 360 / 60;
}
updateClock();
]]></action>
<action trigger="onTimer" interval="1"><![CDATA[
updateClock();
]]></action>
That's it! Your clock is up and running. Now you can start tweaking it the way you want.
Speaking of tweaking, I saved a little cookie for the last part: if you played with a few analog clock widgets you probably observed they have a neat animation of the second hand. That is, every second, the hand moves a bit past its resting position and then immediately comes back, simulating a mechanical recoil. In order to achieve this, you need to make these smalll changes to your code:
* Add a <timer> object to your widget, with a very short interval of 0.05s
* In the updateClock function, make the second hand move 0.5s past its exact position, and start the timer object
* When the timer fires, stop it and return the second hand to its correct position
Your code will look like this:
<action trigger="onLoad"><![CDATA[
function updateClock() {
var now = new Date();
var hour = now.getHours();
var min = now.getMinutes();
var sec = now.getSeconds();
hourhand.rotation = (hour + min / 60) * 360 / 12;
minhand.rotation = min * 360 / 60;
sechand.rotation = (sec + 0.5) * 360 / 60;
sectimer.onTimerFired = "updateSecondHand(" + sec + ")";
sectimer.ticking = true;
}
function updateSecondHand(sec) {
sectimer.ticking = false;
sechand.rotation = sec * 360 / 60;
}
updateClock();
]]></action>
<action trigger="onTimer" interval="1"><![CDATA[
updateClock();
]]></action>
<timer interval="0.05" name="sectimer" />
For your convenience, I've included
a zip file with a sample analog clock.
If you haven't already, you can also read the
tutorial on how to make a digital clock.
Radu Galesanu