« Comcast Uses Flash Video | Main | creationPolicy vs Binding »

January 18, 2008

DataCalendar

The DataCalendar is a combination of DateChooser and DataGrid. Like the DateChooser, the DataCalendar displays a standard calendar with controls to navigate to another month and year. And like the DataGrid, the cells of the DataCalendar display data.

Also similar to the DataGrid, the DataCalendar uses itemRenderers - either the default ones I've included with the package, or ones you create. The image below shows an example using custom itemRenderers and skins.

A long time ago I helped a friend of mine who owns a nightclub write an application which lets her booking manager create an online calendar of the bands performing at her nightclub. The central part of this application is the calendar which displays the bands playing each night, along with any notes and ticket information. I wrote all of that using PHP and I've been meaning to, over the years, write it again in Flex. The only thing holding me back was the calendar.

The DateChooser is fine to pick dates, but you cannot display anything other than the date in the calendar. The DataGrid is also fine but I needed something a bit more flexible. So I finally sat down, planned it out, and came up with the DataCalendar.

See a demo of DataCalendar here

The demonstration is of the nightclub booking tool. The information is stored in XML files and is available for the months of Dec 2007 through Feb 2008; I haven't modified the program to create new months, but feel free to experiment with the code on your own.

Screen shot of the BookingTool

View Documentation

In hindsight, you can probably do this with the DataGrid. Once I had it planned I wanted to see it through, but if you wanted to do something similar with the DataGrid, I believe you could.

Source Code

These ZIP files are Flex 3 Beta 3 project archives.

DataCalendar Flex Library. This is the source to the DataCalendar control and supporting classes.
Test Application. This is the source to the test applications, including the BookingTool (above).

DataProvider

To use the DataCalendar you need a special data provider. I had toyed around with using the conventional ArrayCollection and XMLListCollection classes, but the more I thought about how someone would use this control, the more I thought I needed something specialized. When you look at a calendar, what do you see? Dates, right? And wouldn't it make sense to orient the data to the dates of the calendar?

My first thought was to include the day of the month as one of the fields: {day:18, value:"Tim's Birthday"}, {day:4, value:"Big Meeting"}, and so forth. The problem with this is that you have to repeatedly search through the collection for the information on a particular day. In this example, the information for the 4th comes after the information for the 18th. I could do a one-time pass and create a mapping, but that seemed like too much work and could have issues with data binding events.

Instead, I created the DataCalendarDataProvider class. The class implements ICollectionView, but it allows data to be assigned by day. For instance:

var januaryData:DataCalendarDataProvider = new DataCalendarDataProvider();
januaryData.addItemAt( 18, {value:"Tim's Birthday});
januaryData.addItemAt( 4, {value:"Big Meeting"});

The DataCalendarDataProvider class allocates 32 slots - slot 0 is not used - so each slot corresponds to a day of the month.

Certain properties such as sort and functions such addItem() do not make sense for a calendar, so those will throw exceptions if used.

Layout

The calendar is a grid of 7 columns and 6 rows (to accomodate those months which require 6 weeks, eg. March 2008). Regardless of the width, the DataCalendar makes all of the week day columns the same size. If you specify an explicit height the DataCalendar also makes all of the week rows the same height. However, if you do not specify a height, then the DataCalendar will allow each week row's height to be different from the others, using the content of the day cells to determine a week row's maximum height.

Renderers

I wanted this control to be as flexible as possible, so I gave it the ability to use itemRenderers. There are several renderers you can change:

itemRenderer: This is the renderer for the contents of a day cell. The default (DataCalendarItemRenderer) renderer takes the contents and displays it in a Text field. The BookingTool demonstration uses a complex itemRenderer. You can also add video and audio. Imagine showing the most popular YouTube™ video for each day of the month.
todayRenderer: This renderer displays the indicator for the day cell representing the current date. The default renderer simply displays the DataCalendarTodaySkin.
dayNumberRenderer: This renderer displays the date in the day cell. The default (DataCalendarDayNumberRenderer) displays the numerals for the date in the upper right corner of each day cell.
dayNameRenderer: This renderer displays the name of the day of the week across the top of each week day column. The default is DataCalendarDayNameRenderer.

Skins

I also wanted the control to have a great deal of flexability when it came to its look, so there are also a number of skins you can change:

DataCalendarDayNameSkin: the skin used for the background of the week day names.
DataCalendarDayNumberSkin: the skin used for the background of the dates for each day of the month (day cell).
DataCalendarSkin: the skin used for the background and border of the DataCalendar control.
DataCalendarTodaySkin: the skin used to show the indicator for the current day.

Version 2.0

Of course, once you finish a project you think about things you'd like to add or change. I may never get to this, but I can think of some "enhancement requests":


Posted by pent at January 18, 2008 03:19 PM

Comments

Could you clarify the process to edit/update the skins from the included FLAs? The Import Skin Artwork says Flash should use a SWC while Illustrator uses a SWF. Since the project includes a FLA on presumes you used Flash but there's no SWC and exporting Skins.swc from flash then attempting to import to FB3b3 - finds no symbols to import.

thx much for such a nice, heavily commented project.

--steve...
--------------
I didn't use the artwork import feature of FB3 at all. All I did was create a Flash file with symbols in its library and set those symbols to export on the first frame of the SWF. Then I embedded them using Embed syntax.

So you should not be importing them.

Posted by: Steve at February 4, 2008 12:22 PM

Your "Stack" components, any chance on an update for them allowing for better skinning control?

Currently I have modified the StackBase.as to use a Button as a header and use the toggle and selected properties. Do you think this is o.k? why do you have a seperate class for the StackHeaderButton and not just use the Button.as?

Cheers
Gareth.
-----
Peter: I use my own class so I can control (more easily) the skins it uses.

Posted by: Gareth Edwards at February 4, 2008 11:26 PM

Thankx for the reply Peter....I _thought it was supposed to be that easy...that's how I tried on the first pass but when it didn't work I dug thru a few .pdfs (flexbuilder3_sdext_docs_121207-1.pdf) where they document the import.

In any event...I've re-tried your steps...working off the archived files I open Skins.fla in CS3 (v 9.0), double check that 'Export on 1st frame' setting, and publish. Flex tosses this error:

Unable to transcode .../DataCalendarTestApp/src/assets/Skins.swf. DataCalendarTestApp/src/assets Examples.css line 43 1202306506313 139
---------------
Peter: I'll have to look into this and I don't see where the problem could be.

Posted by: Steve at February 6, 2008 09:12 AM

will this work in FB2? I haven't made the jump yet. Thanks.
---------
Peter: I don't see why not. There's nothing intrinsically "Flex 3" about it as far as I know.

Posted by: Craig Hollabaugh at February 15, 2008 03:09 PM

Any thoughts on how to go about moving calendar events by way of drag and drop? (for an admin)
---------------
Peter: This is a good question. You'd have to implement this within the DataCalendar and use the DragManager. Detect a mouse down+move and tell the DragManager to create a proxy. Then listen for a mouse up event. I'd have to do a little research to see if there is a better way, but that's the idea.

Posted by: Josh at March 17, 2008 11:08 PM

I just got your calendar working in Cairngorm, with the ability to drag the calendar events around, it's a bit rough, but very cool. Cheers.

Posted by: Josh at March 18, 2008 06:28 PM

Post a comment




Remember Me?