At work, I’ve had a task to implement a Gantt chart diagram to show dependencies and order of some… let’s say, milestones.
Given this feature is in a very unstable beta in Google Charts, I thought to myself: “Why don’t I implement it on my own?”.
And tried to recall my D3 knowledge.
I’ve also found a minimalistic, but helpful example / screenshot of some Gantt chart implementation:
The challenges I’ve faced were:
order milestones on a timeline
scale milestones to fit in a viewport
create pretty connection lines
center text inside each milestone
And since D3 is a data-driven library, I’ve used map/reduce where possible.
Here’s how the result looked like:
The full implementation code is under the cut.
I hope the implementation is more or less clear, but here are some details: the algorithm consists of three main parts - initial data pre-processing - (parsing and validating dates, calculating the default values and so on); calculating the graphics params (positions, sizes) and finally, rendering that into SVG.
I’ve tried using caches whenever possible to optimize the performance and save some calculation time by just creating maps id -> object, since the algorithm refers to objects by their IDs a lot (like getting all the children of an element or getting a particular child’s data).
The data pre-processing is basically computing the length of each element based on either startDate and endDate or startDate and duration. Adding the endDate and duration option is possible and trivial, but I thought this is a less useful feature.
The transformation of data is the most interesting part - we need to calculate the positions of each element on a “screen”, and it heavily relies on data sorting mode - if we need to sort the data by the amount of children - this is somewhat simple. But if we sort data by dates - we need to count for element’s index in the overall list of elements.
Then we calculate the parameters of connection lines. They might be redundant for some users, but in my case it was essential to show the dependencies between elements sorted by children count. This is less trivial, since one needs to find the bends of each line. Hence I decided to simplify this problem by putting all the lines under the rectangles and assuming every line consists of these sections:
the “input” and “output” pins (near the endDate end of a parent element and near startDate end of children element)
two vertical sections to reach the height of a children element
a connection between the lines from p. 2
The last piece of an algorithm is generating SVG. This is where D3 strikes in and, given all the params generated in the previous section, creates SVG elements in DOM tree and scales them considering svgOptions passed to the main function.
The implementation is below and the live demo is here
The data format is like follows
To create a chard on a page, you need to pass the reference to a valid existing DOM element where you want the diagram to appear, the data and the SVG options. These options define the looks of a chart - width, height of an element (rectangle), font size and so on. One more option is