B4J Library [B4X] xGantt Chart

I have written a cross-platform xGantt chart Class.

There does also exist an xGanttLite library.
The differences are that the xGantt treats durations and dependencies but the xGanttLite uses only begin and end times.
The xGantt scale is days only, the xGanttLite has three scales: hour, day large and day small.

History.
After having read this thread, i begun to think about it and wrote a first demostrator version.
Then, seeing that there was some interest in this thread, I posted this first version.
And continued to improve it, as a kind of challenge, to see what can be done and left it, because i do not use it.
These days an interest raised again in this thread and i posted my latest version.
Further improvements would mean to write a full project management program, and this is not in my to do list.
As there is some interest, i publish the current version as it is.
It is open source, any member can use, reuse, improve it in any way.

Attached the demo program with the xGantt.bas module.
I have not (yet) made a b4xlib library.
Depending on the interest i can / will give more details in the future.

Missing features.
1. Official holidays or free days are not taken into account, only Saturdays an Sundays.
2. Optimistic and pessimistic time estimations with the corresponding chart display.
3. Critical path.
4. Hour time line, only days are supported.
etc.

The class:

There exist two types of display.
The chart:

1673180649943.png



The table.

1673180736971.png




Data structure:

A xGantt chart is a composed of rows.
Each row has these properties:
1. The ID of the objcet
2. One of the three object types.
2.1. Task
2.2. Group
2.3. Milestone

Objects:
2.1. Task

1673428173231.png

1673428180107.png


This is the main object with different properties:
1. ID - a string that identifies the task.
2. Row - the row number in the chart.
3. Name - a string with the name of the task.
4. Color - only for the display.
5. Responsible - the name of the person in charge of the task
6. BeginDate - the begin date of the task.
This date could be calculated in function of the dependency on other tasks.
7. Duration - the duration in days.
8. Dependency - dependency on other tasks.
Five dependencies do exist:
- None - no dependency, this is always the case for the first task.
The EndDate is calculated with the Duration.
- FS - Finish to Start. The task starts when its predecessor task is finished with a lag or lead. Example Task 1.2
The BeginDate is calculated with the predecessors EndDate and the lag or lead and the EndDate is calculated with the duration.
- FF - Finish to Finish. The task must finish at the same time as its predecessor with a lag or lead. Example Task 2.5
The EndDate is calculated with the predecessors EndDate and the lag or lead and the BeginDate is calculated with the duration.
- SS - Start to Start. The task must start at the dame time as its predecessor with a lag or lead. Example Task 1.4
The BeginDate is calculated with the predecessors BeginDate and the lag or lead and the EndDate is calculated with the duration.
- SF - Start to Finish. The task must be finished when its predecessor starts with a lag or lead. Example Task 1.5
The EndDate is calculated with the predecessors BeginDate and the lag or lead and the BeginDate is calculated with the duration.
9. Completion - percentage of completion of the task.
10. PredecessorID - ID of the predecessor task in the dependency hierarchy.
11 SuccessorIDs - List of the IDs of the successor tasks in the dependency hierarchy. These values are calculated.
12. LagLead - the number of days before or after the begin or end of a task in the hierarchy, when there is a dependency.
13. EndDate - the end date of the task. This value is calculated.


2.2 Group

1673428197469.png


1. ID - a string that identifies the group.
2. Row - the row number in the chart.
3. Name - a string with the name of the group.
4. Color - only for the display.
5. Begin Task ID - the ID of the first task.
6. End Task ID - the ID of the last task.

2.3 Milestone

1673428211665.png


1. ID - a string that identifies the milestone.
2. Row - the row number in the chart.
3. Name - a string with the name of the milestone.
4. Color - only for the display.
5. Dependency - dependency on tasks.
- None - no dependency.
- TB Task Begin - begin of the task.
- TE Task End - end of the task.
6.1 Date of the milestone when there is no dependency.
6.2 Task ID - the ID of the task, if there is a dependency, and the date is calculated.
 

Attachments

  • xGanttDemoV1_0.zip
    303.2 KB · Views: 304
Last edited:

MrKim

