@dagrejs/dagre
Version:
Graph layout for JavaScript
90 lines (80 loc) • 2.23 kB
JavaScript
let util = require("./util");
module.exports = {
run: run,
undo: 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 = [];
g.edges().forEach(edge => normalizeEdge(g, edge));
}
function normalizeEdge(g, e) {
let v = e.v;
let vRank = g.node(v).rank;
let w = e.w;
let wRank = g.node(w).rank;
let name = e.name;
let edgeLabel = g.edge(e);
let labelRank = edgeLabel.labelRank;
if (wRank === vRank + 1) return;
g.removeEdge(e);
let dummy, attrs, 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) {
g.graph().dummyChains.forEach(v => {
let node = g.node(v);
let origLabel = node.edgeLabel;
let 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);
}
});
}
;