/** * The definition of the {@link Twolayer} interface, which is used to * customize {@link DecrossTwoLayer}. * * @packageDocumentation */ import type { SugiNode } from "../sugify"; /** * an operator for optimizing decrossings one layer at a time. * * This is used to customize {@link DecrossTwoLayer}. * * When called with `topDown = true` `topLayer` should be untouched, and * `bottomLayer` should be rearranged to minimize crossings. When * `topDown = false` then `topLayer` should be rearranged, and `bottomLayer` * should remain fixed. There are no requirements for how these needs to order * nodes, but doing so in such a way to minimize edge crossings is usually * desired. * * @example * * It's unlikely that you'll need to implement a custom two-layer operator as * this is already a heuristic solution to decrossing. However, in the event * that you do, we illustrate how to implement one where the order is stored in * the original nodes. Here dummy nodes (nodes that exist on long edges between * "real" nodes) are ordered according to the average value of their source and * target nodes. * * ```ts * function myTwoLayer(topLayer: SugiNode<{ ord: number }, unknown>[], bottomLayer: SugiNode<{ ord: number }, unknown>[], topDown: boolean): void { * let mutate = topDown ? bottomLayer : topLayer; * const vals = new Map(); * for (const node of mutate) { * const { data } = node; * const val = data.role === "node" ? data.node.data.ord ? (data.link.source.data.ord + data.link.target.data.ord) / 2; * vals.set(node, val); * } * layer.sort((a, b) => vals.get(a)! - vals.get(b)!); * } * ``` */ export type Twolayer = (topLayer: SugiNode[], bottomLayer: SugiNode[], topDown: boolean) => void;