Monday, July 5, 2010

How to create a calendar using only Actionscript 3 - Part 3

In the previous 2 tutorials we have created a base for our calendar and added some functionality. Today we are going to add more stuff to it.

Firstly, add a new loop in the compute function, right after the loop that sets text for each cell:


var l:Number;
for (l=0; l<maxdays; l++) {
if(allcells[l].text==now.date && firs.fullYear == now.fullYear && firs.month == now.month){
allcells[l].backgroundColor=0x00FFCB}
}

This will highlight today's date.

To clean up all the cells before computing the data, write this in the beginning of compute function:

var d:Number;
for (d=0; d<42; d++) {
allcells[d].text=""
allcells[d].backgroundColor=0x99CCFF
} 

Now we will add options to change current month and year. We will use ComboBox and NumericStepper components for this. In the very beginning of our script, enter this code:

import fl.controls.ComboBox;
import fl.data.DataProvider;
import fl.events.ComponentEvent;

var monthsdata:Array = [
{label:"January", data:0},
{label:"February", data:1},
{label:"March", data:2},
{label:"April", data:3},
{label:"May", data:4},
{label:"June", data:5},
{label:"July", data:6},
{label:"August", data:7},
{label:"September", data:8},
{label:"October", data:9},
{label:"November", data:10},
{label:"December", data:11},
];

var monthpicker = new ComboBox();
monthpicker.dataProvider = new DataProvider(monthsdata)
addChild(monthpicker);
monthpicker.x=10
monthpicker.y=230

monthpicker.addEventListener(Event.CHANGE, monthHandler);

function monthHandler(event:Event):void {
firs.month=ComboBox(event.target).selectedItem.data;
compute();
} 

monthpicker.selectedIndex=now.month

That will create an array of data, which is then provided for the ComboBox. Every time user changes the value of the box, current month changes.

Because we are showing today's month on start, we have to set the selectedIndex to now.month.

Now we are going to create a year picker using Numeric Stepper:

import fl.controls.NumericStepper;

var yearpicker = new NumericStepper();
yearpicker.maximum = now.fullYear+30
yearpicker.minimum = now.fullYear-30
yearpicker.value = now.fullYear
addChild(yearpicker);
yearpicker.x=130
yearpicker.y=230

yearpicker.addEventListener(Event.CHANGE, yearHandler);
function yearHandler(event:Event) :void {
firs.fullYear = event.target.value;
compute();
}

Done! Now we have a nice little calendar, which highlights today's date, has the option to pick a month or year, and everything is done entirely with code!

Thank you for reading this tutorial. Here's the final code:

var cellformat:TextFormat = new TextFormat();
cellformat.color=0x012943;
cellformat.size=16;
cellformat.align="right";

var cformat:TextFormat = new TextFormat();
cformat.color=0x000000;
cformat.size=14;
cformat.align="center";

var weekdays:Array=new Array("Mon","Tue","Wed","Thu","Fri","Sat","Sun");

var u:uint;
// the first loop to add week day names

for (u=0; u<7; u++) {

 var c:TextField = new TextField();
 c.selectable=false;
 c.width=30;
 c.text=weekdays[u];
 c.setTextFormat(cformat);

 addChild(c);
 c.x=10+(30*u);
 c.y=10;

}

var i:uint;
var allcells:Array = new Array();
// the second loop to create cells

for (i=0; i<42; i++) {

 var cell:TextField = new TextField();
 cell.background=true;
 cell.backgroundColor=0x99CCFF;
 cell.border=true;
 cell.borderColor=0x9999CC;
 cell.selectable=false;
 cell.width=cell.height=24;
 cell.setTextFormat(cellformat);

 addChild(cell);
 cell.x=10+(30*(i-(Math.floor(i/7)*7)));
 cell.y=40+(30*Math.floor(i/7));

 allcells.push(cell);
}

var now:Date = new Date();
var firs:Date=new Date(now.fullYear,now.month,1);

var days:Array=new Array(6,0,1,2,3,4,5);


import fl.controls.ComboBox;
import fl.data.DataProvider;
import fl.events.ComponentEvent;

