UNPKG

d3-dag

Version:

Layout algorithms for visualizing directed acylic graphs.

62 lines (61 loc) 2.35 kB
/** * {@link Coord}s assign `x` coordinates to every node, while * respecting the {@link SugiSeparation}. * * @packageDocumentation */ import { SugiNode, SugiSeparation } from "../sugify"; /** * an operator that assigns coordinates to layered {@link SugiNode}s * * This function must assign each node an `x` coordinate, and return the width * of the layout. The `x` coordinates should satisfy the * {@link SugiSeparation}, and all be between zero and the returned width. * * @example * * In order to illustrate what it might look like, below we demonstrate a * coordinate operator that assigns an x attached to the nodes themselves. If * the node is a dummy node (e.g. a point on an edge between two nodes), then * instead we average the coordinate. Note that this isn't compliant since it * might not respect `sep`, and is therefore only an illustration. * * ```ts * customCoord<N extends { x: number }, L>(layers: SugiNode<N, L>[][], sep: SugiSeparation<N, L>): number { * // determine span of xs * let min = Infinity; * let max = -Infinity; * for (const layer of layers) { * for (const node of layer) { * const { data } = node; * const x = node.x = data.role === "node" ? data.node.data.x : (data.link.source.data.x + data.link.target.data.x) / 2; * min = Math.min(min, x - sep(undefined, node)); * max = Math.max(max, x + sep(node, undefined)); * } * } * // assign xs * for (const node of dag) { * node.x = -= min; * } * return max - min; * } * ``` */ export interface Coord<in NodeDatum = never, in LinkDatum = never> { /** * assign coordinates to a layered graph * * @param layers - a layered graph of sugiyama nodes * @param sep - how much horizontal separation should exist between nodes * @returns width - the total width of the layout */ <N extends NodeDatum, L extends LinkDatum>(layers: SugiNode<N, L>[][], sep: SugiSeparation<N, L>): number; /** * This sentinel field is so that typescript can infer the types of NodeDatum * and LinkDatum, because the extra generics make it otherwise hard to infer. * It's a function to keep the same variance. * * @internal */ __sentinel__?: (_: NodeDatum, __: LinkDatum) => void; }