Skip to content

Layouts & options

type LayoutNode = { id: string; width: number; height: number };
type LayoutEdge = { source: string; target: string };
type EgoGraph<N, E> = { nodes: N[]; edges: E[]; root: string };
type Positions = Map<string, { x: number; y: number }>;

Your own fields travel through the generic types, so classification callbacks can inspect them.

polarPetal(graph, options?), radialDagre(graph, options?), and sectoredDagre(graph, options?) each return Positions. buildSpanningTree(graph, options?) and reachableNodeIds(nodeIds, edges, root) expose the underlying tree utilities.

LAYOUT_NAMES is the shipped layouts as strings. LayoutName is the matching union type. Both live in the root entry and do not import the implementations, so a mode picker can name a layout without pulling @dagrejs/dagre.

import { LAYOUT_NAMES, type LayoutName } from 'ego-graph';
const [layout, setLayout] = useState<LayoutName>('polarPetal');
for (const name of LAYOUT_NAMES) {
// 'radialDagre' | 'sectoredDagre' | 'polarPetal'
}

Map the name to a function only when you are ready to run that layout:

import { polarPetal, radialDagre, sectoredDagre, type LayoutName } from 'ego-graph';
const layouts: Record<LayoutName, typeof polarPetal> = {
polarPetal,
radialDagre,
sectoredDagre,
};
const positions = layouts[layout](graph);

The React Flow complete example uses this for its layout dropdown.

Every layout accepts these optional dials. DEFAULT_SPACING exports the same defaults.

Option Default Meaning
nodeSep 80 Gap between siblings in a Dagre subtree
rankSep 100 Gap between ranks in a Dagre subtree
minRingRadius 220 Minimum root-to-first-ring radius
ringPadding 60 Extra lateral space between branches
satelliteGap π / 3 Angular proximity that triggers satellite fanning
minSatelliteGap π / 12 Minimum separation for fanned satellites