Automatic Layouts
JointJS ships a family of automatic layout algorithms that position a graph from its structure, so you don't place nodes by hand: directed graph, force-directed, tree, stack, grid, and MSAGL. They differ in the shape they produce and in how you call them, but driving one from @joint/react comes down to the same two things: run the layout once your elements have their sizes, and let it write the new positions back onto the cells you already render. This chapter shows that pattern with the directed-graph layout; the rest work the same way.
A complete example​
The pipeline below starts with no positions of its own. Once its cards render and report their sizes, the directed-graph layout sorts them into ranks: Start at the top, a Test / Lint branch fanning out from Build, and everything converging on Done. Use the toolbar to switch between top-down and left-to-right and watch it re-flow.
How a layout runs in @joint/react​
Whichever layout you pick, it needs each node's size to place it without overlaps. How you supply that size decides when you can run the layout.
By default a @joint/react node measures itself: HTMLHost and HTMLBox size the element from its rendered content, so its dimensions only exist after it renders. Run a layout any sooner and you arrange zero-sized boxes, stacked at the origin. useOnElementsMeasured waits for the right moment: it fires on the first pass, once the paper has measured the elements, and again on any later size change. Read the graph with useGraph, then run your layout from the callback, guarding on isInitial so it runs the one time the sizes first appear. Here it is with directed graph:
import { useGraph, useOnElementsMeasured } from '@joint/react';
import { DirectedGraph } from '@joint/layout-directed-graph';
function Layout() {
const { graph } = useGraph();
useOnElementsMeasured(({ isInitial }) => {
if (isInitial) {
DirectedGraph.layout(graph, { rankDir: 'TB' });
}
});
return null;
}
A layout reads the elements and links already on the graph and writes a position onto each element. Because those are the same models @joint/react renders, the diagram re-flows on its own with nothing to wire up. Call it from a component inside your <GraphProvider>, and call it again from an event handler to re-flow later, which is how the demo responds when you flip the direction.
useOnElementsMeasured is the right trigger whether your nodes measure themselves or carry explicit sizes. With explicit sizes (a fixed size on the cell, rendered as plain SVG or with <HTMLHost useModelGeometry>) it simply fires as soon as the graph is populated, so you don't change anything. See Reacting after measurement for more on the hook: its { isInitial, paper, graph } payload, targeting a specific paper, and reacting to later size changes.
The directed-graph layout​
The layout used above lives in its own open-source package, @joint/layout-directed-graph. Add it alongside @joint/react:
- npm
- pnpm
- yarn
npm add @joint/layout-directed-graph
pnpm add @joint/layout-directed-graph
yarn add @joint/layout-directed-graph
import { DirectedGraph } from '@joint/layout-directed-graph';
DirectedGraph.layout(graph, options) takes the graph (or an array of cells) plus an options object. The ones you reach for most:
rankDirsets the flow direction:'TB'(top-to-bottom),'BT','LR', or'RL'.nodeSepis the gap between nodes in the same rank.rankSepis the gap between ranks.marginXandmarginYpad around the whole graph.
DirectedGraph.layout(graph, {
rankDir: 'LR',
nodeSep: 40,
rankSep: 60,
});
See the DirectedGraph API reference for the full list, including clusters, ranking algorithms, and link routing.
Other layouts​
Directed graph is one of several layouts JointJS provides. The React pattern above carries over to all of them; what changes is the call, its options, and where it comes from:
- Force-Directed runs as a force-directed simulation you start and step.
- Tree is a class (
new layout.TreeLayout(...)) for tree-like graphs. - Grid and Stack arrange elements into a grid, rows, or columns with a static
layout()call. - MSAGL brings Microsoft's layered (Sugiyama) layout through the separate
@joint/layout-msaglpackage.
Each one's entry point and options live in the layout API reference. Whatever you choose, run it once your elements have their sizes, exactly as above.