Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dist/dagre.cjs.js

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions dist/dagre.cjs.js.map

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions dist/dagre.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export interface GraphLabel {
marginy?: number | undefined;
acyclicer?: string | undefined;
ranker?: string | undefined;
rankalign?: 'top' | 'center' | 'bottom' | undefined;
}

export interface NodeConfig {
Expand Down
2 changes: 1 addition & 1 deletion dist/dagre.esm.js

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions dist/dagre.esm.js.map

Large diffs are not rendered by default.

16 changes: 13 additions & 3 deletions dist/dagre.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions dist/dagre.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/dagre.min.js

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions dist/dagre.min.js.map

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export interface GraphLabel {
marginy?: number | undefined;
acyclicer?: string | undefined;
ranker?: string | undefined;
rankalign?: 'top' | 'center' | 'bottom' | undefined;
}

export interface NodeConfig {
Expand Down
4 changes: 2 additions & 2 deletions lib/layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,8 @@ function updateInputGraph(inputGraph, layoutGraph) {
}

let graphNumAttrs = ["nodesep", "edgesep", "ranksep", "marginx", "marginy"];
let graphDefaults = { ranksep: 50, edgesep: 20, nodesep: 50, rankdir: "tb" };
let graphAttrs = ["acyclicer", "ranker", "rankdir", "align"];
let graphDefaults = { ranksep: 50, edgesep: 20, nodesep: 50, rankdir: "tb", rankalign: "center" };
let graphAttrs = ["acyclicer", "ranker", "rankdir", "align", "rankalign"];
let nodeNumAttrs = ["width", "height", "rank"];
let nodeDefaults = { width: 0, height: 0 };
let edgeNumAttrs = ["minlen", "weight", "width", "height", "labeloffset"];
Expand Down
13 changes: 11 additions & 2 deletions lib/position/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ function position(g) {
function positionY(g) {
let layering = util.buildLayerMatrix(g);
let rankSep = g.graph().ranksep;
let rankAlign = g.graph().rankalign;
let prevY = 0;
layering.forEach(layer => {
const maxHeight = layer.reduce((acc, v) => {
Expand All @@ -25,8 +26,16 @@ function positionY(g) {
return height;
}
}, 0);
layer.forEach(v => g.node(v).y = prevY + maxHeight / 2);
layer.forEach(v => {
let node = g.node(v);
if (rankAlign === "top") {
node.y = prevY + node.height / 2;
} else if (rankAlign === "bottom") {
node.y = prevY + maxHeight - node.height / 2;
} else {
node.y = prevY + maxHeight / 2;
}
});
prevY += maxHeight + rankSep;
});
}

27 changes: 27 additions & 0 deletions test/position-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,31 @@ describe("position", () => {
expect(g.node("sg1")).not.toHaveProperty("x");
expect(g.node("sg1")).not.toHaveProperty("y");
});

it("aligns nodes to top of rank when rankalign is top", () => {
g.graph().rankalign = "top";
g.setNode("a", { width: 50, height: 100, rank: 0, order: 0 });
g.setNode("b", { width: 50, height: 60, rank: 0, order: 1 });
position(g);
expect(g.node("a").y).toBe(100 / 2);
expect(g.node("b").y).toBe(60 / 2);
});

it("aligns nodes to bottom of rank when rankalign is bottom", () => {
g.graph().rankalign = "bottom";
g.setNode("a", { width: 50, height: 100, rank: 0, order: 0 });
g.setNode("b", { width: 50, height: 60, rank: 0, order: 1 });
position(g);
expect(g.node("a").y).toBe(100 - 100 / 2);
expect(g.node("b").y).toBe(100 - 60 / 2);
});

it("aligns nodes to center of rank when rankalign is center", () => {
g.graph().rankalign = "center";
g.setNode("a", { width: 50, height: 100, rank: 0, order: 0 });
g.setNode("b", { width: 50, height: 60, rank: 0, order: 1 });
position(g);
expect(g.node("a").y).toBe(100 / 2);
expect(g.node("b").y).toBe(100 / 2);
});
});