import _ from 'lodash' import util from './util' /* * 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) }) } function normalizeEdge (g, e) { let v = e.v let vRank = g.node(v).rank const w = e.w const wRank = g.node(w).rank const name = e.name const edgeLabel = g.edge(e) const labelRank = edgeLabel.labelRank if (wRank === vRank + 1) return g.removeEdge(e) let dummy let attrs let 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) { let node = g.node(v) const origLabel = node.edgeLabel let w = null 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) } }) } export default { run, undo }