The Missing Stopwatch Example

A big congratulations to Alexey Gavrilov over at Metalink, who published his first article on DevX. He does a great job of covering Silverlight, AIR and JavaFX as broadly and as fairly as possible. My only complaint is that he chose Flex as the basis for his AIR application. AIR supports both Flash/Flex and HTML workflow’s, and to that end, I’ve stepped up to provide the missing HTML version of the stopwatch example application used in his article.

Alexey provides various assets with his DevX article, and among those assets is the artwork for the stopwatch application. Some of the artwork is in vector format, which as you might image presents a challenge for an HTML version of this application. He does however mention, that he used Inkscape as a vector tool. As it turns out Inkscape also has an “Export as Bitmap” which I used to get the basis for the user interface.

stopwatch.jpg

A quick note here in that I couldn’t get Inkscape to work on the latest Mac OS. There’s apparently a conflict with the X11 library used by the application. I also could not get the SVG documents to open in Illustrator CS3. After inspecting the SVG source code, I’m assuming this has to do with some of the Inkscape namespaces. Luckily I keep VMWare on tap (thanks Adobe IT) and was able to run Inkscape and export the necessary bitmap assets pretty easily.

Assembling the user interface in HTML was painless. There’s the background, two buttons, and a background ellipse for the digital display. A little CSS made this a snap.

<html>
<head>

<title>Stopwatch</title>

<link href="stopwatch.css" type="text/css" rel="stylesheet" />

<!-- AIR JavaScript aliases for common classes -->
<script src="lib/AIRAliases.js" type="text/javascript"></script>

<!-- The stopwatch logic -->
<script src=”lib/stopwatch.js” type=”text/javascript”></script>

</head>
<body onLoad="doLoad();">

<!-- The various parts of the stopwatch UI -->
<!-- Does not include the hands of the watch -->
<img id="back" src="images/sport_bg.png" width="241" height="233" />
<img id="start" src="images/start_btn.png" width="57" height="34" />
<img id="clear" src="images/clear_btn.png" width="39" height="30" />
<img id="digital" src="images/dig_background.png" width="71" height="17" />

<!-- Digital time display -->
<div id="time">00:00:00.00</div>

</body>
</html>

If you’re observant, you’ll likely notice that there’s two very important assets that are missing — the two stopwatch hands. Placement wasn’t an issue, but how does one rotate an image in HTML? It turns out that the HTML 5 specification includes a CANVAS tag, which was apparently originally proposed (added?) by Apple. The problem is that the documentation on the tag, specifically the 2D context, is abysmal. I gave up after several hours of trying, and decided to take an alternative approach.

You see, rotating assets in Flash is a snap. Animation is obviously a core competency of Flash, and rotating assets falls right into that domain. Since I’m building an AIR application however, I have access to everything Flash offers, directly from JavaScript. I figured I would load the images into the runtime via the Flash Loader class. The Loader class inherits from DisplayObject which has a rotation property. The DisplayObject.rotation property takes a numeric value representing the angle in degrees.

// Create a Loader object
bhand = new runtime.flash.display.Loader();

// Position the object on the face of the stopwatch
bhand.x = 117;
bhand.y = 117;
// bhand.rotation = 45;

// Translate the image once it has actually loaded
bhand.contentLoaderInfo.addEventListener( air.Event.COMPLETE, doBigLoaded );

// Load the image from disk
bhand.load( new air.URLRequest( 'images/big_hand.png' ) );

// Add the Loader instance to the UI
window.htmlControl.stage.addChild( bhand );

Objects in Flash, like the HTML CANVAS proposal, are rotated around the upper-left corner (0, 0) in a clockwise direction. In this case, we don’t want the hands to rotate around their tips, but rather a specific center point. To accomplish this task, I wait for the image to load, and then move the loaded content (a PNG in this case) such that the desired center point of the hand is over the upper-left corner. This way, when the rotation is applied, the stopwatch hand will stay centered.

// Called when the image of the "big" hand has been loaded
function doBigLoaded( e )
{
	// Translate the rotation point of the image
	bhand.content.x = -8;
	bhand.content.y = -96;
}

The core animation, which Alexey mentions in his article, but doesn’t cover, is managed in JavaScript through setInterval() which calls a method every millisecond. The duration of time from when the start button was pushed, to when the method is called is determined, and an appropriate angle is calculated from that value. It’s actually a fair bit more involved, and I’ve included the source code for you to peruse.

Managing the interactivity on the start and reset buttons is done through traditional event listeners. The window as an AIR application can also be moved freely around the desktop. I added a traditional event listener via the DOM to the background image, and when that gets clicked, the application invokes the native window move operation.

// Called when the background of the clock is clicked
function doMove()
{
	// Handle the native moving of the window
	window.nativeWindow.startMove();
}

There are numerous way to test an HTML-based AIR application, which include Dreamweaver CS3, Aptana and the good old command-line SDK. Each of these approaches also provides there own means for application packaging. There’s something here for everybody’s workflow, whether you prefer a hard-core IDE, or just the console. Just for the sake of documenting the least common denominator, the testing and packaging command-line statement look as follows in my configuration.

./adl ../../../Sites/stopwatch/application.xml
./adt -package stopwatch.air ../../../Sites/stopwatch/application.xml -C ../../../Sites/stopwatch/ /

There are two compelling parts about this little project. The first is that using nothing more than the free SDK, your existing HTML, CSS and JavaScript skills, and a splash of AIR, you’re now running a desktop application. The second compelling part is that splash of AIR, which in this case meant reaching over to Flash, via JavaScript, to pick up where HTML left off. This hybrid ability is among my favorite features of AIR, and I encourage you to explore the possibilities.

Note: I’m really unhappy with the quality of the hands, which are bitmaps, as they are rotated. It works, but it looks pretty rough. Ideally, I’d like to have Illustrator create SWF files in place of the PNG images I used. The above code wouldn’t change outside of pointing to the SWF and not the PNG, but the results would prove to be substantially cleaner.

6 Responses to “The Missing Stopwatch Example”

  1. Flex and Flash Developer - Jesse Warden dot Kizz-ohm » Blog Archive » Silverlight First Impressions Says:

    [...] done, the better in my opinion. Looking at the Silverlight / AIR / JavaFX Stopwatch example (HTML version here), you can definitely do custom controls, but they don’t seem to be built into the language as [...]

  2. FL Says:

    Nice post.. Thank you for information.

  3. Radu Antohi Says:

    Thanks for this example Kevin!

  4. Simon G. Says:

    Nice Stop Watch and also very nice article, thank you very much Kevin for sharing such a nice kind of example.

    Simon G.

  5. butter Says:

    Thanxs kevin for making this simple

  6. Directorio Says:

    Look nice these Stop Watch and useful the post. Thanks and keep good work mate.

Leave a Reply