Gantt Charts in Flex DataGrids in less than 1 hour !
Here is an example of how you can use an item renderer in a mx:DataGrid to create a basic Gantt Chart. First things first, what is a Gantt Chart?
Q: What is one of the most commmonly used Flex elements for displaying data in horizontal rows?
A: A mx:DataGrid
Why reinvent the wheel? The mx:DataGrid already does just about everything that you could possibly need a Gantt Chart to do, except the graphical visualization, so why start anywhere else? Here is what I did...
First, I created a dataGrid to be the base of my Gantt Chart:
A Gantt chart is a popular type of bar chart that illustrates a project schedule. Gantt charts illustrate the start and finish dates of the terminal elements and summary elements of a project.Those of you who use Microsoft Project are already intimately familiar with Gantt Charts. They show a visual representation of task durations, with respect to sequential execution of tasks. They make it easier to visualize sequential and parallel tasks and determine task execution progress.
- http://en.wikipedia.org/wiki/Gantt_chart
Q: What is one of the most commmonly used Flex elements for displaying data in horizontal rows?
A: A mx:DataGrid
Why reinvent the wheel? The mx:DataGrid already does just about everything that you could possibly need a Gantt Chart to do, except the graphical visualization, so why start anywhere else? Here is what I did...
First, I created a dataGrid to be the base of my Gantt Chart:
<mx:DataGrid top="0" left="0" right="0" bottom="0" id="dg" >I used a custom item renderer to to handle the graphical visualization within the mx:DataGrid. My datasource is an xml object that contains the title, start, duration of each task. I left it as integer values to keep the demo simple. Real world data would use actual dates, thus the logic in the item render would need to be updated to calculate the rectangle based off of acutual date values.
<mx:columns>
<mx:DataGridColumn headerText="Title" dataField="@title" width="80"/>
<mx:DataGridColumn headerText="Duration" dataField="@start" itemRenderer="renderers.SimpleGanttRenderer"/>
</mx:columns>
</mx:DataGrid>
<GanttData>Within the item renderer, I extended the UIComponent class and overrode the updateDisplayList function to draw the rectangle for the gantt chart. Like I said before, this example is very simple. In a real world solution, you would probably want something that is more pleasing to the eye than a red rectangle. Or, you could color code the rectangles based on completion status.
<series duration="20">
<task duration="2" start="0" title="Task 1" />
<task duration="2" start="1" title="Task 2" />
<task duration="7" start="3" title="Task 3" />
<task duration="5" start="8" title="Task 4" />
<task duration="6" start="8" title="Task 5" />
<task duration="4" start="14" title="Task 6" />
<task duration="3" start="17" title="Task 7" />
</series>
</GanttData>
package renderersComments:
{
import mx.core.UIComponent;
import mx.core.IDataRenderer;
import flash.display.Graphics;
import mx.controls.listClasses.IListItemRenderer;
import mx.utils.GraphicsUtil;
import flash.geom.Rectangle;
import util.SimpleGanttUtil;
import flash.events.Event;
import mx.events.FlexEvent;
import mx.controls.listClasses.BaseListData;
import mx.controls.dataGridClasses.DataGridListData;
[Event(name="dataChange", type="mx.events.FlexEvent")]
public class SimpleGanttRenderer extends UIComponent implements IDataRenderer, IListItemRenderer
{
private var _data : Object = null;
[Bindable("dataChange")]
public function get data():Object
{
return _data;
}
public function set data(value:Object):void
{
this._data = value;
this.invalidateProperties();
dispatchEvent(new FlexEvent(FlexEvent.DATA_CHANGE));
}
override protected function updateDisplayList(w:Number, h:Number):void
{
super.updateDisplayList(w, h);
var g:Graphics = graphics;
g.clear();
if ( _data != null)
{
g.lineStyle(1, 0x000000, 1);
g.beginFill(0xFF0000, .5);
var r:Rectangle = calculateRectangle(w,h);
GraphicsUtil.drawRoundRectComplex(g, r.x, r.y, r.width, r.height, 0, 0, 0, 0);
g.endFill();
}
}
private function calculateRectangle(w:Number, h:Number) : Rectangle
{
var xmlData : XML = XML(_data);
var rect_x : int = 1+ ((w-2) * (xmlData.@start/SimpleGanttUtil.duration));
var rect_y : int = 1;
var rect_width : int = (w-2) * (xmlData.@duration/SimpleGanttUtil.duration);
var rect_height : int = h-2;
return new Rectangle( rect_x, rect_y, rect_width, rect_height );
}
}
}
- This does not include linking of tasks. That will require a lot more work.
- This could easily be extended to show "now" within the updateDisplayList function.
- This demo does not show any dates or tooltips... These can be added very easily on the mx:DataGrid component.
- This entire demo, including the blog post took less than 2 hours. Getting the basic Gantt Chart working took less than 1 hour. Making it look good and writing this post took the rest of the time. :)





0 Comments:
Post a Comment
<< Home