var monthsdata:Array = [
{label:"January", data:0},
{label:"February", data:1},
{label:"March", data:2},
{label:"April", data:3},
{label:"May", data:4},
{label:"June", data:5},
{label:"July", data:6},
{label:"August", data:7},
{label:"September", data:8},
{label:"October", data:9},
{label:"November", data:10},
{label:"December", data:11},
];

var monthpicker = new ComboBox();
monthpicker.dataProvider=new DataProvider(monthsdata);
addChild(monthpicker);
monthpicker.x=10;
monthpicker.y=230;

monthpicker.addEventListener(Event.CHANGE, monthHandler);

function monthHandler(event:Event):void {
 firs.month=ComboBox(event.target).selectedItem.data;
 compute();
}

monthpicker.selectedIndex=now.month;

import fl.controls.NumericStepper;

var yearpicker = new NumericStepper();
yearpicker.maximum=now.fullYear+30;
yearpicker.minimum=now.fullYear-30;
yearpicker.value=now.fullYear;
addChild(yearpicker);
yearpicker.x=130;
yearpicker.y=230;

yearpicker.addEventListener(Event.CHANGE, yearHandler);
function yearHandler(event:Event):void {
 firs.fullYear=event.target.value;
 compute();
}

function compute() {
 var d:Number;
 for (d=0; d<42; d++) {
  allcells[d].text="";
  allcells[d].backgroundColor=0x99CCFF;
 }

 allcells[days[firs.day]].text=1;
 allcells[days[firs.day]].setTextFormat(cellformat);

 var maxdays=30;
 var leapyear:Number;

 if (firs.fullYear%4==0&&firs.fullYear%100!=0||firs.fullYear%400==0) {
  leapyear=1;
 } else {
  leapyear=0;
 }

 if (firs.month==0||firs.month==2||firs.month==4||firs.month==6||firs.month==7||firs.month==9||firs.month==11) {
  maxdays=31;
 } else if (firs.month==3 || firs.month==5 || firs.month==8 || firs.month==10) {
  maxdays=30;
 } else if (firs.month==1 && leapyear==1) {
  maxdays=29;
 } else {
  maxdays=28;
 }

 var p:Number;
 for (p=1; p<maxdays; p++) {
  allcells[days[firs.day]+p].text=p+1;
  allcells[days[firs.day]+p].setTextFormat(cellformat);
 }
 var l:Number;
 for (l=0; l<maxdays; l++) {
  if (allcells[l].text==now.date&&firs.fullYear==now.fullYear&&firs.month==now.month) {
   allcells[l].backgroundColor=0x00FFCB;
  }
 }
}

compute();

Feel free to experiment with the settings to get best results. After a bit of tweaking, here's what I got in result.



Related:

How to create a calendar using only Actionscript 3 - part 1
How to create a calendar using only Actionscript 3 - part 2
How to create a calendar using only Actionscript 3 - part 4
How to create a calendar using only Actionscript 3 - part 5
How to create a calendar using only Actionscript 3 - part 6
How to create a calendar using only Actionscript 3 - part 7
How to create a calendar using only Actionscript 3 - part 8
How to create a calendar using only Actionscript 3 - part 9
How to create a calendar using only Actionscript 3 - part 10
How to create a calendar using only Actionscript 3 - part 11
How to create a calendar using only Actionscript 3 - part 12

20 comments:

Anonymous said...

Hi!
I just love this tutorial!! But one question; How do i make the empty fields(before 1 && after 31) Say the next month already? so before 1: 29 30 31
and after 31: 1 2 3 4... and so on.

Please email me: douwe_monster@live.nl

Kirill Poletaev said...

You can check information of the months before and after the current month and see how many days are in that month, then just set the cell values to those numbers.

Anonymous said...

But, how do I do that?

Kirill Poletaev said...

Change the loop with the l:Number variable with this:



var l:Number;
for (l=41; l>0; l--)
{
trace(allcells[l].text);
if (allcells[l].text == now.date && firs.fullYear == now.fullYear && firs.month == now.month)
{
allcells[l].backgroundColor = 0x00FFCB;
}
}
var q:Number;
for (q=1; q<(42-maxdays-days[firs.day]+1); q++)
{
allcells[days[firs.day] + q + maxdays - 1].text = q;
allcells[days[firs.day] + q + maxdays - 1].setTextFormat(cellformat);
}
var f:Number;
var prefirst = new Date(firs.fullYear,firs.month,firs.date - 1);
for (f=days[firs.day]; f>0; f--)
{
allcells[days[f]].text=prefirst.date-(days[firs.day]-f);
allcells[days[f]].setTextFormat(cellformat);
}



This will add dates before and after the current month.

Anonymous said...

Wow, The previous person just asked what i want to ask=). Only i've got one question:
how do i get the X & Y from the cell from TODAY.
so if today is sep 3th, you get the x&y from the cell where the text is sep 3th...
i'm a beginner.
Thankyou!

Kirill Poletaev said...

You can find which row Today cell is located in. I explained how in the tutorial. You can get the coordinates of the cell using maths, by adding the intervals, space from the flash edge to the first cell, etc.

Or, you can just return the x and y properties of the cell itself. You can do that through the loop that colors the Today cell (the one with the l variable).

Inside the if statement, you can write
trace(alldays[l].x);
and
trace(alldays[l].y);
to retrieve the coordinates. To use them later, store these values in variables.

adrian said...

Your blog is awesome!
Thank you very much for sharing this kind of information!

Anonymous said...

Having created the full calendar I now want to be able to highlight custom dates from different months and years to show these days are not available (ie already booked).

So for instance if I wanted to highlight 28th August 2011 how would I go about this.

Needlemouse said...

Hello!!!

First of all, thank you so much for your blog. So many good stuff in here for the not so advanced people in as3.

How can i set the alpha of the cells who are LESS THAN the present date.

its like, today is Oct 26, i want 25, 24, 23...1 to be alpha = .5.

Thanks and more power to your blog!!!

Needlemouse said...

I know its just a basic conditional statement, i just dont know how to implement it :D

Kirill Poletaev said...

To the Anonymous person asking about highlighting custom dates - I'd suggest creating an associative array (or an XML file) with information about the year, month and date. Then check every cell for these properties - paint them if they match.

Firstly, make the array:

var highlightDates:Array = [{day:28,month:8,year:2011},{day:12,month:12,year:2012}];

Then replace the 'l' variable loop with this:

// Code starting here

var l:Number;
var h:Number;
for (l=0; l<maxdays; l++)
{
if (allcells[l].text == now.date && firs.fullYear == now.fullYear && firs.month == now.month)
{
allcells[l].backgroundColor = todayBg;
}

for (h=0; h<highlightDates.length; h++)
{
if(allcells[l].text == highlightDates[h].day && firs.fullYear == highlightDates[h].year && firs.month == (highlightDates[h].month-1)){
allcells[l].backgroundColor = 0x00FF66
}
}

}

// Code ending here

To Needlemouse, replace the 'l' variable loop with this:

// Code starting here

for (l=0; l<maxdays; l++) {
if (allcells[l].text==now.date&&firs.fullYear==now.fullYear&&firs.month==now.month) {
allcells[l].backgroundColor=0x00FFCB;
}
if (Number(allcells[l].text)<now.date&&firs.fullYear==now.fullYear&&firs.month==now.month) {
allcells[l].alpha=0.5
}
}

// Code ending here

Needlemouse said...

Thank you very much!!! You're blog helps a lot of people. KEEP IT UP! GOD BLESS!!!

Needlemouse said...

Hello Kirill!

How can i make the dates which are less than "10" with leading zeroes?

IE: 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11....

Thanks MUCH!!!

Kirill Poletaev said...

Here's a tutorial for adding zeros in front of your numbers: link.

Anonymous said...

Hi there, this was going really well for me from a beginner's point of view. However I'm finding errors now as I'm importing controls for the combo box, data providers and component event. If I copy and paste your final script posted example into Flash Professional CS5 the same errors are produced. As below

