Rappid - layout

layout.ForceDirected

ForceDirected plugin implements automatic layouts for graphs using a force-directed approach. This is useful for, usually larger, undirected graphs.

Installation

Include the joint.layout.ForceDirected.js file into your HTML:

<script src="joint.layout.ForceDirected.js"></script>

Usage

ForceDirected layout plugin auto-layouts graphs based on three forces: repulsive force (forces nodes to move out of each other), attractive force (tries to get nodes together like a spring) and a gravity force (tendency of the nodes to move to a certain point).

The ForceDirected constructor accepts a couple of parameters for configuring the layout. The gravityCenter parameter is the point the nodes tend to move to. This is usually set to the center of the area where the nodes are to be laid out. charge parameter affects the repulsive force. Bigger the parameter is, bigger the repulsive force. linkDistance and linkStrength both affect the attractive force (you can think of it as parameters of a spring that tights together two nodes). Bigger the linkStrength, bigger the attractive force between two connected nodes. On the other hand, smaller the linkDistance, shorter links you allow and so the attractive force is bigger between two connected nodes.

There is no one-fits-all set of parameters that would give great result for all possible graphs. Therefore, it is suggested that you to play with the parameters, try to set different values so that it gives a good result for your use case.

var graphLayout = new joint.layout.ForceDirected({
    graph: graph // or array of selected cells
    x: 0,
    y: 0,
    width: 600,
    height: 400,
    gravityCenter: { x: 300, y: 200 },
    charge: 180,
    linkDistance: 30
});

graphLayout.start();

Array.from({ length: 100 }).forEach(function() { graphLayout.step(); });

Note: It is recommended to use the requestAnimationFrame for stepping the layout.

layout.GridLayout

GridLayout implements automatic layouts for graphs. This is useful in many scenarios, one of them being e.g. automatically positioning elements in Stencil.

Installation

Include the joint.layout.GridLayout.js file into your HTML:

<script src="joint.layout.GridLayout.js"></script>

Usage

GridLayout plugin exposes one function joint.layout.GridLayout.layout(graphOrElements, options). The first parameter graphOrElements is the joint.dia.Graph or an array of joint.dia.Elements we want to layout. The second parameter options is an object that contains various options for configuring the layout.

graph.addCells([
  new joint.shapes.standard.Rectangle({ size: { width: 80, height: 50 }}),
  new joint.shapes.standard.Rectangle({ size: { width: 50, height: 50 }}),
  new joint.shapes.standard.Ellipse({ size: { width: 80, height: 50 }}),
  new joint.shapes.standard.Ellipse({ size: { width: 50, height: 50 }})
]);

// Layout the entire graph
joint.layout.GridLayout.layout(graph, {
  columns: 2,
  columnWidth: 100,
  rowHeight: 70
});

// Layout the ellipses with minimal resulting `y` coordinate equals 100.
var ellipses = graph.getElements().filter(function(el) {
    return el instanceof joint.shapes.standard.Ellipse;
});
joint.layout.GridLayout.layout(ellipses, {
    columns: 2,
    marginY: 100
});

Here are the options for configuring the GridLayout:

  • columns - Number of columns. It defaults to 1.
  • columnWidth
    • 'auto' - width of a column is equal to the widest element amongst all elements
    • 'compact' - width of a column is equal to the widest element in the column
    • number - value of a column width (e.g. 200)
    It defaults to 'auto'.
  • rowHeight
    • 'auto' - height of a row is equal to the highest element amongst all elements
    • 'compact' - height of a row is equal to the highest element in the row
    • number - value of a row height (e.g. 100)
    It defaults to 'auto'.
  • verticalAlign
    • 'top' - the elements in the grid are aligned to the top of a grid cell
    • 'middle' - the elements in the grid are aligned to the center of a grid cell
    • 'bottom' - the elements in the grid are aligned to the bottom of a grid cell
    It defaults to 'top' (if centre) is disabled).
  • horizontalAlign
    • 'left' - the elements in the grid are aligned to the left side of a grid cell
    • 'middle' - the elements in the grid are aligned to the center of a grid cell
    • 'right' - the elements in the grid are aligned to the right side of a grid cell
    It defaults to 'left' (if centre) is disabled).
  • columnGap - the horizontal gap between columns. It defaults to 0.
  • rowGap - the vertical gap between rows. It defaults to 0.
  • resizeToFit - Resizes the elements to fit a grid cell, preserving the aspect ratio (default: false)
  • marginX - Sets the origin (x coordinate) of the most top-left element. It defaults to 0.
  • marginY - Sets the origin (y coordinate) of the most top-left element. It defaults to 0.
  • deep - Uses deep positioning for elements when set to true. i.e. moves not only the elements but also their descendants. It defaults to false.
  • parentRelative - Position the elements relatively to their parents.
    var padding = 20;
    // layout the children of the element `el`
    joint.layout.GridLayout.layout(el.getEmbeddedCells(), {
      parentRelative: true,
      marginX: padding,
      marginY: padding
    });
    // resize the element `el` to fit all children
    el.fitEmbeds({ padding: padding });
    
  • setAttributes(element, { position, size }, opt) - a callback function to customize how the positions (and sizes when resizeToFit enabled) are set to the elements.
  • dx deprecated - Shifts the elements horizontally by a given amount. It defaults to 0.
  • dy deprecated - Shifts the elements vertically by a given amount. It defaults to 0.
  • centre deprecated - Positions the elements in the centre of a grid cell. It defaults to true.

