Understanding Date(): Making a Calendar in AS3

Today we'll build a fully functional calendar widget using AS3. It's not rocket science, just an excellent example of using the Date class, which can handle all the complexity of extracting times, dates, months and years. We are also going to use some Flash components, and make sure that this calendar is portable to Flash Builder, FlashDevelop, and so on.


Final Result Preview

Let's take a look at the final result we will be working towards:


Step 1: Brainstorming

Before starting to build the code, let's take a look at what we'll need:

  • A class file, Calendar.as,
  • A cell grid, to place dates,
  • Labels for day names,
  • Function to get current date, month and year,
  • Function to get previous months' days,
  • Function to get future months' days,
  • Something to address the leap year issue,
  • Interface to pick any month and year,
  • Portability (for Flash Builder, FlashDevelop, and other IDEs).

Step 2: Preparing the Calendar.as Class File

In this step we shall create a basic structure of our Calendar.as class file.

There are several ways of creating ActionScript class file, like using FDT, Flash Builder, FlashDevelop. And, of course, the "Higgs Boson" of this multimedia world: the one true Flash IDE. I am using Flash Professional. Create an ActionScript 3.0 class file. The following is the basic structure of Calendar.as to start with.

I am sure that you have saved this class file as Calendar.as in the new folder for this calendar app. If not please save it.

Step by step we shall modify this Calendar.as to make it fully functional.

In the next step we will create a few text fields to label the weekdays and dates.


Step 3: Setting Up Text Formats for Dates and Weekdays

In this step we will modify our class by declaring some variables and creating a new function setTextFormat( fontFace, fontSize ).

We will also passing some parameters to the constructor of the class.

Initially it will look like "Syntactic Sugar", but as the tutorial progresses it will become "Syntactic Salt". Sorry, but we want to keep this class compact so as to make it easily portable. The idea is to have only one class and that's all.

So, keep a close watch on the constructor's number of parameters and their order as we progress.

Back to modifying the document class...

Observe all the parameters passed to the constructor: we have already assigned values to them. This is the way to create default values for parameters. If no parameters are specified when instantiating the class, these default values will be used instead. We will see this in coming steps.

Nothing visible yet. Wait for a few steps.


Step 4: Creating Cell Grid to Arrange Dates

The calendar is made up of rows and columns forming a grid.

But how many rows and columns?

It depends on the calendar type - Vertical or Horizontal.

Vertical view needs 7 (rows) x 6 (columns), while horizontal view needs 6 (rows) x 7 (columns) as shown:

Horizontal and Vertical Calendars

As our calendar is limited to horizontal view for this tutorial, we will need 7 columns and 6 rows. Thus total (7 x 6) = 42 cells.

So, let us modify our class so that it will generate a grid required for calendar view. Along with adding an import statement, new variables and constructor parameters, we will also add a new function makeDatesCellGrid(..) to the class as shown:

Oops, lots of code is written and nothing visible yet. I know you are waiting to see some visible results. For that we will make a temporary change in makeDatesCellGrid by adding a new line as shown:

Wait...Wait. Now create a new Flash file for ActionScript 3.0 and save this file with any name (ideally Calendar.fla as I did) in the same folder where you saved Calendar.as. Now open the ActionScript panel by pressing "F9" and type the following code:

Now test the movie.

DateCellGrid

There are a few things to fix, like setting up the dates for current month, labels for days, etc.

Also note that though the constructor can take parameters, we saw a result without passing any values for parameters. This is what I was talking about in the previous step.

Observe the following two lines we placed inside the constructor,

We created these vars for global access. We have assigned values to these variables from constructor parameters.

We used "cellW" for placing cells in grid form. We will use "cellP", i.e. cell padding (the gap between neighbouring cells), in coming steps. So wait and watch.

One more thing. After testing above code, remove the line allDatesCells[i].text = i; from the makeDatesCellGrid(..) function. We added it for testing purposes only. Actually, we are going to put dates in those text fields in coming steps.


Step 5: Adding Names of Weekdays

In this step we will add labels for weekdays to our calendar. For that we are going to add a new function makeDaysLabels(...) and call it inside the constructor.

First of all, add new array weekDays[] at the start of the class under the //Variables declaration section. This array hold names of all weekdays as shown:

Now add the following function to the class.

Finally, call this function inside constructor as shown:

Weekdays are ready and waiting for dates to have their right places.


Step 6: Initializing and Decorating Dates' Cells

In this step we will make textfield background visible so that there's no need to draw a rectangle shape. But if you want to add more style then after completing this tutorial go ahead and create rectangle instances as dates' cells background and add a gradient color to them. For now it's ok to set the textfield's background to true and apply a solid color to it.

Add the following new function to our class.

Then, call this function inside constructor as shown:

Test the movie.

Dates' Cell background