Well-Known Member
Licensed User
Longtime User
FYI, completion has been left out of Loads and Inserts, adding to the end of the list can get you out of bounds errors.
 

MrKim

Well-Known Member
Licensed User
Longtime User
Could you please be more precise in what conditions you get the problem ?
First let me say what a wonderful job you have done. I wish I had your talent. While this program is not what I need I am learning A LOT that will help me do what I want. Thank you. I only mentioned the errors to save others some time. Absolutely not a criticism.

% complete:
This is done only when loading the examples, even though the field is on TableEdit:
B4X:
    MyGantt.SetCompletion("1.1", 100)
But never here:
B4X:
Private Sub btnEditUpdate_Click
'    xcvsCursor.ClearRect(xcvsCursor.TargetRect)
    Private Err As Boolean
    
    Select btnEditUpdate.Text
        Case "Add"
            Err = EditAdd
        Case "Insert At"
            Err = EditInsertAt
        Case "Update"
            EditUpdate
    End Select
    
    If Err = False Then
        pnlEdit.Visible = False
        DrawChart
    End If
End Sub
out of bounds errors:
I get this when I try to delete the last line in the table:
B4X:
Waiting for debugger to connect...
Program started.
Call B4XPages.GetManager.LogEvents = True to enable logging B4XPages events.
Error occurred on line: 1066 (xGantt)
java.lang.IndexOutOfBoundsException: Index -1 out of bounds for length 23
    at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64)
    at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70)
    at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:248)
    at java.base/java.util.Objects.checkIndex(Objects.java:372)
    at java.base/java.util.ArrayList.get(ArrayList.java:458)
    at anywheresoftware.b4a.objects.collections.List.Get(List.java:122)
    at b4j.xGanttDemo.xgantt._updategroups(xgantt.java:7928)
    at b4j.xGanttDemo.xgantt._drawtable(xgantt.java:6334)
    at b4j.xGanttDemo.xgantt._drawchart(xgantt.java:751)
    at b4j.xGanttDemo.xgantt$ResumableSub_DeleteTask.resume(xgantt.java:4572)
    at b4j.xGanttDemo.xgantt._deletetask(xgantt.java:4167)
    at b4j.xGanttDemo.xgantt._deleteitem(xgantt.java:4117)
    at b4j.xGanttDemo.xgantt$ResumableSub_ItemDelete.resume(xgantt.java:638)
    at anywheresoftware.b4a.shell.DebugResumableSub$DelegatableResumableSub.resumeAsUserSub(DebugResumableSub.java:47)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:629)
    at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:237)
    at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:167)
    at jdk.internal.reflect.GeneratedMethodAccessor2.invoke(Unknown Source)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:109)
    at anywheresoftware.b4a.shell.ShellBA.raiseEvent2(ShellBA.java:98)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:96)
    at anywheresoftware.b4a.shell.DebugResumableSub$DelegatableResumableSub.resume(DebugResumableSub.java:42)
    at anywheresoftware.b4a.BA.checkAndRunWaitForEvent(BA.java:154)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:103)
    at anywheresoftware.b4a.shell.ShellBA.raiseEvent2(ShellBA.java:98)
    at anywheresoftware.b4a.BA$1.run(BA.java:234)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
    at java.base/java.security.AccessController.doPrivileged(Native Method)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
    at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
    at java.base/java.lang.Thread.run(Thread.java:834)
Also,
When editing/adding code blows up if you don't enter the date perfectly.
You cannot move a line to the last line. You must move the last line up. This is what I was trying to do when I encountered issues.
1688812765370.png

I believe I was trying to insert a line at the end when I started having issues.
 

klaus

Expert
Licensed User
Longtime User
Thank you for your reporting.
1: %Completion is ony taken into account when you update an existing task.
When adding a new task, I admitted that nothing has been done, therefore %Completion is 0.
I should either hide the %Completion field or take the value into account.

2: Incorrect date, yes the program crashes. I had in mind to add a date picker, but have never done it.

3: Adding / removing lines I have for sure not tested all possibilities.
With wrong data, there will be for sure some other crashes.

I do not know if anybody is using this class.
 
Last edited:
Top