Scene 1, Layer 'Layer 1', Frame 1, Line 58 1172: Definition fl.controls:ComboBox could not be found.
Scene 1, Layer 'Layer 1', Frame 1, Line 59 1172: Definition fl.data:DataProvider could not be found.
Scene 1, Layer 'Layer 1', Frame 1, Line 60 1172: Definition fl.events:ComponentEvent could not be found.
Scene 1, Layer 'Layer 1', Frame 1, Line 92 1172: Definition fl.controls:NumericStepper could not be found.
Scene 1, Layer 'Layer 1', Frame 1, Line 58 1172: Definition fl.controls:ComboBox could not be found.
Scene 1, Layer 'Layer 1', Frame 1, Line 59 1172: Definition fl.data:DataProvider could not be found.
Scene 1, Layer 'Layer 1', Frame 1, Line 60 1172: Definition fl.events:ComponentEvent could not be found.
Scene 1, Layer 'Layer 1', Frame 1, Line 92 1172: Definition fl.controls:NumericStepper could not be found.
Scene 1, Layer 'Layer 1', Frame 1, Line 86 1180: Call to a possibly undefined method ComboBox.
Scene 1, Layer 'Layer 1', Frame 1, Line 77 1180: Call to a possibly undefined method ComboBox.
Scene 1, Layer 'Layer 1', Frame 1, Line 78 1180: Call to a possibly undefined method DataProvider.
Scene 1, Layer 'Layer 1', Frame 1, Line 94 1180: Call to a possibly undefined method NumericStepper.

I would really would appreciate some help with this Scene 1, Layer 'Layer 1', Frame 1, Line 58 1172: Definition fl.controls:ComboBox could not be found.
Scene 1, Layer 'Layer 1', Frame 1, Line 59 1172: Definition fl.data:DataProvider could not be found.
Scene 1, Layer 'Layer 1', Frame 1, Line 60 1172: Definition fl.events:ComponentEvent could not be found.
Scene 1, Layer 'Layer 1', Frame 1, Line 92 1172: Definition fl.controls:NumericStepper could not be found.
Scene 1, Layer 'Layer 1', Frame 1, Line 58 1172: Definition fl.controls:ComboBox could not be found.
Scene 1, Layer 'Layer 1', Frame 1, Line 59 1172: Definition fl.data:DataProvider could not be found.
Scene 1, Layer 'Layer 1', Frame 1, Line 60 1172: Definition fl.events:ComponentEvent could not be found.
Scene 1, Layer 'Layer 1', Frame 1, Line 92 1172: Definition fl.controls:NumericStepper could not be found.
Scene 1, Layer 'Layer 1', Frame 1, Line 86 1180: Call to a possibly undefined method ComboBox.
Scene 1, Layer 'Layer 1', Frame 1, Line 77 1180: Call to a possibly undefined method ComboBox.
Scene 1, Layer 'Layer 1', Frame 1, Line 78 1180: Call to a possibly undefined method DataProvider.
Scene 1, Layer 'Layer 1', Frame 1, Line 94 1180: Call to a possibly undefined method NumericStepper.

I'm sure you will have better things to be do with your time. But it seems as if the error is made from undefined code. I'm still trying to gain overview of how AS3 is formatted correctly I cannot seem to correct this error. Thanks in advance for a response from a learner.

Kirill Poletaev said...

You need to have the components in your Flash library. Go to Window>Components and draw the needed components to your library.

Anonymous said...

Hello, I was wondering if there was a way of having previous and next month buttons instead of a drop down menu? :)

Anonymous said...

Hello i am following this tutorial and i keep getting the following message :

access of undefined property maxdays

this is the line the error falls onto:

var l:Number;
for (l=0; l<maxdays; l++) {
if(allcells[l].text==now.date && firs.fullYear == now.fullYear && firs.month == now.month){
allcells[l].backgroundColor=0x00FFCB}
}

i don't know know what is wrong and have followed the tutorial exact can you help please?

Kirill Poletaev said...

Make sure the maxdays variable is declared before you used. Take a look at the full code - the "var maxdays" line is above the piece of code you posted.

Anonymous said...

Kirill Poletaev said...

You need to have the components in your Flash library. Go to Window>Components and draw the needed components to your library.


IS THERE A TUTORIAL THAT SHOWS HOW TO DO THIS?

THANK YOU!!!!! :)

Post a Comment