Cool... The cells are ready to hold dates for the selected month.


Step 7: Arrange Dates for Selected Month

We will add a new function arrangeDates(). This is the most important function for this Calendar app.

We will be completing the following must-do tasks through this function:

  • Creating date object from Date class.
  • Identifying the column number for first day of selected month.
  • Getting maximum number of days for selected month (with respect to leap year, if applicable).
  • Putting dates at correct places for selected month.
  • Highlighting today's date, if selected month is current month.

Pretty challenging tasks, but interesting.

Ok, back to the job. First we will declare some variables at the start of the class under the //Variables section as shown:

Here currDateTime gives the current time, today's date, and the current month and year.

firstDay gives all info about the first day (i.e. Date 1) of the current month. Observe that we have passed the value for third parameter as "1" for date. Try tracing with various dates to get an idea of what this is doing. But remember to make it "1" again after testing.

firstDayColumn, as the name suggests, gives the column number for the first day of current month,

daysOfMonths array holds maximum number of days from "January..." to "...December". But for "February" we have "28" days; in case of leap year we must assign "29" days as the maximum number of days for February. We will see it later in this step.

maxDays will hold maximum number of days for current month.

Fine. Good enough explanation for each var. It's time for new function arrangeDates().

In order to understand this function neatly, we will modify it gradually.

So first, In this function we will get the column number for first day (i.e. Date 1) of a selected month as shown:

This "firstDayColumn" is important since once we get column number for first day (i.e Date 1) then placing next dates becomes very easy. We will simply use this "firstDayColumn" number inside a for loop to place the next dates. We will see it soon in coming steps.


Step 8: Getting the Maximum Number of Days for Selected Month

We will modify the "arrangeDates()" function to get the maximum days for selected month as shown:

The above new line is a shorthand method for an if statement. New users may consider it "Syntactic Salt", but once used to it will consider it "Syntactic Sugar".

Observe the question mark "?" in the above line. On the left side of this question mark - i.e. "firstDay.getFullYear()%4 == 0 && firstDay.getMonth() == 1" - is a conditional statement. If this left side is true then the statement after the "?" mark (here 29) is executed; if it is false the statment on the right of the ":" mark (here daysOfMonths[firstDay.getMonth()]) is executed. See the image below for a better understanding.

Short hand method for if statement

Ok, back to our shorthand if statement. It gives the maximum number of days for selected month. But you have to consider leap years, too. In a leap year, February has 29 maximum days. This leap year comes every fourth year.

So we have two conditions, one is to check if it is leap year and second is to check if it is February.

To check whether current year is leap year we used modulus operator (which gives the remainder after dividing one number by another), as in "firstDay.getFullYear() % 4". If it gives a remainder of 0 (zero) then we can say that it is a leap year. For example, 2012 is a leap year, as (2012 % 4 == 0). Similarly (2016 % 4 == 0), so 2016 is a leap year, and so on. If the remainder is nonzero then obviously it is not a leap year. Thus we can detect leap years.

