Tips on hierarchical diagrams

JointJS provides a facility to create hierarchy in your diagrams. The API is simple and contains three methods and two properties dealing with parent-child relationships between elements. The methods are embed(), unembed() and getEmbeddedCells(). The properties are embeds and parent (Please refer to the Nesting section of the joint.dia.Element model reference).

This tutorial shows how to take advantage of these methods in order to implement three functionalities common to parent-child relationships: child movement restriction to the parent area, expanding parent area to cover its children and reparenting.

Restricting child movement to the parent area

The goal is to restrict the movement of an element embedded in a parent in order disallow the user to drag the element outside the parent element area.

The trick here is to detect when the child element bounding box gets outside the bounding box of the parent and revert the child position if that happens.

Try to move the child element outside the parent element area.



            

Expanding parent area to cover its children

This section shows how to make the parent element automatically resizable so that it coveres its children.

Again, we'll react on the change:position event on the graph but this time we resize the parent element based on the position and size of its children. We also store the original position and size of the parent element so that we can shrink the parent element back if the child element we manipulate fits into the original parent element area.

Try to move the child element outside the parent element area and see how the parent element automatically expands/shirnks.




            

Reparenting

Another useful technique when dealing with parent-child relationships is being able to drop an element above another element and let the element below become a new parent of the dropped element. This way we alow the user to change the parentage via the UI.

First, we register a handler for the cell:pointerdown event on the paper that is triggered whenever a mousedown (touchstart) above a cell is emitted. This is where the dragging begins. In this handler, we unembed the dragged element if it was a child of a parent. Note that we also show the dragged element above all the other cells (toFront()) so that we always see it in the front while dragging. Second, we register a handler for the cell:pointerup event which is triggered when we drop the dragged element. In this handler, we find all the cells that are below the center of the dragged element. In this example, we pick the first one that is not the dragged element itself and make it a new parent of the dragged element. If you have more than one level of hierarchy in your application, you might want to find an element the most in the front (by looking at the z property) instead. We left this out of this example for simplicity.

Try to move the El B over El A, then move the El A. You should see the El B moves as well as it became a child of El A.