Comparing version 0.5.1 to 0.5.2
@@ -0,1 +1,9 @@ | ||
v0.5.2 | ||
====== | ||
* Added support for positioning edge labels to the left or right of an edge. By | ||
default edges are positioned to the right. See the wiki for more details. | ||
* Fixed self loop layout with rankdir=LR and rankdir=RL. | ||
* Attribute keys are now treated as case-insensitive. | ||
v0.5.1 | ||
@@ -2,0 +10,0 @@ ====== |
@@ -24,2 +24,4 @@ /* | ||
module.exports = { | ||
graphlib: require("graphlib"), | ||
layout: require("./lib/layout"), | ||
@@ -26,0 +28,0 @@ debug: require("./lib/debug"), |
@@ -12,2 +12,3 @@ "use strict"; | ||
addBorderSegments = require("./add-border-segments"), | ||
coordinateSystem = require("./coordinate-system"), | ||
order = require("./order"), | ||
@@ -47,7 +48,10 @@ position = require("./position"), | ||
time(" insertSelfEdges", function() { insertSelfEdges(g); }); | ||
time(" adjustCoordinateSystem", function() { coordinateSystem.adjust(g); }); | ||
time(" position", function() { position(g); }); | ||
time(" positionSelfEdges", function() { positionSelfEdges(g); }); | ||
time(" setGraphDimensions", function() { setGraphDimensions(g); }); | ||
time(" removeBorderNodes", function() { removeBorderNodes(g); }); | ||
time(" normalize.undo", function() { normalize.undo(g); }); | ||
time(" fixupEdgeLabelCoords", function() { fixupEdgeLabelCoords(g); }); | ||
time(" undoCoordinateSystem", function() { coordinateSystem.undo(g); }); | ||
time(" translateGraph", function() { translateGraph(g); }); | ||
time(" assignNodeIntersects", function() { assignNodeIntersects(g); }); | ||
@@ -96,8 +100,12 @@ time(" reversePoints", function() { reversePointsForReversedEdges(g); }); | ||
var graphNumAttrs = ["nodesep", "edgesep", "ranksep", "marginx", "marginy"], | ||
graphDefaults = { ranksep: 50, edgesep: 10, nodesep: 50 }, | ||
graphDefaults = { ranksep: 50, edgesep: 10, nodesep: 50, rankdir: "tb" }, | ||
graphAttrs = ["acyclicer", "ranker", "rankdir", "align"], | ||
nodeNumAttrs = ["width", "height"], | ||
nodeDefaults = { width: 0, height: 0 }, | ||
edgeNumAttrs = ["minlen", "weight", "width", "height"], | ||
edgeDefaults = { minlen: 1, weight: 1, width: 0, height: 0 }; | ||
edgeNumAttrs = ["minlen", "weight", "width", "height", "labeloffset"], | ||
edgeDefaults = { | ||
minlen: 1, weight: 1, width: 0, height: 0, | ||
labeloffset: 10, labelpos: "r" | ||
}, | ||
edgeAttrs = ["labelpos"]; | ||
@@ -111,12 +119,13 @@ /* | ||
function buildLayoutGraph(inputGraph) { | ||
var g = new Graph({ multigraph: true, compound: true }); | ||
var g = new Graph({ multigraph: true, compound: true }), | ||
graph = canonicalize(inputGraph.graph()); | ||
g.setGraph(_.merge({}, | ||
graphDefaults, | ||
selectNumberAttrs(inputGraph.graph(), graphNumAttrs), | ||
_.pick(inputGraph.graph(), graphAttrs))); | ||
selectNumberAttrs(graph, graphNumAttrs), | ||
_.pick(graph, graphAttrs))); | ||
_.each(inputGraph.nodes(), function(v) { | ||
var label = inputGraph.node(v); | ||
g.setNode(v, _.defaults(selectNumberAttrs(label, nodeNumAttrs), nodeDefaults)); | ||
var node = canonicalize(inputGraph.node(v)); | ||
g.setNode(v, _.defaults(selectNumberAttrs(node, nodeNumAttrs), nodeDefaults)); | ||
g.setParent(v, inputGraph.parent(v)); | ||
@@ -126,4 +135,7 @@ }); | ||
_.each(inputGraph.edges(), function(e) { | ||
var label = inputGraph.edge(e); | ||
g.setEdge(e, _.defaults(selectNumberAttrs(label, edgeNumAttrs), edgeDefaults)); | ||
var edge = canonicalize(inputGraph.edge(e)); | ||
g.setEdge(e, _.merge({}, | ||
edgeDefaults, | ||
selectNumberAttrs(edge, edgeNumAttrs), | ||
_.pick(edge, edgeAttrs))); | ||
}); | ||
@@ -138,2 +150,5 @@ | ||
* Then we can place labels at these mid-points between nodes. | ||
* | ||
* We also add some minimal padding to the width to push the label for the edge | ||
* away from the edge itself a bit. | ||
*/ | ||
@@ -144,3 +159,7 @@ function makeSpaceForEdgeLabels(g) { | ||
_.each(g.edges(), function(e) { | ||
g.edge(e).minlen *= 2; | ||
var edge = g.edge(e); | ||
edge.minlen *= 2; | ||
if (edge.labelpos.toLowerCase() !== "c") { | ||
edge.width += edge.labeloffset; | ||
} | ||
}); | ||
@@ -190,13 +209,44 @@ } | ||
function setGraphDimensions(g) { | ||
var width = 0, | ||
height = 0, | ||
graph = g.graph(); | ||
function translateGraph(g) { | ||
var minX = Number.POSITIVE_INFINITY, | ||
maxX = 0, | ||
minY = Number.POSITIVE_INFINITY, | ||
maxY = 0, | ||
graphLabel = g.graph(), | ||
marginX = graphLabel.marginx || 0, | ||
marginY = graphLabel.marginy || 0; | ||
_.each(g.nodes(), function(v) { | ||
var node = g.node(v), | ||
x = node.x, | ||
y = node.y, | ||
w = node.width, | ||
h = node.height; | ||
minX = Math.min(minX, x - w / 2); | ||
maxX = Math.max(maxX, x + w / 2); | ||
minY = Math.min(minY, y - h / 2); | ||
maxY = Math.max(maxY, y + h / 2); | ||
}); | ||
minX -= marginX; | ||
minY -= marginY; | ||
_.each(g.nodes(), function(v) { | ||
var node = g.node(v); | ||
width = Math.max(width, node.x + node.width / 2); | ||
height = Math.max(height, node.y + node.height / 2); | ||
node.x -= minX; | ||
node.y -= minY; | ||
}); | ||
graph.width = width; | ||
graph.height = height; | ||
_.each(g.edges(), function(e) { | ||
var edge = g.edge(e); | ||
_.each(edge.points, function(p) { | ||
p.x -= minX; | ||
p.y -= minY; | ||
}); | ||
if (_.has(edge, "x")) { edge.x -= minX; } | ||
if (_.has(edge, "y")) { edge.y -= minY; } | ||
}); | ||
graphLabel.width = maxX - minX + marginX; | ||
graphLabel.height = maxY - minY + marginY; | ||
} | ||
@@ -223,2 +273,14 @@ | ||
function fixupEdgeLabelCoords(g) { | ||
_.each(g.edges(), function(e) { | ||
var edge = g.edge(e); | ||
if (_.has(edge, "x")) { | ||
switch (edge.labelpos) { | ||
case "l": edge.x -= edge.width / 2; break; | ||
case "r": edge.x += edge.width / 2; break; | ||
} | ||
} | ||
}); | ||
} | ||
function reversePointsForReversedEdges(g) { | ||
@@ -234,3 +296,2 @@ _.each(g.edges(), function(e) { | ||
function removeBorderNodes(g) { | ||
var rankdir = (g.graph().rankdir || "tb").toLowerCase(); | ||
_.each(g.nodes(), function(v) { | ||
@@ -242,22 +303,6 @@ if (g.children(v).length) { | ||
l = g.node(_.last(node.borderLeft)), | ||
r = g.node(_.last(node.borderRight)), | ||
tmp; | ||
r = g.node(_.last(node.borderRight)); | ||
if (rankdir === "bt" || rankdir === "rl") { | ||
tmp = t; | ||
t = b; | ||
b = tmp; | ||
} | ||
if (rankdir === "lr" || rankdir === "rl") { | ||
tmp = t; | ||
t = l; | ||
l = tmp; | ||
tmp = b; | ||
b = r; | ||
r = tmp; | ||
} | ||
node.width = r.x - l.x; | ||
node.height = b.y - t.y; | ||
node.width = Math.abs(r.x - l.x); | ||
node.height = Math.abs(b.y - t.y); | ||
node.x = l.x + node.width / 2; | ||
@@ -337,1 +382,9 @@ node.y = t.y + node.height / 2; | ||
} | ||
function canonicalize(attrs) { | ||
var newAttrs = {}; | ||
_.each(attrs, function(v, k) { | ||
newAttrs[k.toLowerCase()] = v; | ||
}); | ||
return newAttrs; | ||
} |
@@ -58,2 +58,3 @@ "use strict"; | ||
attrs.dummy = "edge-label"; | ||
attrs.labelpos = edgeLabel.labelpos; | ||
} | ||
@@ -60,0 +61,0 @@ g.setEdge(v, dummy, { weight: edgeLabel.weight }, name); |
@@ -206,3 +206,3 @@ "use strict"; | ||
function horizontalCompaction(g, layering, root, align) { | ||
function horizontalCompaction(g, layering, root, align, reverseSep) { | ||
// We use local variables for these parameters instead of manipulating the | ||
@@ -215,3 +215,3 @@ // graph because it becomes more verbose to access them in a chained manner. | ||
graphLabel = g.graph(), | ||
sepFn = sep(graphLabel.nodesep, graphLabel.edgesep); | ||
sepFn = sep(graphLabel.nodesep, graphLabel.edgesep, reverseSep); | ||
@@ -338,3 +338,5 @@ _.each(layering, function(layer) { | ||
var align = verticalAlignment(g, adjustedLayering, conflicts, neighborFn); | ||
var xs = horizontalCompaction(g, adjustedLayering, align.root, align.align); | ||
var xs = horizontalCompaction(g, adjustedLayering, | ||
align.root, align.align, | ||
horiz === "r"); | ||
if (horiz === "r") { | ||
@@ -352,11 +354,37 @@ xs = _.mapValues(xs, function(x) { return -x; }); | ||
function sep(nodeSep, edgeSep) { | ||
return function(g, v, u) { | ||
function sep(nodeSep, edgeSep, reverseSep) { | ||
return function(g, v, w) { | ||
var vLabel = g.node(v), | ||
uLabel = g.node(u), | ||
sums = uLabel.width + | ||
(uLabel.dummy ? edgeSep : nodeSep) + | ||
(vLabel.dummy ? edgeSep : nodeSep) + | ||
vLabel.width; | ||
return sums / 2; | ||
wLabel = g.node(w), | ||
sum = 0, | ||
delta; | ||
sum += vLabel.width / 2; | ||
if (_.has(vLabel, "labelpos")) { | ||
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 (_.has(wLabel, "labelpos")) { | ||
switch (wLabel.labelpos.toLowerCase()) { | ||
case "l": delta = wLabel.width / 2; break; | ||
case "r": delta = -wLabel.width / 2; break; | ||
} | ||
} | ||
if (delta) { | ||
sum += reverseSep ? delta : -delta; | ||
} | ||
delta = 0; | ||
return sum; | ||
}; | ||
@@ -363,0 +391,0 @@ } |
@@ -12,8 +12,2 @@ "use strict"; | ||
var rankDir = (g.graph().rankdir || "tb").toLowerCase(); | ||
if (rankDir === "lr" || rankDir === "rl") { | ||
swapWidthHeight(g); | ||
} | ||
positionY(g); | ||
@@ -23,12 +17,2 @@ _.each(positionX(g), function(x, v) { | ||
}); | ||
if (rankDir === "bt" || rankDir === "rl") { | ||
reverseY(g); | ||
} | ||
if (rankDir === "lr" || rankDir === "rl") { | ||
swapXY(g); | ||
swapWidthHeight(g); | ||
} | ||
translate(g); | ||
} | ||
@@ -49,61 +33,1 @@ | ||
function translate(g) { | ||
var minX = Number.POSITIVE_INFINITY, | ||
maxX = 0, | ||
minY = Number.POSITIVE_INFINITY, | ||
maxY = 0, | ||
graphLabel = g.graph(), | ||
marginX = graphLabel.marginx || 0, | ||
marginY = graphLabel.marginy || 0; | ||
_.each(g.nodes(), function(v) { | ||
var node = g.node(v), | ||
x = node.x, | ||
y = node.y, | ||
w = node.width, | ||
h = node.height; | ||
minX = Math.min(minX, x - w / 2); | ||
maxX = Math.max(maxX, x + w / 2); | ||
minY = Math.min(minY, y - h / 2); | ||
maxY = Math.max(maxY, y + h / 2); | ||
}); | ||
minX -= marginX; | ||
minY -= marginY; | ||
_.each(g.nodes(), function(v) { | ||
var node = g.node(v); | ||
node.x -= minX; | ||
node.y -= minY; | ||
}); | ||
graphLabel.width = maxX - minX + marginX; | ||
graphLabel.height = maxY - minY + marginY; | ||
} | ||
function reverseY(g) { | ||
_.each(g.nodes(), function(v) { | ||
var node = g.node(v); | ||
node.y = -node.y; | ||
}); | ||
} | ||
function swapWidthHeight(g) { | ||
_.each(g.nodes(), function(v) { | ||
var node = g.node(v), | ||
width = node.width, | ||
height = node.height; | ||
node.width = height; | ||
node.height = width; | ||
}); | ||
} | ||
function swapXY(g) { | ||
_.each(g.nodes(), function(v) { | ||
var node = g.node(v), | ||
x = node.x, | ||
y = node.y; | ||
node.x = y; | ||
node.y = x; | ||
}); | ||
} |
@@ -1,1 +0,1 @@ | ||
module.exports = "0.5.1"; | ||
module.exports = "0.5.2"; |
{ | ||
"name": "dagre", | ||
"version": "0.5.1", | ||
"version": "0.5.2", | ||
"description": "Graph layout for JavaScript", | ||
@@ -12,3 +12,3 @@ "author": "Chris Pettitt <cpettitt@gmail.com>", | ||
"dependencies": { | ||
"graphlib": "0.8.0", | ||
"graphlib": "^0.8.0", | ||
"lodash": "^2.4.1" | ||
@@ -15,0 +15,0 @@ }, |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
378156
43
2448
+ Addedgraphlib@0.8.3(transitive)
- Removedgraphlib@0.8.0(transitive)
Updatedgraphlib@^0.8.0