(Editor's note: actually, there's a little more to it than that: years divisible by 100 are usually not leap years - unless they are also divisible by 400. To keep this tutorial simple, we'll omit that, but you can program it in if you wish!)

Now we will check whether the current month is "February". Before that let us consider the index number for months generated by Date class. It starts from 0 for Jan, 1 for Feb, 2 for March and so on. So to find out whether the current month is "February", we use "firstDay.getMonth() == 1". "1" for "February".

If both these conditions are true then we set maxDays = 29; otherwise we refer to the "daysOfMonths" array.


Step 9: Placing Dates of Selected Month at Their Positions

Now we have "maxDays" and "firstDayColumn" with us so we are able to arrange dates for selected month.

Modify "arrangeDates()" as shown below,

We set "allDatesCells[firstDayColumn + i].alpha = 1" for date field as we are going to set previous and next month's date fields' alpha to 0.5 in coming steps. So we set alpha = 1 in advance to avoid returning to this function, since this function is almost finished.

Now "arrangeDates()" function has something to show. But we need to call it somewhere. The function "monthSetup()" is the right place to call this function.

So modify function "monthSetup()" as shown:

At this point you can test the movie.

Wow. exciting. See those dates at their positions.

Dates at their positions

Step 10: Highlighting Today's Date

In this step we will highllight today's date. So modify the "for" loop in "arrangeDates()" as shown:

Test movie to see today's date highlighted.

We are very close to getting that "Calendar" feel. Once the dates of previous month and next month are placed, then we are done - for the current month, at least.


Step 11: Adding Dates of the Previous Month

We want to add dates from before the "firstDayColumn", so we will get all previous date fields in reverse order by using a decrementing "for" loop.

Add the following new function to the class:

Now call this function inside "monthSetup()" as shown:

Test the movie to see the previous month's dates placed at their positions.


Step 12: Adding Dates of the Next Month

In this step we will add dates of next month. Add the following new function to the class as shown:

Now call this function inside "monthSetup()" function as shown:

Test the movie to see dates of next month placed at their positions.

At this point our calendar is ready, displaying all the dates required in the current month's display. Now in the coming steps we will allow the user to select any month and any year, to complete the Calendar application.


Step 13: Adding the Capability to Select Any Month

Selecting any month will add more sense to our Calendar. To select any month from the list, the "ComboBox" component is the best option available.

Therefore we need to add a ComboBox which holds a list of months. It should be placed at an appropriate position, somewhere near the calendar. So we will allow placing this ComboBox as per the developer's choice. How will we allow the developer to change this? We will pass parameter for the X and Y positions of this ComboBox to the constructor of Calendar.as.

To add and place the ComboBox, first consider the following tasks we must perform:

  • Passing parameters for the ComboBox's "X" and "Y" positions to the constructor.
  • Adding new function "monthPicker(...)" where we will manipulate the ComboBox.
  • Adding one more new function "pickMonth()" which will hear the ComboBox's events and will call a function to show the selected month.
  • Importing the ComboBox component by dragging it from the Component Panel to the Library Panel of our FLA.

First, add the following import statements to the class,

Then add new variables at start of the class under //Variables section as shown:

We will use the "months" array to put values inside combobox.

Ok, now let us modify the constructor function as shown:

We added the parameters "cbX" and "cbY" into the constructor's signature to pass position values specified by user, or to use default values if not specified.

Then we created a ComboBox instance as "monthPickerCB = new ComboBox()".

We called "monthPicker(...)" in advance, as we are going to create it now.

So we will add two new functions "monthPicker(...)" and "pickMonth(...)" as shown:

One more step and we are done adding the ComboBox.

Drag the ComboBox from the Component panel into your Flash file's Library panel. (Use the Window menu if you can't find the panels.) This way, we can access the ComboBox component and its classes at runtime.

Combobox and its prerequisites in the library.

Test the movie to see combobox at bottom left of the calendar (as default value).

Now you can display all the months, for the current year.

Exciting... So we will now add year selection, giving one more dimension to our calendar.


Step 14: Adding the Capability to Select Any Year

Selecting any year will add one more dimension to our Calendar. To select any year within a range, the NumericStepper component is a good choice.

Therefore we will add "NumericStepper" component which will allow the user to increment or decrement the selected year. As with the ComboBox, we will pass parameters to the constructor to specify its X and Y positions.

To add and place a NumericStepper, we'll have to perform the following tasks:

  • Passing parameters for NumericStepper's "X" and "Y" positions to the constructor.
  • Adding new function "yearPicker(...)" where we will manipulate NumericStepper.
  • Adding one more new function "pickYear()" which will hear NumericStepper events and will tell to show the selected year.
  • Importing the NumericStepper component by dragging it from the Component panel to the Library panel of our FLA.

First, add the following import statement to the class,

Then add a new variable at the start of the class under the //Variables section as shown:

Ok, now let us modify constructor function as shown:

We have added three parameters: "nsX", "nsY" and "monthsRange". The first two are to specify the position, and the third one is to specify the range (previous and next months). 39 will allow to pick any year within the next and previous 40.

OK, now we will add two new functions "yearPicker(...)" and "pickYear(...)", as shown:

One more step and we are done adding the numeric stepper.

Drag the Numeric Stepper component from the Component panel to your Flash file's Library panel. This way, we can access the Numeric Stepper component and its classes at runtime.

That's it. Test your movie to see a basic Calendar App running.

Step 15: Customizing the Calendar

We were testing the Calendar app with default values. Now we will customize it by passing different parameter values to its constructor.

To start with, we will try using the different fonts available on our system.

So, in the Flash file, go to the first statement in the ActionScript panel as shown:

Click inside parenthesis next to new Calendar, and type "Courier New". Now your statement will look like this:

Test the movie to see the new font applied to dates.

Now try changing next parameter (font size) like so:

While typing the next parameter you will see a code hint pop up, showing all necessary parameters with their default values, like so:

Code hint for constructor parameter

Make sure all parameters are there in the code hint popup. There is a bug(?) I have found when I was working on one project, which I'd like to make you aware of.

When I was writing a document class, at a point when there were only four parameters in the constructor signature, I closed this class file. When I got back to the work, I continued working on this class. At one point there were six parameters. Then I wanted to check this parameter passing stuff. So I opened the Flash file I created for this project and started typing parameters, as we did in our Calendar Flash file. I was expecting my newly added parameters to be displayed in code hints... but surprisingly there were still only four parameters.

