Gantt4Flex Developer's Documentation
1. Introduction
Thank you for your interest in Gantt4Flex library. Gantt4Flex is a powerful and flexible library that allows you to include in your application Gantt diagrams. Gantt diagrams built with Gantt4Flex support "2-way" or "read-write" operations:
- users view data (based on your application's model and customizations)
- users interact with data (and trigger client-side or server-side behavior, specific to your application's needs)
This guide will walk you through the majority of the features. Each paragraph contains links to working examples, sample source code and ASDoc documentation of the library.
Gantt4Flex is built on the powerful diagramming library that is used in the products from the Flower Modeling Platform family (e.g. UML4AS). If your needs go beyond what is described in this document and in the ASDoc documentation, please don't hesitate to contact us (via support or forums), as there might already be a solution for what you are looking for.
When we designed Gantt4Flex (or when we add new features), we have the following (slightly funny) image in mind:
- Gantt4Flex is not a component that displays just a "classic" Gantt chart by default. And then...
"
I need to adapt. Can I do it? How?"
"
"Euhh... Well...
This might be possible...
But you need to do a trick... Etc."
Gantt4Flex is not this kind of product. - Gantt4Flex is a library that has been designed to be customized to match every small detail.
"
I need to adapt. Can I do it? How?"
"
Easily. You have just the API you need."
2. Model Configuration
The first step when using Gantt4Flex is to configure the model that holds the data to display. Any ActionScript class can be used as model. The model can be:
- flat or hierarchical. If it is hierarchical, an element can have child elements, and it is displayed as a tree within the Gantt diagram's associated DataGrid.
- single or multi segment. If multi segment, an element (a row) can have several segments.
2.1. Single Segment Model
If the model that is used is single segment, only 2 details need to be configured (if it is flat): the names of the 2 properties of the model (attributes or properties with getters/setters) that point to the start date and end date of the segment (startDateProperty and endDateProperty).
NOTE: The above properties need to dispatch a PropertyChangeEvent when they change. In the majority of the cases, a Bindable annotation will be used, either on property or class level.
Example:
2.2. Multi Segment Model
An element (a row) may have more than one segment. In this case, the start and end dates are not taken from the model element. Instead, the model should provide an ArrayCollection of segments; segmentsProperty needs to be set accordingly. Each segment should provide a start date (startDateProperty), an end date (endDateProperty) and a pointer to the parent model element (segmentParentProperty), and the corresponding property names should be set as well.
NOTE 1: Notice that the property names for getting the start/end dates are the same as in the case of a single segment model. The difference is that for a single segment configuration, they are applied directly on the model element (e.g. model.start) and for a multi segment configuration, they are applied on segments belonging to a model element (i.e. model.segments[i].start).
NOTE 2: For a multi segment configuration, the property that contains the segments should always be not-null (i.e. including when there are no segments), and should not change at runtime.
Example:
- Task Manager Sample - the model is also hierarchical but flat/multi segment model is supported as well.
- Task Manager Sample source code
2.3. Hierarchical Model
The model can be hierarchical. In this case, each model elements needs to provide an ArrayCollection of child model elements (childrenProperty) and a pointer towards the element's parent (parentProperty); the corresponding properties need to be configured accordingly.
NOTE: For a hierarchical configuration, the property that contains the children should always be not-null (i.e. including when there are no children), and should not change at runtime.
For a hierarchical model, the dataProvider can be an ArrayCollection or a single root model element (which is not displayed on the diagram / DataGrid).
Examples:
- Conference Sample - the model is heterogeneous; there is a limited depth on 2, and the parent/child have different classes (i.e.
ConferenceandTopic) - Conference Sample source code
- Task Manager Sample - the model is homogeneous; there is an unlimited depth, and the parent/child have the same class (i.e.
Task) - Task Manager Sample source code
2.4. Advanced Model Configuration: Model Elements of Different Types
You might have a model that is more complex. I.e. there is an hierarchy but different hierarchical levels are represented by different classes; e.g. instead of having a Task that has subtasks that have subtasks, etc., you have a first level: authors (that have a birth date) and a second level: books (that have a publish date). In this case a "static" model configuration is limiting.
Instead of using the properties discussed above, in GanttDiagramFigure you can define callback functions that have the same role, but can return different results, based on the instance type. For the above example, we can define a callback function for startDatePropertyFunction that returns "birthDate" for "Author" model elements and "publishingStartDate" for "Book".
Examples:
- Supermarket Resources Sample - there are multiple model classes that have different fields that access start/end dates, hierarchy, etc.
- Supermarket Resources Sample source code
3. Associating a DataGrid
The Gantt diagram usually has a DataGrid associated to it. The dataGrid property (gantt4flex:dataGrid from MXML) is used for this purpose. A couple of remarks about it (necessary because of the close integration/synchronization of the Gantt diagram and the DataGrid):
- the dataProvider of the DataGrid shouldn't be set/modified from within the application. It is controlled by the Gantt diagram.
- some visual properties of the DataGrid shouldn't be modified directly. They should be set through the Gantt diagram (headerHeight, rowHeight, the alternatingItemColors style).
Besides the above remarks, there are no additional constraints regarding the DataGrid. You can even have a customized DataGrid (e.g. renderers, custom columns classes, custom DataGrid class, etc.).
If a hierarchical model is used, the first column needs to have a special item renderer. GanttDataGridItemRenderer or GanttDataGridColumn need to be used.
Examples:
- Scientists Sample - flat model
- Scientists Sample source code
- Conference Sample - hierarchical model
- Conference Sample source code
4. Segment Figures (Renderers)
The default figure (renderer) for a Gantt segment is BasicGanttSegmentFigure. Another figure can be configured in one of the following ways, by setting the segmentFigure property.
"Bar"-like figure; all visual components are within the Gantt segment/bar
- extend BasicGanttSegmentFigure. It can be extended in order customize the drawing of the bar and/or to add children (e.g. labels; this can be done easily through MXML; this class descends (indirectly) from
VBox); - or, use another graphical component that implements the IGanttSegmentFigure interface. This should be straight forward. Besides implementing the methods (cf. the interface doc), nothing else needs to be done.
Figure with leading and/or trailing graphical components
If additional components need to be displayed before and/or after the bar component,
- use HBoxGanttSegmentFigure. It needs to have a child that draws the actual bar (+ the reference segmentBarComponent pointing towards it);
- or, use another graphical component that implements the IGanttSegmentFigure interface. The interface doc describes what are the responsibilities to fulfill in this case. This is not so straight forward, and it is recommended to use HBoxGanttSegmentFigure.
Examples:
- Conference Sample - custom figure, configured from MXML; keeps the original drawing logic
- Conference Sample source code
- Task Manager Sample - custom figure, configured partly from AS, partly MXML; customizes the original drawing logic
- Task Manager Sample source code
4.1. Advanced Figure Configuration: Different Types of Figures
As in the case of model configuration, a callback function can be defined (segmentFigureClassFunction in GanttDiagramFigure) that can return different figure classes (renderers) for different types of segments.
It's recommended (from the performance point of vies) to have several different (and light-weight) figure classes, instead of having a single, heavier, figure, that shows/hides subcomponents or modifies appearance using data binding.
Examples:
- Supermarket Resources Sample - there are multiple figure classes.
- Supermarket Resources Sample source code
4.2. Z Index
If your segments are likely to overlap, you might define a callback function (zIndexFunction) that controls the sorting of the figure on the Z Axis.
Examples:
- Supermarket Resources Sample - defines a function that controls the Z index.
- Supermarket Resources Sample source code
5. Timelines
A Gantt diagram may have timelines associated to it (0, 1 or more) by setting the timelines property. A Timeline is configured with various TimeUnits by setting the timeUnits property.
A TimeUnit represents a predefined interval that will be used for dividing the current display interval of the diagram. Timeline's documentation describes the logic used to determine the current time unit (chosen from the configured time units).
The Timeline has a default time units configuration, and it can be customized by using o mix of provided time units. The TimeUnits can be used as-is or they can be further configured (e.g. changing the date format). Some units allow using multiples. E.g. a YearTimeUnit with multiple = 5 is in fact a time unit that represents 5 years.
If there are several timelines, smallerTimeline is usually used to "chain" them. This ensures that the smaller timeline (below the current one) always has smaller time units (i.e. they split the display interval differently, even if they have the same time units configuration).
Examples:
- Scientists Sample - one timeline, with custom configuration (using
multipleas well) - Scientists Sample source code
- Conference Sample - 2 timelines with default configurations
- Conference Sample source code
6. Grids
A Gantt diagram can have one or several grids, displayed as background for the diagram. They are configured using grids. The library provides 2 implementations:
- HorizontalGrid that draws horizontal lines, according to diagrams rowHeight (i.e. they are aligned with the rows of the associated
DataGrid, if existent). - VerticalGrid that draws vertical lines, according to the intervals defined by the smallest Timeline
Although not a grid, let's mention NowIndicatorLine. It's an horizontal line that indicates the current time.
Examples:
- Scientists Sample - uses 2 grids
- Scientists Sample source code
7. Context Menu
The Flash platform is quite limiting regarding right click context menus. Gantt4Flex has its own context menu framework that is meant to overcome the Flash imposed limitations, while being as less intrusive as possible (from the user experience perspective).
The context menu is displayed next to an element when it is selected (it works for multiple selection as well). There are some timers involved in the context menu logic, which you can adjust if you want: contextMenuExpandMenuDelay, contextMenuAcceleratedExpandMenuDelay, contextMenuCloseMenuDelay.
Please note that the top application object needs to have an absolute layout, in order for the context menu to function correctly. If you are using a Spark application (Flex SDK 4 and above), this is the case by default. If you are using a MX application, you need to set layout="absolute".
7.1. Actions
FlowerContextMenu lets you define entries that are shown and executed against the current selection of the diagram (when a single element is selected, multiple elements or even no element => the "general" context menu of the diagram).
The first step is to define some actions. You need to extend the BaseAction class.
- Within the constructor you may define a title and an icon for the action.
- isVisible() needs to be overridden with code that decides if the action should be displayed or not (based on the current selection).
- run() needs to be overridden with code that does the work.
Please note the following items when writing actions
- The selection contains
EditParts which wrap the model elements. To access a model element useselection[i].getModel(). - Besides the current selection, actions can use the context data structure that contains some parameters that may be useful for the action.
- If your code removes elements from the data provider, please clone the selection
ArrayCollectionand operate on the clone.
The second step is to define a callback function for fillContextMenuFunction. The implementation of the callback should add the actions in the context menu (e.g. using addActionEntryIfVisible()).
You can have nested context menus (by using SubMenuEntry).
7.2. Create Actions
Create actions are a little bit special. They are not displayed like "normal" actions, when something is selected on the screen. They are displayed after a "drag to create" operation (see SelectMoveResizeTool). To work with create actions, you need to follow the same 2 steps as above, but with the follwing remarks.
The actions that you define (first step) won't use the selection (which is empty). They will probably use the information available in context (e.g. to know how big was the rectangle dragged by the user).
A different callback function is used (second step): fillCreateContextMenuFunction
Examples:
- Supermarket Resources Sample - define both "normal" actions and "create" actions.
- Supermarket Resources Sample source code
8. Print and Export as Image or PDF
To print the current Gantt diagram, you need to instantiate the Print Options dialog (GanttPrintDialog) and call its show() method. The user selects some options (which rows to print, how many rows per page, etc); after that he/she selects printer specific options (the window specific to the operating system) and the data is sent to the printer.
The printing is done in vector format. This means that transparent raster images are not supported (i.e. the transparency is shown as white background). If this is not convenient, you need to use SVG images.
To export the current Gantt diagram as an image, you need to instantiate the Export as Image Options dialog (GanttExportAsImageDialog) and call its show() method. This method needs a callback function that is invoked after the image has been generated. This callback function needs to to something with the data (a ByteArray): "give it" to the user in a browser "Save as" dialog, send it to the server, etc.
The PDF export mechanism works in a similar way. Use GanttExportAsPdfDialog and call its show() by providing a callback. Please note that in order to use this feature, you need to import the AlivePDF (http://www.alivepdf.org/, version >= 0.1.5_RC) library in your application. For the moment, the AlivePDF supports PDFs that contains bitmap (raster) data (not vector).
Examples:
- Supermarket Resources Sample - contains buttons for Print and Export as Image and PDF
- Supermarket Resources Sample source code
9. Other Customizations
9.1. Drag and Drop Segments
By default, drag and drop operations are allowed only on the horizontal axis. The user can grab a segment and move it or resize it. When the drop operation occurs, the system changes the dragged segment (i.e. it's start and/or end).
You may want to enable drag and drop an the vetical axis as well. In this case, a callback function needs to be specified: allowSegmentVerticalDragFunction.
Once the vertical drag and drop is enabled, another callback function needs to be provided: segmentDropFunction. Its implementation should decide what to do when an object is dropped (e.g. reorder in the data provider, associate to another element in the tree hierarchy, etc.). The system doesn't do anything by default (on the vertical axis).
This callback function might be used as well to prevent the default move/resize behavior (i.e. horizontal axis). Your particular business context might require this (e.g. some segments cannot be dragged unless a custom condition is met).
Examples:
- Supermarket Resources Sample - horizontal axis: move child elements together with the parent; vertical axis: change order or hierarchy
- Supermarket Resources Sample source code
- Task Manager Sample - horizontal axis: composed tasks are not allowed to me moved/resized
- Task Manager Sample source code
9.2. Status Bar Text
Gantt4Flex has a class that handles how the status bar text is formatted: StatusBarTextFormatter. You can customize the status bar text by assigning a new StatusBarTextFormatter instance to the diagram (statusBarTextFormatter). You can:
- use the same class and modify one or more of its format and/or substitution strings that configure the display; or
- extend the class and override one of more of its method (if changing the configuration is not enough).
Examples:
- Scientists Sample - modifies the format and substitution strings with something more appropriate for displaying born/die dates and ages
- Scientists Sample source code
- Task Manager Sample - modifies the format strings (display days instead of hours and minutes)
- Task Manager Sample source code
9.3. Snap to Grid
If the Gantt diagram has one (or several) Timelines, the "smallest"/last one (in the timelines array) controls the snap to grid behavior, when moving or resizing segments.
The snap to grid can be controlled independently of timelines as well. snapToGridTimeUnits needs to be set.
Examples:
- Scientists Sample - has different time units (from timelines) for snap to grid
- Scientists Sample source code
10. Runtime
The above sections, described various configuration elements, which are done at design time.
The entry point of Gantt4Flex is the GanttDiagramFigure component. It can be added within an MXML component (or application), or via ActionScript.
The library provides features that are accessed at runtime. They are described in the API documentation, but let's take a look at a couple of them.
10.1. DataProvider
Once the component is on the screen, you can set an ArrayCollection of model elements as its dataProvider. The component supports data binding. When the dataProvider changes or when one model element changes its start or end property, the diagram refreshes.
From the performance perspective, if you need to add a lot of items sequentially (e.g. when data comes from the server) it is recommended to add them in an ArrayCollection and then set it as dataProvider (rather than setting the collection first and adding the items afterwards). The same remark applies for delete as well; if you need to delete all the elements, you should set the dataProvider to null, rather than removing the elements one by one (or using removeAll(), which does the same). Actually this applies to almost all Flex data bound components, because of the sequential way of dispatching notifications.
10.2. Display Interval
The display interval is the the time interval currently displayed in the diagram. It is controlled by the user via scrolling or zooming. It can be controlled programmatically as well, using setDisplayInterval().
10.3. Formatting Durations
Formatting dates as durations (instead as date and/or time) is rather difficult in ActionScript (even in Java) as the API doesn't provide appropriate formatters. The Gantt4Flex has a static method (used by the status bar) which you can use in your application as well, if you need to display durations: formatDuration().