The function returns an object with various geometry information.

  • bbox - a tight bounding box around the elements
  • gridX - an array of x-coordinates of vertical separators between columns.
  • gridY - an array of y-coordinates of horizontal separators between rows.
  • rowHeights - an array of row heights
  • columnWidths - an array of column widths

layout.TreeLayout

layout.TreeLayout is a layout algorithm for tree-like graphs. It's great for displaying org charts, mind maps, class hierarchies and other tree structures. The layout.TreeLayout is strong in combination with the ui.TreeLayoutView which implements drag&drop functionality useful when editing a tree structure.

Installation

Include joint.layout.treeLayout.js file to your HTML:

<script src="joint.layout.treeLayout.js"></script>

Usage

Create an object of layout.TreeLayout type passing your graph (object of type joint.dia.Graph) as a parameter. Then you can just call the layout() method and the graph will be automatically laid out. It's important to note that the position of the root element of the tree will stay the same as it was before the layout. This allows you to move the tree to a position you want or have your tree be laid out around the root.

var graphLayout = new joint.layout.TreeLayout({
    graph: graph,
    parentGap: 20,
    siblingGap: 20
});

// Root element position stays the same after the layout.
// In this demo, we assume the root is the first element.
var root = graph.getElements()[0].position(200, 200);

graphLayout.layout();

Configuration

The following table lists options that you can pass to the layout.TreeLayout constructor function:

graph The JointJS graph object on which you want to perform the layout.
parentGap The distance between a parent element and its children. Defaults to 20.
siblingGap The distance between siblings. Defaults to 20.
firstChildGap The distance between the first sibling and its parent. It's applicable only for diagonal layouts ('TL', 'TR','BL', 'BR'). It defaults to 20.
direction The default direction of the layout. It can be set to one of the following values: 'L', 'R', 'T', 'B' (for left-to-right, right-to-left, top-to-bottom and bottom-to-top layouts) or diagonal variants 'TL', 'TR','BL', 'BR' (for top-left, top-right, bottom-left and bottom-right). It defaults to 'R'.

The direction defines how an element connects its parent. For instance element.set('direction', 'R') will appear on the right side to the parent element. Note that, this option is only used for nodes that do not have a direction property explicitelly set.

filter(children, parent, opt)

An arbitrary element or sub-tree can be skipped by the layout. By providing a filter function, one can control, which elements will be laid out and which not.

The filter function returns an array of elements to be laid out and runs for every single parent element in the graph.

Parameters:
  • children is an array of siblings
  • parent is the parent of the children or null, when children are roots
  • opt is the option object passed to layout() method when calling the layout.

// e.g. a collapse branch is not visible in the paper but resides in the graph.
function(children) {
    return children.filter(function(child) {
        return child.get('visible');
    });
}

No element is filtered out by default.

updatePosition(element, position, opt) A function responsible for setting the resulting position on the elements. It calls element.set('position', position, opt); by default. It can be used for positioning the elements in an animated manner. For instance:
element.transition('position', position, {
    delay: 300,
    valueFunction: joint.util.interpolate.object,
});
updateVertices(link, vertices, opt) A function responsible for setting the resulting vertices on the links. It calls link.set('vertices', vertices, opt); by default. If the option is defined as null no vertices will be set by the layout.
attributeNames An object that maps element attributes accepted by the layout to user defined attribute names. Useful for resolving conflicts when an attribute is already in use by the application logic. e.g Setting { siblingRank: 'index' } will make the layout look for the index attribute instead of siblingRank when trying to figure out the order of siblings.

The tree layout also reads some element properties allowing for a fine control of the layout engine. These are:

direction

The direction of the layout for this specific node. Note the tree layout can handle even mixed layout directions on a per-node basis.

See the globally defined direction in the TreeLayout constructor function configuration.

siblingRank The index of the element among its siblings.
offset The additional distance from the parent (the real distance is a sum of parentGap - defined globally in the TreeLayout constructor function configuration. - and the offset).
margin Extends the area occupied by the element on both sibling sides.
element.set({
    direction: 'R',
    size: { width: 100, height: 100 },
    margin: 20
});
// as the `element` siblings are located above and under the element,
// it will in fact occupied an area of { width: 100, height: 140 }
prevSiblingGap The additional gap next to the element sub-tree on the side of the previous sibling. The previous sibling is defined as the sibling with the closest smaller siblingRank.
nextSiblingGap The additional gap next to the element sub-tree on the side of the next sibling. The next sibling is defined as the sibling with the closest larger siblingRank.
firstChildGap The distance between the element and the first child. It's applicable only for diagonal layouts ('TL', 'TR','BL', 'BR'). It overides the global firstChildGap option.

API

layout([opt])

Layout the graph in a tree. It iterates over all graph sources (elements without a parent) and layout them as separate trees.

The option object opt, which will be passed down to all operations on the graph made by the layout call. e.g. treeLayout.layout({ myFlag: true }) will internally set an element position as element.position(x, y, { myFlag: true });.

getLayoutBBox()

Returns the bounding box of all affected elements from the last layout run (i.e. elements, which have been filtered are not taken into account when calculating the bounding box).