I saved and restarted all related files but the result was the same. After lots of testing I found the reason. The reason was, I created a new folder in the same folder where the document class was placed. I removed this folder outside the main folder, then I opened the class file to make some changes and I saved it. Then I went back to Flash file and started typing parameters and this time all parameters showed up.

Ok, not a severe bug, but the lesson is: be careful while setting up a folder structure for your project.

So back to the point where we left off. Try passing proper values for different parameters. You can also set up variables in Flash file (or in a class), so if one value is changed then other related parameters will also get adjusted accordingly - for example, if you want to increase the Font Size then Cell Width must increase accordingly, and so on.


Step 16: Checking the Portability of This Calendar App

The real power of this class is that you can use it in any of your project like so:

  • Using in Flash IDE (as we've been doing)
  • Calling this Calendar.as inside another document class.
  • Using it with FlashDevelop.
  • Using it with Flash Builder.

We have already seen how to instantiate Calendar.as in Flash timeline code through this tutorial.

Now we will see how to call it in another class.

There is nothing much that we have to do differently when calling our class from another one. We simply put the same code we typed in Flash timeline into some other class. See the "Main.as" class below for better understanding:

You can use the above "Main.as" in Flash, FlashDevelop, FlashBuilder, FDT. Only you will have to carry Calendar.as, "Main.as" in your project folders.

In Flash IDE set this "Main.as" as Document class using Property Inspector panel. Make sure you have both Calendar.as, "Main.as" in your project folder. Also make sure you have "Combobox" and "NumericStepper" in your library panel. Now you can test the movie to see the working calendar.

FlashDevelop

Now we will test it with FlashDevelop 4.

Create a new folder "Calendar_FD".

Open FlashDevelop, create a new project, and browse for the above "Calendar_FD" folder. Press OK to create new project.

FlashDevelop Select Project window

Inside "Calendar_FD" folder, you will see three new folders: "bin", "lib" and "src".

Now in the "src" folder copy Calendar.as. Also copy above "Main.as" we created and replace it with the auto generated "Main.as" in the same folder.

Now every thing is set up. But what about the "ComboBox" and "NumericStepper" components? Here no Library panel is present, unlike in the Flash IDE.

The solution to this issue is making SWC files. We will create a "CalendarComp.swc" file.

Create a new FLA (in Flash Pro), name it "CalendarComp.fla", and save it anywhere (but remember its path).

Drag "ComboBox" and "NumericStepper" components to the Library panel and save the file.

Open Publish Settings and in the "Flash" tab check "Export SWC" under "SWF settings" group. Hit Publish.

PublishSettings_SWC

"CalendarComp.swc" is created in the folder where you saved "CalendarComp.fla", so browse to this folder and copy "CalendarComp.swc" to the "lib" folder of the "Calendar_FD" main folder.

Back in FlashDevelop, look in the Project Panel. Right click "CalendarComp.swc" and select "Add to Library". Now we can access all class files required for our components, just like in the Flash IDE.

Add CalendarComp.swc to library.

Finally click "Test Project" to see your Calendar app running.

Flash Builder

How about Flash Builder 4?

Create a new folder, "Calendar_FB".

Open Flash Builder and create a new project.

Flash Builder Select Project Menu.

Browse for the above "Calendar_FB" folder. Also enter a project name (I used "MyProject" as a project name). Press Finish to create a new project.

Flash Builder Select Project window.

Inside the "Calendar_FB" folder, you will see a "src" directoy, which already contains "MyProject.as" as the main class.

MyProject Folder structure.

Copy our Calendar.as class file to this folder. It is now visible in the "Package Explorer".

MyProject Folder structure.

As in, FlashDevelop there is no library panel like the Flash IDE has. So how to get "ComboBox" and "NumericStepper" components?

The solution is to use a SWC, like we did with FlashDevelop. But you need to specify the class path in Flash Builder.

So first copy the "CalendarComp.swc" we created in the above section for FlashDevelop, and paste this file inside the "src" folder of the "Calendar_FB" main folder.

In Flash Builder we need to add a class path. So click on Project > Properties to open the "Properties" window. Select "ActionScript Build Path" and click the "Add SWC..." button. Then browse for "CalendarComp.swc" which you pasted in the "src" folder.

Project properties.

Modify "MyProject.as" as shown:

Finally click "Run My Project" to see your Calendar app running.


Conclusion

So, friends, I would like to stop at this stage. I hope you have got something useful from this tutorial that will help in your coming projects. Best of luck... See you soon.

In this tutorial we saw the logical use of the "Date()" class in AS3. We addressed the leap year issue. We displayed the next and previous month's dates. We saw how to deal with Flash components. We also checked the portability of this Calendar app using FlashDevelop, Flash Builder and Flash Pro. During the process we also saw how to create and use SWC files to access Flash components outside Flash Pro.

All good. Friends, keep reading Activetuts+. Enjoy!

Tags:

Comments

Related Articles