Skip to Content
ExamplesLayout

Entitree Flex

import type { Edge, Node } from '@xyflow/vue'; import type { TreeNodeData } from './initialElements'; import { Position } from '@xyflow/vue'; import { layoutFromMap } from 'entitree-flex'; export type EntitreeNodeData = { label: string; direction: string; isRoot?: boolean; isSpouse?: boolean; isSibling?: boolean; children?: string[]; siblings?: string[]; spouses?: string[]; }; export type EntitreeNode = Node<EntitreeNodeData, 'custom'>; const nodeWidth = 150; const nodeHeight = 36; const Orientation = { Vertical: 'vertical', Horizontal: 'horizontal', } as const; 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 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" = parents top / children bottom, "horizontal" = parents left rootX: 0, // set root position if other than 0 rootY: 0, // set root position if other than 0 secondDegreeSpacing: 100, // spacing between nodes not belonging to the same parent, e.g. "cousin" nodes sourcesAccessor: 'parents', // the prop used as the array of ancestor 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 function layoutElements(tree: Record<string, TreeNodeData>, rootId: string | number, direction: 'TB' | 'LR' = 'TB') { const isTreeHorizontal = direction === 'LR'; const { nodes: entitreeNodes, rels: entitreeEdges } = layoutFromMap(rootId, tree, { ...entitreeSettings, orientation: isTreeHorizontal ? Orientation.Horizontal : Orientation.Vertical, }); const nodes: EntitreeNode[] = []; const edges: Edge[] = []; entitreeEdges.forEach((edge) => { const sourceNode = edge.source.id; const targetNode = edge.target.id; // check if the target node is a spouse or a sibling to pick which handles to connect const isTargetSpouse = !!edge.target.isSpouse; const isTargetSibling = !!edge.target.isSibling; let sourceHandle: Position; let targetHandle: Position; if (isTargetSpouse) { sourceHandle = isTreeHorizontal ? Bottom : Right; targetHandle = isTreeHorizontal ? Top : Left; } else if (isTargetSibling) { sourceHandle = isTreeHorizontal ? Top : Left; targetHandle = isTreeHorizontal ? Bottom : Right; } else { sourceHandle = isTreeHorizontal ? Right : Bottom; targetHandle = isTreeHorizontal ? Left : Top; } edges.push({ id: `e${sourceNode}${targetNode}`, source: sourceNode, target: targetNode, type: 'smoothstep', animated: true, sourceHandle, targetHandle, }); }); entitreeNodes.forEach((node) => { const isSpouse = !!node.isSpouse; const isSibling = !!node.isSibling; let sourcePosition: Position; let targetPosition: Position; if (isSpouse) { sourcePosition = isTreeHorizontal ? Bottom : Right; targetPosition = isTreeHorizontal ? Top : Left; } else if (isSibling) { sourcePosition = isTreeHorizontal ? Top : Left; targetPosition = isTreeHorizontal ? Bottom : Right; } else { sourcePosition = isTreeHorizontal ? Right : Bottom; targetPosition = isTreeHorizontal ? Left : Top; } nodes.push({ id: node.id, type: 'custom', position: { x: node.x, y: node.y }, width: nodeWidth, height: nodeHeight, sourcePosition, targetPosition, // `isRoot` (and isSpouse/isSibling/children/…) come from the spread entitree node data: { label: node.name, direction, ...node }, }); }); return { nodes, edges }; }
Last updated on