/** * TypeScript type imports: * * @import { Graph } from '../graphlib/graph.js'; */ import * as _ from 'lodash-es'; import * as util from './util.js'; export { run, undo }; /* * Breaks any long edges in the graph into short segments that span 1 layer * each. This operation is undoable with the denormalize function. * * Pre-conditions: * * 1. The input graph is a DAG. * 2. Each node in the graph has a "rank" property. * * Post-condition: * * 1. All edges in the graph have a length of 1. * 2. Dummy nodes are added where edges have been split into segments. * 3. The graph is augmented with a "dummyChains" attribute which contains * the first dummy in each chain of dummy nodes produced. */ function run(g) { g.graph().dummyChains = []; _.forEach(g.edges(), function (edge) { normalizeEdge(g, edge); }); } /** * @param {Graph} g */ function normalizeEdge(g, e) { var v = e.v; var vRank = g.node(v).rank; var w = e.w; var wRank = g.node(w).rank; var name = e.name; var edgeLabel = g.edge(e); var labelRank = edgeLabel.labelRank; if (wRank === vRank + 1) return; g.removeEdge(e); /** * @typedef {Object} Attrs * @property {number} width * @property {number} height * @property {ReturnType} edgeLabel * @property {any} edgeObj * @property {ReturnType["rank"]} rank * @property {string} [dummy] * @property {ReturnType["labelpos"]} [labelpos] */ /** @type {Attrs | undefined} */ var attrs = undefined; var dummy, i; for (i = 0, ++vRank; vRank < wRank; ++i, ++vRank) { edgeLabel.points = []; attrs = { width: 0, height: 0, edgeLabel: edgeLabel, edgeObj: e, rank: vRank, }; dummy = util.addDummyNode(g, 'edge', attrs, '_d'); if (vRank === labelRank) { attrs.width = edgeLabel.width; attrs.height = edgeLabel.height; attrs.dummy = 'edge-label'; attrs.labelpos = edgeLabel.labelpos; } g.setEdge(v, dummy, { weight: edgeLabel.weight }, name); if (i === 0) { g.graph().dummyChains.push(dummy); } v = dummy; } g.setEdge(v, w, { weight: edgeLabel.weight }, name); } function undo(g) { _.forEach(g.graph().dummyChains, function (v) { var node = g.node(v); var origLabel = node.edgeLabel; var w; g.setEdge(node.edgeObj, origLabel); while (node.dummy) { w = g.successors(v)[0]; g.removeNode(v); origLabel.points.push({ x: node.x, y: node.y }); if (node.dummy === 'edge-label') { origLabel.x = node.x; origLabel.y = node.y; origLabel.width = node.width; origLabel.height = node.height; } v = w; node = g.node(v); } }); }