2024-06-11
Layouting example for Entitree Flex

Hayleigh Thompson
Software Engineer
We add a new layouting algorithm to our example lineup with the addition of Entitree Flex. This algorithm is similar to d3-hierarchy but allows for sibling nodes as well as nodes with different dimensions.
This example was very kindly contributed by GitHub user @kaustubhxd , thanks Kaustubh! Check it out below.
import { Position } from '@xyflow/react';
import { layoutFromMap } from 'entitree-flex';
const nodeWidth = 150;
const nodeHeight = 36;
const Orientation = {
Vertical: 'vertical',
Horizontal: 'horizontal',
};
const entitreeSettings = {
clone: true, // returns a copy of the input, if your application does not allow editing the original object
enableFlex: true, // has slightly better performance if turned off (node.width, node.height will not be read)
firstDegreeSpacing: 100, // spacing in px between nodes belonging to the same source, e.g. children with same parent
nextAfterAccessor: 'spouses', // the side node prop used to go sideways, AFTER the current node
nextAfterSpacing: 100, // the spacing of the "side" nodes AFTER the current node
nextBeforeAccessor: 'siblings', // the side node prop used to go sideways, BEFORE the current node
nextBeforeSpacing: 100, // the spacing of the "side" nodes BEFORE the current node
nodeHeight, // default node height in px
nodeWidth, // default node width in px
orientation: Orientation.Vertical, // "vertical" to see parents top and children bottom, "horizontal" to see parents left and
rootX: 0, // set root position if other than 0
rootY: 0, // set root position if other than 0
secondDegreeSpacing: 100, // spacing in px between nodes not belonging to same parent eg "cousin" nodes
sourcesAccessor: 'parents', // the prop used as the array of ancestors ids
sourceTargetSpacing: 100, // the "vertical" spacing between nodes in vertical orientation, horizontal otherwise
targetsAccessor: 'children', // the prop used as the array of children ids
};
const { Top, Bottom, Left, Right } = Position;
export const layoutElements = (tree, rootId, direction = 'TB') => {
const isTreeHorizontal = direction === 'LR';
const { nodes: entitreeNodes, rels: entitreeEdges } = layoutFromMap(
rootId,
tree,
{
...entitreeSettings,
orientation: isTreeHorizontal
? Orientation.Horizontal
: Orientation.Vertical,
},
);
const nodes = [],
edges = [];
entitreeEdges.forEach((edge) => {
const sourceNode = edge.source.id;
const targetNode = edge.target.id;
const newEdge = {};
newEdge.id = 'e' + sourceNode + targetNode;
newEdge.source = sourceNode;
newEdge.target = targetNode;
newEdge.type = 'smoothstep';
newEdge.animated = 'true';
// Check if target node is spouse or sibling
const isTargetSpouse = !!edge.target.isSpouse;
const isTargetSibling = !!edge.target.isSibling;
if (isTargetSpouse) {
newEdge.sourceHandle = isTreeHorizontal ? Bottom : Right;
newEdge.targetHandle = isTreeHorizontal ? Top : Left;
} else if (isTargetSibling) {
newEdge.sourceHandle = isTreeHorizontal ? Top : Left;
newEdge.targetHandle = isTreeHorizontal ? Bottom : Right;
} else {
newEdge.sourceHandle = isTreeHorizontal ? Right : Bottom;
newEdge.targetHandle = isTreeHorizontal ? Left : Top;
}
edges.push(newEdge);
});
entitreeNodes.forEach((node) => {
const newNode = {};
const isSpouse = !!node?.isSpouse;
const isSibling = !!node?.isSibling;
const isRoot = node?.id === rootId;
if (isSpouse) {
newNode.sourcePosition = isTreeHorizontal ? Bottom : Right;
newNode.targetPosition = isTreeHorizontal ? Top : Left;
} else if (isSibling) {
newNode.sourcePosition = isTreeHorizontal ? Top : Left;
newNode.targetPosition = isTreeHorizontal ? Bottom : Right;
} else {
newNode.sourcePosition = isTreeHorizontal ? Right : Bottom;
newNode.targetPosition = isTreeHorizontal ? Left : Top;
}
newNode.data = { label: node.name, direction, isRoot, ...node };
newNode.id = node.id;
newNode.type = 'custom';
newNode.width = nodeWidth;
newNode.height = nodeHeight;
newNode.position = {
x: node.x,
y: node.y,
};
nodes.push(newNode);
});
return { nodes, edges };
};Get Pro examples, prioritized bug reports, 1:1 support from the maintainers, and more with React Flow Pro
Last updated on
