Tuesday, March 13, 2012

Gantt task dependencies in HTML/CSS

The task is to draw dependencies on a web-based Gantt Chart, using HTML / CSS (and JavaScript as required). There are "tasks" shown against the timeline, and some tasks are dependent on others, and it is required to draw nice thin lines connecting the two dependent tasks.

Like this*:

Task dependency as a right-angled line
My question - how?

My second question - how to do it in a nice way?

Canvas

One option is the canvas element. I have not yet experienced the miracle of canvas in full, yet I did try it in a prototype of an hierarchy configuration screen (I hope to be able to complete it one day - at least to add nice little direction arrows), as you can see below:

Hiearchy display using HTML elements on top of canvas

The connecting lines are drawn using canvas, the rest is HTML / CSS. Nice transparency overlap effect, eh?

From working on this I can confirm that combining canvas and HTML elements works well (even redrawing was smooth in my tests, the nodes can be moved thanks to jQueryUI Draggable widget), so it is a good approach in general.

Yet there are some nuances**, especially when dealing with window resizing - canvas has its own coordinate system compared to that of the HTML document, plus there is some seldom flicker on some browsers. I hope those problems can be solved, and I hope to work on that later, but for now I looked for something simpler, and leave the canvas out of the picture (heh).

That means using regular div's.

First, I was creating a mind picture of a div using some complex background images. You have to convince yourself that complex solutions are born due to fear of imagined task difficulty. Throw them away.

Two Divs

Next I came up with this approach:

Task dependency display using two divs

There are two narrow div elements - horizontal and vertical, - drawn for the connected Gantt items. Coorditane calculation here is obvious, so I see no need to repeat it.

The advantage here is that I can use standard div styles (e.g. CSS3 box-shadow) for the depedency lines. Actually, I can only think of shadows as an advantage here, because, straight after implementing this, a colleague looked over my shoulder and, surprised, said that he didn't think of using div borders like I did here.

Which I didn't. What a great idea!

One Div

...to rule them all. Here's how it would work:

Task dependency display using one div

I.e. a single div of correct dimensions, with transparent background and only top and right borders set. Hurrah!

The advantage of this method is, apart from using half the number of divs (and that's a great advantage!), is that I can still control the color and thickness of both link parts, and I can even use border-radius, if you fancy that kind of thing. If several divs overlap, the borders are still shown correctly for all the divs involved, which is great for complex Gantt Charts with lots of dependencies reminding of a war plan.

This is how it looks in the implemented form (a lot more features planned for this Gantt, I'll be able to show you when the project is live):

The end result - HTML-based Gantt task dependencies using one div

Very nice indeed.

I'll keep you posted on new interesting discoveries.


* - the little connector circle is a client request and a good idea - to be able to see when connection lines do connect, or are simply passing underneath the task. I implemented this by using yet another div, can't see a good way around it.

** - plus, I still prefer relying on the browser to render the elements using styles from CSS, that's perhaps a weakness I need to overcome - your feedback is welcome. I feel that coding graphics directly in canvas produces code that would be difficult to maintain - so it is a great tool but should be used only when needed.

3 comments:

  1. Great idea with a single div. I wonder, maybe it is even compatible with "semantic markup" somehow. I.e. maybe having these connector divs in markup can be justified semantically too? The "task" divs and the "bordered" divs are vertices and edges of the graph, so it is very good that each semantic object is represented by single markup object.

    ReplyDelete
    Replies
    1. Theoretically, yes. Though I don't chase semantic markup as much as I perhaps ought to :)

      There is one more div "in the picture", though - the small connector circle. Though your comment gives me a new idea - I can try to implement it using the :after pseudo-class.

      Thanks!

      Delete