Bläddra i källkod

Update dagre.js

Lutz Roeder 4 år sedan
förälder
incheckning
3769838893
2 ändrade filer med 179 tillägg och 208 borttagningar
  1. 172 195
      source/dagre.js
  2. 7 13
      source/view-grapher.js

+ 172 - 195
source/dagre.js

@@ -27,16 +27,17 @@ dagre.layout = (graph, options) => {
     const buildLayoutGraph = (graph) => {
         const g = new dagre.Graph({ compound: true });
         g.setGraph(Object.assign({}, { ranksep: 50, edgesep: 20, nodesep: 50, rankdir: 'tb' }, graph.graph()));
-        for (const v of graph.nodes().keys()) {
-            const node = graph.node(v);
+        for (const entry of graph.nodes()) {
+            const v = entry[0];
+            const node = entry[1];
             g.setNode(v, {
                 width: node.width || 0,
                 height: node.height || 0
             });
             g.setParent(v, graph.parent(v));
         }
-        for (const e of graph.edges()) {
-            const edge = graph.edge(e);
+        for (const e of graph.edges().values()) {
+            const edge = e.label;
             g.setEdge(e.v, e.w, {
                 minlen: edge.minlen || 1,
                 weight: edge.weight || 1,
@@ -88,13 +89,15 @@ dagre.layout = (graph, options) => {
         const asNonCompoundGraph = (g) => {
             const graph = new dagre.Graph({});
             graph.setGraph(g.graph());
-            for (const v of g.nodes().keys()) {
+            for (const entry of g.nodes()) {
+                const v = entry[0];
                 if (g.children(v).length === 0) {
-                    graph.setNode(v, g.node(v));
+                    const node = entry[1];
+                    graph.setNode(v, node);
                 }
             }
-            for (const e of g.edges()) {
-                graph.setEdge(e.v, e.w, g.edge(e));
+            for (const e of g.edges().values()) {
+                graph.setEdge(e.v, e.w, e.label);
             }
             return graph;
         };
@@ -115,11 +118,11 @@ dagre.layout = (graph, options) => {
             const rank = maxRank(g);
             const length = rank === undefined ? 0 : rank + 1;
             const layering = Array.from(new Array(length), () => []);
-            for (const v of g.nodes().keys()) {
-                const node = g.node(v);
+            for (const entry of g.nodes()) {
+                const node = entry[1];
                 const rank = node.rank;
                 if (rank !== undefined) {
-                    layering[rank][node.order] = v;
+                    layering[rank][node.order] = entry[0];
                 }
             }
             return layering;
@@ -131,8 +134,8 @@ dagre.layout = (graph, options) => {
         const makeSpaceForEdgeLabels = (g) => {
             const graph = g.graph();
             graph.ranksep /= 2;
-            for (const e of g.edges()) {
-                const edge = g.edge(e);
+            for (const e of g.edges().values()) {
+                const edge = e.label;
                 edge.minlen *= 2;
                 if (edge.labelpos.toLowerCase() !== 'c') {
                     if (graph.rankdir === 'TB' || graph.rankdir === 'BT') {
@@ -190,13 +193,13 @@ dagre.layout = (graph, options) => {
         };
 
         const removeSelfEdges = (g) => {
-            for (const e of g.edges()) {
+            for (const e of g.edges().values()) {
                 if (e.v === e.w) {
                     const node = g.node(e.v);
                     if (!node.selfEdges) {
                         node.selfEdges = [];
                     }
-                    node.selfEdges.push({ e: e, label: g.edge(e) });
+                    node.selfEdges.push({ e: e, label: e.label });
                     g.removeEdge(e);
                 }
             }
@@ -228,7 +231,7 @@ dagre.layout = (graph, options) => {
                 return fas;
             };
             for (const e of dfsFAS(g)) {
-                const label = g.edge(e);
+                const label = e.label;
                 g.removeEdge(e);
                 label.forwardName = e.name;
                 label.reversed = true;
@@ -236,8 +239,8 @@ dagre.layout = (graph, options) => {
             }
         };
         const acyclic_undo = (g) => {
-            for (const e of g.edges()) {
-                const edge = g.edge(e);
+            for (const e of g.edges().values()) {
+                const edge = e.label;
                 if (edge.reversed) {
                     edge.points.reverse();
                     g.removeEdge(e);
@@ -252,7 +255,7 @@ dagre.layout = (graph, options) => {
         // Returns the amount of slack for the given edge. The slack is defined as the
         // difference between the length of the edge and its minimum length.
         const slack = (g, e) => {
-            return g.node(e.w).rank - g.node(e.v).rank - g.edge(e).minlen;
+            return g.node(e.w).rank - g.node(e.v).rank - e.label.minlen;
         };
 
         /*
@@ -310,7 +313,7 @@ dagre.layout = (graph, options) => {
                 const findMinSlackEdge = (t, g) => {
                     let minKey = Number.POSITIVE_INFINITY;
                     let minValue = undefined;
-                    for (const e of g.edges()) {
+                    for (const e of g.edges().values()) {
                         if (t.hasNode(e.v) !== t.hasNode(e.w)) {
                             const key = slack(g, e);
                             if (key < minKey) {
@@ -378,7 +381,7 @@ dagre.layout = (graph, options) => {
                     visited.add(v);
                     let rank = Number.MAX_SAFE_INTEGER;
                     for (const e of g.outEdges(v)) {
-                        const x = dfs(e.w) - g.edge(e).minlen;
+                        const x = dfs(e.w) - e.label.minlen;
                         if (x < rank) {
                             rank = x;
                         }
@@ -434,12 +437,13 @@ dagre.layout = (graph, options) => {
                 const simplify = (g) => {
                     const graph = new dagre.Graph();
                     graph.setGraph(g.graph());
-                    for (const v of g.nodes().keys()) {
-                        graph.setNode(v, g.node(v));
+                    for (const entry of g.nodes()) {
+                        graph.setNode(entry[0], entry[1]);
                     }
-                    for (const e of g.edges()) {
-                        const simpleLabel = graph.edge(e) || { weight: 0, minlen: 1 };
-                        const label = g.edge(e);
+                    for (const e of g.edges().values()) {
+                        const simpleEdge =  graph.edge(e.v, e.w);
+                        const simpleLabel = simpleEdge ? simpleEdge.label : { weight: 0, minlen: 1 };
+                        const label = e.label;
                         graph.setEdge(e.v, e.w, {
                             weight: simpleLabel.weight + label.weight,
                             minlen: Math.max(simpleLabel.minlen, label.minlen)
@@ -479,25 +483,23 @@ dagre.layout = (graph, options) => {
                     const calcCutValue = (t, g, child) => {
                         const childLab = t.node(child);
                         const parent = childLab.parent;
-                        // True if the child is on the tail end of the edge in the directed graph
-                        let childIsTail = true;
                         // The graph's view of the tree edge we're inspecting
-                        let graphEdge = g.edge(child, parent);
+                        const edge = g.edge(child, parent);
+                        // True if the child is on the tail end of the edge in the directed graph
+                        const childIsTail = edge ? true : false;
                         // The accumulated cut value for the edge between this node and its parent
-                        if (!graphEdge) {
-                            childIsTail = false;
-                            graphEdge = g.edge(parent, child);
-                        }
+                        const graphEdge = edge ? edge.label : g.edge(parent, child).label;
                         let cutValue = graphEdge.weight;
                         for (const e of g.nodeEdges(child)) {
                             const isOutEdge = e.v === child;
                             const other = isOutEdge ? e.w : e.v;
                             if (other !== parent) {
                                 const pointsToHead = isOutEdge === childIsTail;
-                                const otherWeight = g.edge(e).weight;
+                                const otherWeight = e.label.weight;
                                 cutValue += pointsToHead ? otherWeight : -otherWeight;
-                                if (t.hasEdge(child, other)) {
-                                    const otherCutValue = t.edge(child, other).cutvalue;
+                                const edge = t.edge(child, other);
+                                if (edge) {
+                                    const otherCutValue = edge.label.cutvalue;
                                     cutValue += pointsToHead ? -otherCutValue : otherCutValue;
                                 }
                             }
@@ -507,7 +509,7 @@ dagre.layout = (graph, options) => {
                     const assignCutValue = (t, g, child) => {
                         const childLab = t.node(child);
                         const parent = childLab.parent;
-                        t.edge(child, parent).cutvalue = calcCutValue(t, g, child);
+                        t.edge(child, parent).label.cutvalue = calcCutValue(t, g, child);
                     };
                     let vs = postorder(t, Array.from(t.nodes().keys()));
                     vs = vs.slice(0, vs.length - 1);
@@ -516,7 +518,7 @@ dagre.layout = (graph, options) => {
                     }
                 };
                 const leaveEdge = (tree) => {
-                    return Array.from(tree.edges()).find((e) => tree.edge(e).cutvalue < 0);
+                    return Array.from(tree.edges().values()).find((e) => e.label.cutvalue < 0);
                 };
                 const enterEdge = (t, g, edge) => {
                     let v = edge.v;
@@ -524,7 +526,7 @@ dagre.layout = (graph, options) => {
                     // For the rest of this function we assume that v is the tail and w is the
                     // head, so if we don't have this edge in the graph we should flip it to
                     // match the correct orientation.
-                    if (!g.hasEdge(v, w)) {
+                    if (!g.edge(v, w)) {
                         v = edge.w;
                         w = edge.v;
                     }
@@ -543,7 +545,7 @@ dagre.layout = (graph, options) => {
                     const isDescendant = (tree, vLabel, rootLabel) => {
                         return rootLabel.low <= vLabel.lim && vLabel.lim <= rootLabel.lim;
                     };
-                    const candidates = Array.from(g.edges()).filter((edge) => flip === isDescendant(t, t.node(edge.v), tailLabel) && flip !== isDescendant(t, t.node(edge.w), tailLabel));
+                    const candidates = Array.from(g.edges().values()).filter((edge) => flip === isDescendant(t, t.node(edge.v), tailLabel) && flip !== isDescendant(t, t.node(edge.w), tailLabel));
                     let minKey = Number.POSITIVE_INFINITY;
                     let minValue = undefined;
                     for (const edge of candidates) {
@@ -572,7 +574,7 @@ dagre.layout = (graph, options) => {
                                 edge = g.edge(parent, v);
                                 flipped = true;
                             }
-                            g.node(v).rank = g.node(parent).rank + (flipped ? edge.minlen : -edge.minlen);
+                            g.node(v).rank = g.node(parent).rank + (flipped ? edge.label.minlen : -edge.label.minlen);
                         }
                     };
                     updateRanks(t, g);
@@ -610,8 +612,8 @@ dagre.layout = (graph, options) => {
         // Creates temporary dummy nodes that capture the rank in which each edge's label is going to, if it has one of non-zero width and height.
         // We do this so that we can safely remove empty ranks while preserving balance for the label's position.
         const injectEdgeLabelProxies = (g) => {
-            for (const e of g.edges()) {
-                const edge = g.edge(e);
+            for (const e of g.edges().values()) {
+                const edge = e.label;
                 if (edge.width && edge.height) {
                     const v = g.node(e.v);
                     const w = g.node(e.w);
@@ -639,14 +641,14 @@ dagre.layout = (graph, options) => {
                 const size = maxRank - minRank;
                 if (size > 0) {
                     const layers = new Array(size);
-                    for (const v of g.nodes().keys()) {
-                        const node = g.node(v);
+                    for (const entry of g.nodes()) {
+                        const node = entry[1];
                         if (node.rank !== undefined) {
                             const rank = node.rank - minRank;
                             if (!layers[rank]) {
                                 layers[rank] = [];
                             }
-                            layers[rank].push(v);
+                            layers[rank].push(entry[0]);
                         }
                     }
                     let delta = 0;
@@ -741,12 +743,12 @@ dagre.layout = (graph, options) => {
             const nodeSep = 2 * height + 1;
             g.graph().nestingRoot = root;
             // Multiply minlen by nodeSep to align nodes on non-border ranks.
-            for (const e of g.edges()) {
-                g.edge(e).minlen *= nodeSep;
+            for (const e of g.edges().values()) {
+                e.label.minlen *= nodeSep;
             }
             // Calculate a weight that is sufficient to keep subgraphs vertically compact
             const sumWeights = (g) => {
-                return Array.from(g.edges()).reduce((acc, e) => acc + g.edge(e).weight, 0);
+                return Array.from(g.edges().values()).reduce((acc, e) => acc + e.label.weight, 0);
             };
             const weight = sumWeights(g) + 1;
             // Create border nodes and link them up
@@ -760,9 +762,8 @@ dagre.layout = (graph, options) => {
             const graphLabel = g.graph();
             g.removeNode(graphLabel.nestingRoot);
             delete graphLabel.nestingRoot;
-            for (const e of g.edges()) {
-                const edge = g.edge(e);
-                if (edge.nestingEdge) {
+            for (const e of g.edges().values()) {
+                if (e.label.nestingEdge) {
                     g.removeEdge(e);
                 }
             }
@@ -810,13 +811,13 @@ dagre.layout = (graph, options) => {
         //      the first dummy in each chain of dummy nodes produced.
         const normalize = (g) => {
             g.graph().dummyChains = [];
-            for (const e of g.edges()) {
+            for (const e of g.edges().values()) {
                 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 edgeLabel = e.label;
                 const labelRank = edgeLabel.labelRank;
                 if (wRank !== vRank + 1) {
                     g.removeEdge(e);
@@ -876,11 +877,11 @@ dagre.layout = (graph, options) => {
         };
 
         const removeEdgeLabelProxies = (g) => {
-            for (const v of g.nodes().keys()) {
-                const node = g.node(v);
+            for (const entry of g.nodes()) {
+                const node = entry[1];
                 if (node.dummy === 'edge-proxy') {
-                    g.edge(node.e).labelRank = node.rank;
-                    g.removeNode(v);
+                    node.e.label.labelRank = node.rank;
+                    g.removeNode(entry[0]);
                 }
             }
         };
@@ -1058,7 +1059,7 @@ dagre.layout = (graph, options) => {
                             tmp.weight = entry.weight;
                         }
                     });
-                    for (const e of cg.edges()) {
+                    for (const e of cg.edges().values()) {
                         const entryV = mappedEntries[e.v];
                         const entryW = mappedEntries[e.w];
                         if (entryV !== undefined && entryW !== undefined) {
@@ -1119,7 +1120,7 @@ dagre.layout = (graph, options) => {
                         }
                         else {
                             const result = inV.reduce((acc, e) => {
-                                const edge = g.edge(e);
+                                const edge = e.label;
                                 const nodeU = g.node(e.v);
                                 return {
                                     sum: acc.sum + (edge.weight * nodeU.order),
@@ -1233,10 +1234,9 @@ dagre.layout = (graph, options) => {
                 let rootPrev;
                 for (const v of vs) {
                     let child = g.parent(v);
-                    let parent;
                     let prevChild;
                     while (child) {
-                        parent = g.parent(child);
+                        const parent = g.parent(child);
                         if (parent) {
                             prevChild = prev[parent];
                             prev[parent] = child;
@@ -1301,7 +1301,7 @@ dagre.layout = (graph, options) => {
                         for (const e of edges) {
                             entries.push({
                                 pos: southPos[e.w],
-                                weight: g.edge(e).weight
+                                weight: e.label.weight
                             });
                         }
                         entries.sort((a, b) => a.pos - b.pos);
@@ -1407,21 +1407,22 @@ dagre.layout = (graph, options) => {
                 const graph = new dagre.Graph({ compound: true });
                 graph.setGraph({ root: root });
                 graph.setDefaultNodeLabel((v) => g.node(v));
-                for (const v of g.nodes().keys()) {
-                    const node = g.node(v);
+                for (const entry of g.nodes()) {
+                    const node = entry[1];
                     if (node.rank === rank || node.minRank <= rank && rank <= node.maxRank) {
+                        const v = entry[0];
                         graph.setNode(v);
                         const parent = g.parent(v);
                         graph.setParent(v, parent || root);
                         // This assumes we have only short edges!
                         if (relationship) {
                             for (const e of g.inEdges(v)) {
-                                graph.setEdge(e.v, v, { weight: g.edge(e).weight });
+                                graph.setEdge(e.v, v, { weight: e.label.weight });
                             }
                         }
                         else {
                             for (const e of g.outEdges(v)) {
-                                graph.setEdge(e.w, v, { weight: g.edge(e).weight });
+                                graph.setEdge(e.w, v, { weight: e.label.weight });
                             }
                         }
                         if ('minRank' in node) {
@@ -1511,8 +1512,8 @@ dagre.layout = (graph, options) => {
                 for (const node of g.nodes().values()) {
                     swapXYOne(node);
                 }
-                for (const e of g.edges()) {
-                    const edge = g.edge(e);
+                for (const e of g.edges().values()) {
+                    const edge = e.label;
                     for (const e of edge.points) {
                         swapXYOne(e);
                     }
@@ -1526,8 +1527,8 @@ dagre.layout = (graph, options) => {
                 for (const node of g.nodes().values()) {
                     node.y = -node.y;
                 }
-                for (const e of g.edges()) {
-                    const edge = g.edge(e);
+                for (const e of g.edges().values()) {
+                    const edge = e.label;
                     for (const attr of edge.points) {
                         attr.y = -attr.y;
                     }
@@ -1547,11 +1548,11 @@ dagre.layout = (graph, options) => {
                 node.width = node.height;
                 node.height = w;
             }
-            for (const e of g.edges()) {
-                const edge = g.edge(e);
-                const w = edge.width;
-                edge.width = edge.height;
-                edge.height = w;
+            for (const e of g.edges().values()) {
+                const label = e.label;
+                const w = label.width;
+                label.width = label.height;
+                label.height = w;
             }
         };
 
@@ -1628,41 +1629,36 @@ dagre.layout = (graph, options) => {
                 const borderType = reverseSep ? 'borderLeft' : 'borderRight';
                 const iterate = (setXsFunc, nextNodesFunc) => {
                     let stack = Array.from(blockG.nodes().keys());
-                    let elem = stack.pop();
                     const visited = new Set();
-                    while (elem) {
-                        if (visited.has(elem)) {
-                            setXsFunc(elem);
+                    while (stack.length > 0) {
+                        const v = stack.pop();
+                        if (visited.has(v)) {
+                            setXsFunc(v);
                         }
                         else {
-                            visited.add(elem);
-                            stack.push(elem);
-                            stack = stack.concat(nextNodesFunc(elem));
-                        }
-                        if (stack.length === 0) {
-                            break;
+                            visited.add(v);
+                            stack.push(v);
+                            stack = stack.concat(nextNodesFunc(v));
                         }
-                        elem = stack.pop();
                     }
                 };
                 // First pass, assign smallest coordinates
-                const pass1 = (elem) => {
+                const pass1 = (v) => {
                     let max = 0;
-                    for (const e of blockG.inEdges(elem)) {
-                        max = Math.max(max, xs[e.v] + blockG.edge(e));
+                    for (const e of blockG.inEdges(v)) {
+                        max = Math.max(max, xs[e.v] + e.label);
                     }
-                    xs[elem] = max;
+                    xs[v] = max;
                 };
                 // Second pass, assign greatest coordinates
-                const pass2 = (elem) => {
-                    const edges = blockG.outEdges(elem);
+                const pass2 = (v) => {
                     let min = Number.POSITIVE_INFINITY;
-                    for (const e of edges) {
-                        min = Math.min(min, xs[e.w] - blockG.edge(e));
+                    for (const e of blockG.outEdges(v)) {
+                        min = Math.min(min, xs[e.w] - e.label);
                     }
-                    const node = g.node(elem);
+                    const node = g.node(v);
                     if (min !== Number.POSITIVE_INFINITY && node.borderType !== borderType) {
-                        xs[elem] = Math.max(xs[elem], min);
+                        xs[v] = Math.max(xs[v], min);
                     }
                 };
                 iterate(pass1, blockG.predecessors.bind(blockG));
@@ -1674,42 +1670,38 @@ dagre.layout = (graph, options) => {
                 return xs;
             };
             const buildBlockGraph = (g, layering, root, reverseSep) => {
-                const sep = (nodeSep, edgeSep, reverseSep) => {
-                    return function(g, v, w) {
-                        const vLabel = g.node(v);
-                        const wLabel = g.node(w);
-                        let sum = 0;
-                        let delta;
-                        sum += vLabel.width / 2;
-                        if ('labelpos' in vLabel) {
-                            switch (vLabel.labelpos.toLowerCase()) {
-                                case 'l': delta = -vLabel.width / 2; break;
-                                case 'r': delta = vLabel.width / 2; break;
-                            }
-                        }
-                        if (delta) {
-                            sum += reverseSep ? delta : -delta;
-                        }
-                        delta = 0;
-                        sum += (vLabel.dummy ? edgeSep : nodeSep) / 2;
-                        sum += (wLabel.dummy ? edgeSep : nodeSep) / 2;
-                        sum += wLabel.width / 2;
-                        if ('labelpos' in wLabel) {
-                            switch (wLabel.labelpos.toLowerCase()) {
-                                case 'l': delta = wLabel.width / 2; break;
-                                case 'r': delta = -wLabel.width / 2; break;
-                            }
+                const nodeSep = g.graph().nodesep;
+                const edgeSep = g.graph().edgesep;
+                const sep = (vLabel, wLabel) => {
+                    let sum = 0;
+                    let delta;
+                    sum += vLabel.width / 2;
+                    if ('labelpos' in vLabel) {
+                        switch (vLabel.labelpos) {
+                            case 'l': delta = -vLabel.width / 2; break;
+                            case 'r': delta = vLabel.width / 2; break;
                         }
-                        if (delta) {
-                            sum += reverseSep ? delta : -delta;
+                    }
+                    if (delta) {
+                        sum += reverseSep ? delta : -delta;
+                    }
+                    delta = 0;
+                    sum += (vLabel.dummy ? edgeSep : nodeSep) / 2;
+                    sum += (wLabel.dummy ? edgeSep : nodeSep) / 2;
+                    sum += wLabel.width / 2;
+                    if ('labelpos' in wLabel) {
+                        switch (wLabel.labelpos) {
+                            case 'l': delta = wLabel.width / 2; break;
+                            case 'r': delta = -wLabel.width / 2; break;
                         }
-                        delta = 0;
-                        return sum;
-                    };
+                    }
+                    if (delta) {
+                        sum += reverseSep ? delta : -delta;
+                    }
+                    delta = 0;
+                    return sum;
                 };
                 const blockGraph = new dagre.Graph();
-                const graphLabel = g.graph();
-                const sepFn = sep(graphLabel.nodesep, graphLabel.edgesep, reverseSep);
                 for (const layer of layering) {
                     let u;
                     for (const v of layer) {
@@ -1717,8 +1709,9 @@ dagre.layout = (graph, options) => {
                         blockGraph.setNode(vRoot, {});
                         if (u) {
                             const uRoot = root[u];
-                            const prevMax = blockGraph.edge(uRoot, vRoot);
-                            blockGraph.setEdge(uRoot, vRoot, Math.max(sepFn(g, v, u), prevMax || 0));
+                            const edge = blockGraph.edge(uRoot, vRoot);
+                            const prevMax = edge ? edge.label : 0;
+                            blockGraph.setEdge(uRoot, vRoot, Math.max(sep(g.node(v), g.node(u)), prevMax));
                         }
                         u = v;
                     }
@@ -1937,9 +1930,10 @@ dagre.layout = (graph, options) => {
         };
 
         const positionSelfEdges = (g) => {
-            for (const v of g.nodes().keys()) {
-                const node = g.node(v);
+            for (const entry of g.nodes()) {
+                const node = entry[1];
                 if (node.dummy === 'selfedge') {
+                    const v = entry[0];
                     const selfNode = g.node(node.e.v);
                     const x = selfNode.x + selfNode.width / 2;
                     const y = selfNode.y;
@@ -1961,9 +1955,10 @@ dagre.layout = (graph, options) => {
         };
 
         const removeBorderNodes = (g) => {
-            for (const v of g.nodes().keys()) {
+            for (const entry of g.nodes()) {
+                const v = entry[0];
                 if (g.children(v).length) {
-                    const node = g.node(v);
+                    const node = entry[1];
                     const t = g.node(node.borderTop);
                     const b = g.node(node.borderBottom);
                     const l = g.node(node.borderLeft[node.borderLeft.length - 1]);
@@ -1974,16 +1969,18 @@ dagre.layout = (graph, options) => {
                     node.y = t.y + node.height / 2;
                 }
             }
-            for (const v of g.nodes().keys()) {
-                if (g.node(v).dummy === 'border') {
+            for (const entry of g.nodes()) {
+                const node = entry[1];
+                if (node.dummy === 'border') {
+                    const v = entry[0];
                     g.removeNode(v);
                 }
             }
         };
 
         const fixupEdgeLabelCoords = (g) => {
-            for (const e of g.edges()) {
-                const edge = g.edge(e);
+            for (const e of g.edges().values()) {
+                const edge = e.label;
                 if ('x' in edge) {
                     if (edge.labelpos === 'l' || edge.labelpos === 'r') {
                         edge.width -= edge.labeloffset;
@@ -2014,8 +2011,8 @@ dagre.layout = (graph, options) => {
             for (const node of g.nodes().values()) {
                 getExtremes(node);
             }
-            for (const e of g.edges()) {
-                const edge = g.edge(e);
+            for (const e of g.edges().values()) {
+                const edge = e.label;
                 if ('x' in edge) {
                     getExtremes(edge);
                 }
@@ -2024,8 +2021,8 @@ dagre.layout = (graph, options) => {
                 node.x -= minX;
                 node.y -= minY;
             }
-            for (const e of g.edges()) {
-                const edge = g.edge(e);
+            for (const e of g.edges().values()) {
+                const edge = e.label;
                 for (const p of edge.points) {
                     p.x -= minX;
                     p.y -= minY;
@@ -2076,8 +2073,8 @@ dagre.layout = (graph, options) => {
                 }
                 return { x: x + sx, y: y + sy };
             };
-            for (const e of g.edges()) {
-                const edge = g.edge(e);
+            for (const e of g.edges().values()) {
+                const edge = e.label;
                 const nodeV = g.node(e.v);
                 const nodeW = g.node(e.w);
                 let p1;
@@ -2131,10 +2128,11 @@ dagre.layout = (graph, options) => {
     * attributes can influence layout.
     */
     const updateInputGraph = (inputGraph, layoutGraph) => {
-        for (const v of inputGraph.nodes().keys()) {
-            const inputLabel = inputGraph.node(v);
-            const layoutLabel = layoutGraph.node(v);
+        for (const entry of inputGraph.nodes()) {
+            const inputLabel = entry[1];
             if (inputLabel) {
+                const v = entry[0];
+                const layoutLabel = layoutGraph.node(v);
                 inputLabel.x = layoutLabel.x;
                 inputLabel.y = layoutLabel.y;
                 if (layoutGraph.children(v).length) {
@@ -2143,9 +2141,9 @@ dagre.layout = (graph, options) => {
                 }
             }
         }
-        for (const e of inputGraph.edges()) {
-            const inputLabel = inputGraph.edge(e);
-            const layoutLabel = layoutGraph.edge(e);
+        for (const e of inputGraph.edges().values()) {
+            const inputLabel = e.label;
+            const layoutLabel = layoutGraph.edge(e.v, e.w).label;
             inputLabel.points = layoutLabel.points;
             if ('x' in layoutLabel) {
                 inputLabel.x = layoutLabel.x;
@@ -2184,8 +2182,7 @@ dagre.Graph = class {
         this._predecessors = {};
         this._out = {};
         this._successors = {};
-        this._edgeKeys = new Map();
-        this._edgeLabels = new Map();
+        this._edges = new Map();
     }
 
     isDirected() {
@@ -2259,12 +2256,12 @@ dagre.Graph = class {
                 delete this._children[v];
             }
             for (const e of Object.keys(this._in[v])) {
-                this.removeEdge(this._edgeKeys.get(e));
+                this.removeEdge(this._edges.get(e));
             }
             delete this._in[v];
             delete this._predecessors[v];
             for (const e of Object.keys(this._out[v])) {
-                this.removeEdge(this._edgeKeys.get(e));
+                this.removeEdge(this._edges.get(e));
             }
             delete this._out[v];
             delete this._successors[v];
@@ -2319,46 +2316,41 @@ dagre.Graph = class {
     }
 
     predecessors(v) {
-        const value = this._predecessors[v];
-        if (value) {
-            return Object.keys(value);
-        }
+        return Object.keys(this._predecessors[v]);
     }
 
     successors(v) {
-        const value = this._successors[v];
-        if (value) {
-            return Object.keys(value);
-        }
+        return Object.keys(this._successors[v]);
     }
 
     neighbors(v) {
-        const value = this.predecessors(v);
-        if (value) {
-            return Array.from(new Set(value.concat(this.successors(v))));
-        }
+        return Array.from(new Set(this.predecessors(v).concat(this.successors(v))));
     }
 
     edges() {
-        return this._edgeKeys.values();
+        return this._edges;
+    }
+
+    edge(v, w) {
+        return this._edges.get(this._edgeKey(this._isDirected, v, w));
     }
 
     setEdge(v, w, value, name) {
-        const e = this.edgeArgsToId(this._isDirected, v, w, name);
-        if (this._edgeLabels.has(e)) {
-            this._edgeLabels.set(e, value);
+        const e = this._edgeKey(this._isDirected, v, w, name);
+        const edge = this._edges.get(e);
+        if (edge) {
+            edge.label = value;
         }
         else {
             this.setNode(v);
             this.setNode(w);
-            this._edgeLabels.set(e, value);
             if (!this._isDirected && v > w) {
                 const tmp = v;
                 v = w;
                 w = tmp;
             }
-            const key = Object.freeze(name ? { v: v, w: w, name: name } : { v: v, w: w });
-            this._edgeKeys.set(e, key);
+            const edge = { label: value, v: v, w: w, name: name };
+            this._edges.set(e, edge);
             const incrementOrInitEntry = (map, k) => {
                 if (map[k]) {
                     map[k]++;
@@ -2369,29 +2361,18 @@ dagre.Graph = class {
             };
             incrementOrInitEntry(this._predecessors[w], v);
             incrementOrInitEntry(this._successors[v], w);
-            this._in[w][e] = key;
-            this._out[v][e] = key;
+            this._in[w][e] = edge;
+            this._out[v][e] = edge;
         }
     }
 
-    edge(v, w) {
-        const key = (arguments.length === 1 ? this.edgeObjToId(this._isDirected, arguments[0]) : this.edgeArgsToId(this._isDirected, v, w));
-        return this._edgeLabels.get(key);
-    }
-
-    hasEdge(v, w) {
-        const key = this.edgeArgsToId(this._isDirected, v, w);
-        return this._edgeLabels.has(key);
-    }
-
     removeEdge(e) {
-        const key = this.edgeObjToId(this._isDirected, e);
-        const edge = this._edgeKeys.get(key);
+        const key = this._edgeKey(this._isDirected, e.v, e.w, e.name);
+        const edge = this._edges.get(key);
         if (edge) {
             const v = edge.v;
             const w = edge.w;
-            this._edgeLabels.delete(key);
-            this._edgeKeys.delete(key);
+            this._edges.delete(key);
             const decrementOrRemoveEntry = (map, k) => {
                 if (!--map[k]) {
                     delete map[k];
@@ -2416,16 +2397,12 @@ dagre.Graph = class {
         return this.inEdges(v).concat(this.outEdges(v));
     }
 
-    edgeArgsToId(isDirected, v, w, name) {
+    _edgeKey(isDirected, v, w, name) {
         if (!isDirected && v > w) {
             return name ? w + ':' + v + ':' + name : w + ':' + v + ':';
         }
         return name ? v + ':' + w + ':' + name : v + ':' + w + ':';
     }
-
-    edgeObjToId(isDirected, edgeObj) {
-        return this.edgeArgsToId(isDirected, edgeObj.v, edgeObj.w, edgeObj.name);
-    }
 };
 
 if (typeof module !== 'undefined' && typeof module.exports === 'object') {

+ 7 - 13
source/view-grapher.js

@@ -35,9 +35,9 @@ grapher.Graph = class {
         if (!this._nodes.has(edge.w)) {
             throw new grapher.Error();
         }
-        const key = edge.v + ' ' + edge.w + ' ';
+        const key = edge.v + ':' + edge.w;
         if (!this._edges.has(key)) {
-            this._edges.set(key, edge);
+            this._edges.set(key, { v: edge.v, w: edge.w, label: edge });
         }
         return this;
     }
@@ -71,11 +71,7 @@ grapher.Graph = class {
     }
 
     edges() {
-        return Array.from(this._edges.values());
-    }
-
-    edge(key) {
-        return key;
+        return this._edges;
     }
 
     parent(key) {
@@ -164,9 +160,8 @@ grapher.Graph = class {
             }
         }
 
-        for (const edgeId of this.edges()) {
-            const edge = this.edge(edgeId);
-            edge.build(document, edgePathGroup, edgeLabelGroup);
+        for (const edge of this.edges().values()) {
+            edge.label.build(document, edgePathGroup, edgeLabelGroup);
         }
     }
 
@@ -191,9 +186,8 @@ grapher.Graph = class {
             }
         }
 
-        for (const edgeId of this.edges()) {
-            const edge = this.edge(edgeId);
-            edge.layout();
+        for (const edge of this.edges().values()) {
+            edge.label.layout();
         }
     }
 };