Tuesday, August 12, 2008

Code Review Vol. 1.01 - Calendar Class Walkthrough


import flash.display.*;
import net.com.calendar.Day;

public class AbstractCalendar extends Sprite
{
private static var _dayIDSequence:Number = 0;

private var _dayHeight:Number = 50;
private var _dayWidth:Number = 50;
private var _startX:Number = 10;
private var _startY:Number = 10;

private const WEEKDAYCOUNT:Number = 7;

private var _bgColor:uint = 0xCCCCCC;
private var _borderColor:uint = 0x666666;
private var _borderSize:uint = 1;

public function AbstractCalendar(month:Number)
{}



CreateDay instantiates a Day object and sets all of its properties. Date is the date object for the specific day, Name is used to getChildByName and Display is the string value to be stored in the textfield in the Day. OriginalStackIndex is exactly what it sounds like, the original index in the display list that the object was first created. I get this at runtime by pulling from a sequence of my own creation - I'm enamored with the Oracle concept of sequences. It really isn't used in this example, its a remnant from my actual implementation where I change the child index when a user clicks on a day.



private function createDay(today:Date,name:String, display:String, dayNum:Number):Day
{
var tempDay:Day = new Day()
tempDay.name = getNewDayID();
tempDay.setDate(today)
tempDay.setName(name);
tempDay.setDisplay(display);
tempDay.setDayNumber(dayNum)
tempDay.drawDay(_bgColor, _borderSize,_borderColor, _dayWidth, _dayHeight);
tempDay.originalStackIndex = Number(tempDay.name)
return tempDay
}



getNewDayID is my version of the Oracle sequence. It gives unique ids for the objects and tells me their stack index


private function getNewDayID():String
{
return (_dayIDSequence++).toString();
}



DrawMonth is the engine for this implementation. Essentially you pass in a number for the month you want to render. With that month number I create a date object for the first day of the month. I assume its the current year, change at your own discretion. Once I have the date object for the first day I just keep iterating and incrementing the date object one day at a time. I check several things - if its the first day of the month and the day of the week isn't Sunday I back fill for however many days away from Sunday the actual day is. I check to make sure we are still on the month we're supposed to be rendering, if we aren't, then I find out what day it is and front-fill the current week with as many days as we are away from Saturday. If we are still in the month then I keep drawing days. I check if the current day is Sunday, if it is I reset the x coordinate back to 0 to start a new week. I also check if the current dayStepper - which is just an incrementor to keep track of how many times we've looped through, to account for the back and front-filling we've been doing - gives a remainder when divided by 7 (the number of days in a week) if it doesn't I know a full week has been rendered and I need to increment the y coordinate by the height of the day to start a new line.



public function drawMonth(tempMonth:Number,tempDay:Day, backDay:Day):void{
var currentDay:Number = 1
var dayStepper:Number = 0
var tempDate:Date = new Date(tempMonth + "/"+currentDay+"/" + new Date().getFullYear());
var tempMonthChecker:Number = tempDate.getMonth()
//check for current month to step through each day in the month
while(tempDate.getMonth() + 1 == tempMonth){

tempDate = new Date(tempMonth + "/"+currentDay+"/" + new Date().getFullYear());
tempMonthChecker = tempDate.getMonth()

// check for day num, at each zero
// reset startX back to 0
if(tempDate.getDay() == 0){ _startX = 10}

//figure out the day number for the first day only
if(tempDate.getDay() > 0 && currentDay == 1 )
{
for(var x:Number = 0;x < tempDate.getDay(); x++)
{
//backfill previous days
backDay = createDay(tempDate,"","",x)
backDay.x = _startX
backDay.y = _startY
_startX += _dayWidth
addChild(backDay);
dayStepper++
}
}

if(tempDate.getMonth() + 1 == tempMonth){
tempDay = createDay(tempDate, "",currentDay.toString(),tempDate.getDay())
tempDay.x = _startX
tempDay.y = _startY
_startX += _dayWidth
addChild(tempDay);
dayStepper++

// increment startY by the _dayHeight
if(dayStepper % WEEKDAYCOUNT == 0){_startY += _dayHeight}

currentDay++
}else{
for(var y:Number = tempDate.getDay(); y < WEEKDAYCOUNT;y++)
{
//front fill the next months days
backDay = createDay(tempDate,"","",x)
backDay.x = _startX
backDay.y = _startY
_startX += _dayWidth
addChild(backDay);
}
}
}
}
}


And that's it. When taken apart and examined the logic is fairly straightforward. Yet it's extensible and powerful. You can extend the Day class to do almost anything and encompass any kind of custom logic. You can change the basic engine to draw a single day or draw a week or a set window of weeks.

No comments: