A Gantt chart app as a single PHP file

New article in my series "a web app in one single PHP file". This time I'm interested in Gantt charts. They are ubiquitous in project managements, and I've used them in several occasions as a feature of third party softwares. I found them simple and useful, therefore I was motivated to implement my own version.

Gantt charts are calendars used to display the chronological progress of a project divided into tasks. Its useful as a planning tool (for tasks to come), and as a report tool (for tasks done). The main advantage of a software version of a Gantt chart is the automatic management of dependencies (task B must start after task A): the calendar gets automatically reorganised as one modifies/adds tasks. Other features I wanted in my own implementation were: subtasks, status (todo, wip, done, burning), comments, and a simple search tool.

I reused the same template as the two previous apps in this series of article (1, 2) and it was done in a little less than 1100 lines. As always, there is nothing else to do than copying the file on a PHP server for it to be ready to use (except for an obfuscation parameter to set for security). I've actually used it on a real project for a customer for several months at the time of writing. It would certainly not fit every one needs and taste, but it serves me well and is stable, so I'm confident in sharing it.

The user interface looks like this (completely fictitious data for illustrative purpose only):

After logging, the user access the main page displaying the Gantt chart. One can select a display range of one week or one month around the selected date (which is highlighted in the calendar). Tasks are displayed one per line, in chronological order of starting date, and grouped together (parent-childs). At the bottom of the calendar, info messages about the last three actions are displayed.

Next to the date selection, there is the input to add a new task, and below there is a filter tool. New tasks have a default starting/ending date equal to the currently selected date. The filter tool hides all currently displayed tasks but ones which include the keyword in their title, reference or comment.

The colored bars show the period during which tasks are performed. Color indicates the status (todo, wip, done, burning) of the task. The title of the task is preceded by its reference, and its parents' one (if any) to show the relation. A graphical representation of that relation would be welcome, but I couldn't find a way to design and implement it easily and gave up. I hope to find a nice solution one day, if you have one let me know!

Clicking on the bar of a task opens the task editor.

One can set the title, starting/ending date, and status. The parent of the task can be set to one of the currently displayed tasks, as well as the chronological dependency (task B after task A) among siblings. A text area allows the user to add comments about the task. And finally, one can create child tasks using the input at the bottom.

Security check avoids infinite loops in the parenthood relations and chronological dependencies, and reset chronological dependencies when the parent is modified. Also, modification of the dates or status are propagated with respect to these relations and dependencies. For example, when all childs become 'done', their parent's status also changes to 'done'. Or, if the end date of task gets extended, all following tasks are shifted accordingly (cf below for more details).

These checks and automations are really the only tricky part of the web app. The database schema is straightforward: one table to hold the task information and one for the chronological dependency.

The PHP API is nothing more than the usual CRUD. Tasks are returned as a dictionary with some extra information to help on the JS side to format the DOM (position and dimension of the bars):

Returned dictionary:

The JS code keeps a copy of the dictionary which it uses to create the bars in the DOM.

The rest of the JS code is just updating the content of the task editor when it is summoned, and sending the API requests as necessary when the user update a task or change the current date. The filtering function loop on the dictionary, search the keyword and update the display property of elements in the DOM accordingly. For convenience I've also added the possibility to save an edited task using shift+enter (instead of clicking on 'save').

On the PHP side, adding and deleting tasks are piece of cake, you just need to not forget to delete childs as well.

Check for infinite loops in dependencies and relations is done when saving data. Automatic update based on these dependencies and relations are done at the same time. It can seems to be a complex problem to solve, but actually it's rather simple if you apply recursively the rule 'always push to the right'.

  1. If the new end date is before a child's end date, set the new end date to the child's one.
  2. If the new start date is after the old start date, shift (recursively on childhood) all childs' start and end date toward the future by (new date - old date) days.
  3. If the new start date is before the parent start date, shift the task' and its childs' start and end date toward the future by (parent date - new date) days. Recursion on the parent.
  4. If the new end date is after the parent end date, set the parent end date to the child end date. Recursion on the parent.
  5. Recursion on all preceding tasks.
  6. Recursion on all following tasks.

And that's it. Things I would like to add: better representation of dependencies, and some export functions to create listing, pdf or images of the chart to share with my customers.

The code is available to download here. As usual, questions and comments are welcome, email me !

Edit on 2023/11/16: Modif the div containing preceding tasks to limit its height and add a scrollbar when necessary.

Edit on 2023/12/09: Modif to keep the filter active after the date changes.

in All, Web app,
Copyright 2021-2023 Baillehache Pascal