This project demonstrates how to use the timer class as well as how to do some complex math to build a backwards countdown timer. While it appears simplistic, accounting for un-even length months and localized time zone offsets adds some complexity.
Solution
This recipe also demonstrates how to include multiple MXML components in one project and how to reference them. Prayank Swaroop and I wrote this last year and just ported it to Flex Builder 3, beta 3.
Detailed explanation
The basic structure of this project is as follows:
To include the //utils/SimpleClock.mxml components in the project, it is as simple as adding one attribute to the first line of the application as show below in bold:
This tells the compiler to look in the folder "utils" and include any components in that folder. You can then add them to your project by using the namespace to qualify them as shown below:
Note that code complete in Flex Builder 3, beta 3 will automatically include any inherited properties, events etc.
The AIR3_BackwardsTimer.mxml class is as follows. You can also download the source below and import the finished project.
*****************SOURCE***********************
<?xml version="1.0" encoding="utf-8"?> <mx:WindowedApplication showFlexChrome="false" xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" xmlns:utils="utils.*" creationComplete="init()" height="154" width="465"> <!--Note the use of @showFlexChrome="false". Without this, you will still end up with some AIR chrome. --> <!--The line xmlns:utils="utils.*" declares the namespace and references anything in the utils folder --> <!--creationComplete="init()" calls the init() function once the app has created itself-->
<!--The Style tag below declares the CSS to make the application fully chromeless--> <mx:Style>
private var MAX_DATE:Date = new Date(); private function init():void {
// Move the app when the panelis dragged mainPanel.addEventListener( MouseEvent.MOUSE_DOWN, startMove );
function startMove(event:MouseEvent):void { stage.nativeWindow.startMove(); } // This set the specific date as the 30th of the month. MAX_DATE.setDate(29); countDownClock.countDownDate = MAX_DATE; } // This makes the close button work. public function closeEvent(event:CloseEvent):void { stage.nativeWindow.close(); }
The SimpleClock.mxml component is where all the heavy lifting is done. Note that all counts of arrays of days, months start at zero and not one. Also note the complex math involved in calculating the days, months minutes, seconds remaining. Lastly, there is a simple function call to get the time zone offset to account for the users local time.
<!-- Simple clock class to return a string representing a count down to MAX 2007. This can be modified to return a Date object instead of a string object Authors: Prayank Swaroop, Duane Nickull 2007. No warranties exist - use at your own peril. We warned you. Send complaints to dev@null.net --> <mx:Label xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="init()"> <mx:Script> <![CDATA[ public var countDownDate:Date = new Date; // countDownDate.getDate();
private function init():void
{ //public var countDownDate:Date; // creates a Timer that fires an event once per second var ticker:Timer = new Timer(1000);
// designates the onTick() method to handle Timer events ticker.addEventListener(TimerEvent.TIMER, onTick);
// starts the clock ticking ticker.start(); }
public function onTick(evt:TimerEvent):void
{ // updates the clock display //this.text = getCountDown(countDownDate.getTime() - (new Date()).getTime()); this.text = getCountDown(countDownDate.getTime());
}
protected function getCountDown(uptime:Number):String
{ //current date var currentDate:Date
// get current Date currentDate = new Date();
//initialize event variables. Seconds are using Math(). var eventMonth:int = 10; //Nov = 8 var eventDay:int = 15; //day = 16 var eventHour:int = 15; //the event starts at 8 AM local + 8 (-1 for starting at zero) for 15 GMT var eventMinutes:int = 0; // assume it starts right at 8:00 AM sharp. Yeah right....
//get time zone offset. Number returned in minutes. var currentOffset:Number = currentDate.getTimezoneOffset();
//check if we started if(uptime <= 0) return "MAX has begun!";
var secs:Number = uptime/1000;
// Construct String var result:String = new String();
// For debug only... //result += "Current UTC date is: " + currentDate + ". MAX 2007 is ";
// Build Result string //result += "MAX 2007 begins in ";
/*How many months until MAX 2007*/ var months2MAX:int = eventMonth - currentDate.getMonth(); result += months2MAX + " Months ";
/*How many days until max*/ var days2MAX:int = eventDay - currentDate.getDate(); result += days2MAX + " Days " ;
/* How many hours including the offset from users local time * - getHours returns the 0-23 value, adding in offset comes up with current GMT time * - subtract the event hour to get offset then subtract number from 24 to count down. */ var hours2MAX:int = 24 - ((currentDate.getHours() + (currentOffset/60))- eventHour); result += hours2MAX + " Hours ";
var minutes2MAX:int = (60 - currentDate.getMinutes()); result += minutes2MAX + " Min ";
result += (60 - currentDate.getSeconds()) + " Sec" ;