diff --git a/ci/release/changelogs/next.md b/ci/release/changelogs/next.md
index 5e0f785ea..3198075d4 100644
--- a/ci/release/changelogs/next.md
+++ b/ci/release/changelogs/next.md
@@ -18,6 +18,7 @@
- Common invalid array separator `,` usage in class arrays returns a helpful error message [#1376](https://github.com/terrastruct/d2/pull/1376)
- Invalid `constraint` usage is met with an error message, preventing a common mistake of omitting `shape: sql_table` [#1379](https://github.com/terrastruct/d2/pull/1379)
- Connections now stop at all outside labels. [#1381](https://github.com/terrastruct/d2/pull/1381)
+- Container connections in `dagre` are more balanced [#1384](https://github.com/terrastruct/d2/pull/1384)
#### Bugfixes ⛑️
diff --git a/d2layouts/d2dagrelayout/layout.go b/d2layouts/d2dagrelayout/layout.go
index 6ee2c57ad..da29d818a 100644
--- a/d2layouts/d2dagrelayout/layout.go
+++ b/d2layouts/d2dagrelayout/layout.go
@@ -544,22 +544,7 @@ func getEdgeEndpoints(g *d2graph.Graph, edge *d2graph.Edge) (*d2graph.Object, *d
}
dst := edge.Dst
for len(dst.Children) > 0 && dst.Class == nil && dst.SQLTable == nil {
- dst = dst.ChildrenArray[0]
-
- // We want to get the top node of destinations
- for _, child := range dst.ChildrenArray {
- isHead := true
- for _, e := range g.Edges {
- if inContainer(e.Src, child) != nil && inContainer(e.Dst, dst) != nil {
- isHead = false
- break
- }
- }
- if isHead {
- dst = child
- break
- }
- }
+ dst = getLongestEdgeChainHead(g, dst)
}
if edge.SrcArrow && !edge.DstArrow {
// for `b <- a`, edge.Edge is `a -> b` and we expect this routing result
@@ -607,8 +592,73 @@ func generateAddEdgeLine(fromID, toID, edgeID string, width, height int) string
return fmt.Sprintf("g.setEdge({v:`%s`, w:`%s`, name:`%s`}, { width:%d, height:%d, labelpos: `c` });\n", escapeID(fromID), escapeID(toID), escapeID(edgeID), width, height)
}
+// getLongestEdgeChainHead finds the longest chain in a container and gets its head
+// If there are multiple chains of the same length, get the head closest to the center
+func getLongestEdgeChainHead(g *d2graph.Graph, container *d2graph.Object) *d2graph.Object {
+ rank := make(map[*d2graph.Object]int)
+ chainLength := make(map[*d2graph.Object]int)
+
+ for _, obj := range container.ChildrenArray {
+ isHead := true
+ for _, e := range g.Edges {
+ if inContainer(e.Src, container) != nil && inContainer(e.Dst, obj) != nil {
+ isHead = false
+ break
+ }
+ }
+ if !isHead {
+ continue
+ }
+ rank[obj] = 1
+ chainLength[obj] = 1
+ // BFS
+ queue := []*d2graph.Object{obj}
+ visited := make(map[*d2graph.Object]struct{})
+ for len(queue) > 0 {
+ curr := queue[0]
+ queue = queue[1:]
+ if _, ok := visited[curr]; ok {
+ continue
+ }
+ visited[curr] = struct{}{}
+ for _, e := range g.Edges {
+ child := inContainer(e.Dst, container)
+ if child == curr {
+ continue
+ }
+ if child != nil && inContainer(e.Src, curr) != nil {
+ if rank[curr]+1 > rank[child] {
+ rank[child] = rank[curr] + 1
+ chainLength[obj] = go2.Max(chainLength[obj], rank[child])
+ }
+ queue = append(queue, child)
+ }
+ }
+ }
+ }
+ max := int(math.MinInt32)
+ for _, obj := range container.ChildrenArray {
+ if chainLength[obj] > max {
+ max = chainLength[obj]
+ }
+ }
+
+ var heads []*d2graph.Object
+ for i, obj := range container.ChildrenArray {
+ if rank[obj] == 1 && chainLength[obj] == max {
+ heads = append(heads, container.ChildrenArray[i])
+ }
+ }
+
+ if len(heads) > 0 {
+ return heads[int(math.Floor(float64(len(heads))/2.0))]
+ }
+ return container.ChildrenArray[0]
+}
+
// getLongestEdgeChainTail gets the node at the end of the longest edge chain, because that will be the end of the container
-// and is what external connections should connect with
+// and is what external connections should connect with.
+// If there are multiple of same length, get the one closest to the middle
func getLongestEdgeChainTail(g *d2graph.Graph, container *d2graph.Object) *d2graph.Object {
rank := make(map[*d2graph.Object]int)
@@ -647,14 +697,20 @@ func getLongestEdgeChainTail(g *d2graph.Graph, container *d2graph.Object) *d2gra
}
}
max := int(math.MinInt32)
- var tail *d2graph.Object
for _, obj := range container.ChildrenArray {
- if rank[obj] >= max {
+ if rank[obj] > max {
max = rank[obj]
- tail = obj
}
}
- return tail
+
+ var tails []*d2graph.Object
+ for i, obj := range container.ChildrenArray {
+ if rank[obj] == max {
+ tails = append(tails, container.ChildrenArray[i])
+ }
+ }
+
+ return tails[int(math.Floor(float64(len(tails))/2.0))]
}
func inContainer(obj, container *d2graph.Object) *d2graph.Object {
diff --git a/e2etests/stable_test.go b/e2etests/stable_test.go
index dcdc0f8e7..809e791d5 100644
--- a/e2etests/stable_test.go
+++ b/e2etests/stable_test.go
@@ -2316,6 +2316,23 @@ Listen <-> Talk: {
target-arrowhead.shape: diamond
label: hear
}
+`,
+ },
+ {
+ name: "dagre-container",
+ script: `a: {
+ a
+ b
+ c
+}
+
+b: {
+ a
+ b
+ c
+}
+
+a -> b
`,
},
{
diff --git a/e2etests/testdata/regression/overlapping-edge-label/dagre/board.exp.json b/e2etests/testdata/regression/overlapping-edge-label/dagre/board.exp.json
index 19b79c792..dfd3b611c 100644
--- a/e2etests/testdata/regression/overlapping-edge-label/dagre/board.exp.json
+++ b/e2etests/testdata/regression/overlapping-edge-label/dagre/board.exp.json
@@ -10,7 +10,7 @@
"x": 0,
"y": 41
},
- "width": 1221,
+ "width": 1175,
"height": 125,
"opacity": 1,
"strokeDash": 0,
@@ -294,10 +294,10 @@
"id": "osvc",
"type": "rectangle",
"pos": {
- "x": 796,
+ "x": 406,
"y": 328
},
- "width": 415,
+ "width": 455,
"height": 125,
"opacity": 1,
"strokeDash": 0,
@@ -335,7 +335,7 @@
"id": "osvc.vm1",
"type": "rectangle",
"pos": {
- "x": 916,
+ "x": 446,
"y": 357
},
"width": 76,
@@ -376,7 +376,7 @@
"id": "osvc.vm2",
"type": "rectangle",
"pos": {
- "x": 1094,
+ "x": 645,
"y": 357
},
"width": 76,
@@ -440,19 +440,19 @@
"labelPercentage": 0,
"route": [
{
- "x": 854.75,
+ "x": 532.5,
"y": 166
},
{
- "x": 854.75,
+ "x": 532.5,
"y": 214.39999389648438
},
{
- "x": 854.75,
+ "x": 532.5,
"y": 246.89999389648438
},
{
- "x": 854.75,
+ "x": 532.5,
"y": 328.5
}
],
@@ -487,19 +487,19 @@
"labelPercentage": 0,
"route": [
{
- "x": 956.75,
+ "x": 634.5,
"y": 166
},
{
- "x": 956.75,
+ "x": 634.5,
"y": 214.39999389648438
},
{
- "x": 956.75,
+ "x": 634.5,
"y": 238.6999969482422
},
{
- "x": 956.75,
+ "x": 634.5,
"y": 287.5
}
],
@@ -534,20 +534,20 @@
"labelPercentage": 0,
"route": [
{
- "x": 1052.75,
+ "x": 730.5,
"y": 166
},
{
- "x": 1052.75,
+ "x": 730.5,
"y": 214.39999389648438
},
{
- "x": 1052.75,
- "y": 238.6999969482422
+ "x": 730.5,
+ "y": 246.89999389648438
},
{
- "x": 1052.75,
- "y": 287.5
+ "x": 730.5,
+ "y": 328.5
}
],
"isCurve": true,
@@ -581,19 +581,19 @@
"labelPercentage": 0,
"route": [
{
- "x": 1157,
+ "x": 811.5,
"y": 166
},
{
- "x": 1157,
+ "x": 811.5,
"y": 214.39999389648438
},
{
- "x": 1157,
+ "x": 811.5,
"y": 246.89999389648438
},
{
- "x": 1157,
+ "x": 811.5,
"y": 328.5
}
],
diff --git a/e2etests/testdata/regression/overlapping-edge-label/dagre/sketch.exp.svg b/e2etests/testdata/regression/overlapping-edge-label/dagre/sketch.exp.svg
index a72ff6169..e06e2c6dd 100644
--- a/e2etests/testdata/regression/overlapping-edge-label/dagre/sketch.exp.svg
+++ b/e2etests/testdata/regression/overlapping-edge-label/dagre/sketch.exp.svg
@@ -1,23 +1,23 @@
-
\ No newline at end of file
diff --git a/e2etests/testdata/stable/chaos2/dagre/board.exp.json b/e2etests/testdata/stable/chaos2/dagre/board.exp.json
index 51d5f6c54..6c720f8ad 100644
--- a/e2etests/testdata/stable/chaos2/dagre/board.exp.json
+++ b/e2etests/testdata/stable/chaos2/dagre/board.exp.json
@@ -10,7 +10,7 @@
"x": 0,
"y": 41
},
- "width": 834,
+ "width": 813,
"height": 1314,
"opacity": 1,
"strokeDash": 0,
@@ -51,7 +51,7 @@
"x": 20,
"y": 106
},
- "width": 595,
+ "width": 574,
"height": 1219,
"opacity": 1,
"strokeDash": 0,
@@ -92,7 +92,7 @@
"x": 40,
"y": 721
},
- "width": 421,
+ "width": 343,
"height": 572,
"opacity": 1,
"strokeDash": 0,
@@ -130,10 +130,10 @@
"id": "aa.bb.cc.dd",
"type": "rectangle",
"pos": {
- "x": 60,
+ "x": 62,
"y": 782
},
- "width": 223,
+ "width": 213,
"height": 140,
"opacity": 1,
"strokeDash": 0,
@@ -171,7 +171,7 @@
"id": "aa.bb.cc.dd.ee",
"type": "text",
"pos": {
- "x": 110,
+ "x": 102,
"y": 842
},
"width": 16,
@@ -211,7 +211,7 @@
"id": "aa.bb.cc.dd.ff",
"type": "rectangle",
"pos": {
- "x": 186,
+ "x": 178,
"y": 819
},
"width": 57,
@@ -252,7 +252,7 @@
"id": "aa.bb.cc.gg",
"type": "text",
"pos": {
- "x": 187,
+ "x": 171,
"y": 1043
},
"width": 17,
@@ -292,7 +292,7 @@
"id": "aa.bb.cc.hh",
"type": "rectangle",
"pos": {
- "x": 334,
+ "x": 177,
"y": 1189
},
"width": 63,
@@ -333,10 +333,10 @@
"id": "aa.bb.ii",
"type": "package",
"pos": {
- "x": 52,
+ "x": 140,
"y": 169
},
- "width": 497,
+ "width": 434,
"height": 161,
"opacity": 1,
"strokeDash": 0,
@@ -374,7 +374,7 @@
"id": "aa.bb.ii.jj",
"type": "diamond",
"pos": {
- "x": 458,
+ "x": 434,
"y": 204
},
"width": 50,
@@ -415,7 +415,7 @@
"id": "aa.bb.kk",
"type": "oval",
"pos": {
- "x": 501,
+ "x": 451,
"y": 1169
},
"width": 74,
@@ -456,7 +456,7 @@
"id": "aa.ll",
"type": "rectangle",
"pos": {
- "x": 698,
+ "x": 676,
"y": 772
},
"width": 54,
@@ -497,7 +497,7 @@
"id": "aa.mm",
"type": "cylinder",
"pos": {
- "x": 689,
+ "x": 667,
"y": 433
},
"width": 71,
@@ -538,7 +538,7 @@
"id": "aa.nn",
"type": "text",
"pos": {
- "x": 655,
+ "x": 633,
"y": 1178
},
"width": 16,
@@ -578,7 +578,7 @@
"id": "aa.oo",
"type": "rectangle",
"pos": {
- "x": 731,
+ "x": 709,
"y": 1155
},
"width": 63,
@@ -642,20 +642,20 @@
"labelPercentage": 0,
"route": [
{
- "x": 118,
+ "x": 109.75,
"y": 863.5
},
{
- "x": 118,
+ "x": 109.75,
"y": 910.2999877929688
},
{
- "x": 131.8000030517578,
- "y": 995.0999755859375
+ "x": 121.94999694824219,
+ "y": 994.9000244140625
},
{
- "x": 187,
- "y": 1045.5
+ "x": 170.75,
+ "y": 1044.5
}
],
"isCurve": true,
@@ -689,20 +689,20 @@
"labelPercentage": 0,
"route": [
{
- "x": 195.5,
+ "x": 179.75,
"y": 1064
},
{
- "x": 195.5,
+ "x": 179.75,
"y": 1112.4000244140625
},
{
- "x": 223.3000030517578,
- "y": 1140.300048828125
+ "x": 183.5500030517578,
+ "y": 1137.5
},
{
- "x": 334.5,
- "y": 1203.5
+ "x": 198.75,
+ "y": 1189.5
}
],
"isCurve": true,
@@ -736,43 +736,43 @@
"labelPercentage": 0,
"route": [
{
- "x": 104,
+ "x": 192,
"y": 331
},
{
- "x": 104,
+ "x": 192.1999969482422,
"y": 379
},
{
- "x": 104,
+ "x": 192.25,
"y": 414.8999938964844
},
{
- "x": 104,
+ "x": 192.25,
"y": 450.75
},
{
- "x": 104,
+ "x": 192.25,
"y": 486.6000061035156
},
{
- "x": 104,
+ "x": 192.25,
"y": 534.4000244140625
},
{
- "x": 104,
+ "x": 192.25,
"y": 570.25
},
{
- "x": 104,
+ "x": 192.25,
"y": 606.0999755859375
},
{
- "x": 104,
+ "x": 192.25,
"y": 708.7999877929688
},
{
- "x": 104,
+ "x": 192.25,
"y": 782
}
],
@@ -807,12 +807,12 @@
"labelPercentage": 0,
"route": [
{
- "x": 697.5,
- "y": 811.427978515625
+ "x": 675.75,
+ "y": 796.2960205078125
},
{
- "x": 614.5,
- "y": 865.427978515625
+ "x": 593.75,
+ "y": 804.2960205078125
}
],
"animated": false,
@@ -845,19 +845,19 @@
"labelPercentage": 0,
"route": [
{
- "x": 689,
- "y": 500
+ "x": 667,
+ "y": 502
},
{
- "x": 290.20001220703125,
- "y": 589.5999755859375
+ "x": 317.79901123046875,
+ "y": 590
},
{
- "x": 190.5,
+ "x": 230.5,
"y": 634
},
{
- "x": 190.5,
+ "x": 230.5,
"y": 722
}
],
@@ -892,31 +892,31 @@
"labelPercentage": 0,
"route": [
{
- "x": 725,
+ "x": 703,
"y": 552
},
{
- "x": 724.5999755859375,
+ "x": 702.7999877929688,
"y": 600
},
{
- "x": 724.5,
+ "x": 702.75,
"y": 624.0999755859375
},
{
- "x": 724.5,
+ "x": 702.75,
"y": 642.25
},
{
- "x": 724.5,
+ "x": 702.75,
"y": 660.4000244140625
},
{
- "x": 724.5,
+ "x": 702.75,
"y": 732.5
},
{
- "x": 724.5,
+ "x": 702.75,
"y": 772.5
}
],
@@ -951,12 +951,12 @@
"labelPercentage": 0,
"route": [
{
- "x": 689,
- "y": 505
+ "x": 667,
+ "y": 464
},
{
- "x": 615,
- "y": 566.9949951171875
+ "x": 594.25,
+ "y": 441.12298583984375
}
],
"animated": false,
@@ -989,20 +989,20 @@
"labelPercentage": 0,
"route": [
{
- "x": 697.5,
- "y": 810.8159790039062
+ "x": 675.75,
+ "y": 810.9920043945312
},
{
- "x": 381.8999938964844,
- "y": 872.9630126953125
+ "x": 370.95001220703125,
+ "y": 872.9979858398438
},
{
- "x": 283.20001220703125,
- "y": 968.7000122070312
+ "x": 273.45001220703125,
+ "y": 968.8499755859375
},
{
- "x": 204,
- "y": 1047.5
+ "x": 188.25,
+ "y": 1048.251953125
}
],
"isCurve": true,
@@ -1036,19 +1036,19 @@
"labelPercentage": 0,
"route": [
{
- "x": 689,
- "y": 473
+ "x": 667,
+ "y": 472
},
{
- "x": 545,
- "y": 393
+ "x": 531.2000122070312,
+ "y": 392.79998779296875
},
{
- "x": 509,
+ "x": 497.20001220703125,
"y": 364.6000061035156
},
{
- "x": 509,
+ "x": 497,
"y": 331
}
],
@@ -1083,12 +1083,12 @@
"labelPercentage": 0,
"route": [
{
- "x": 461,
- "y": 896.5
+ "x": 383,
+ "y": 895.5
},
{
- "x": 697.5,
- "y": 812.9320068359375
+ "x": 675.75,
+ "y": 811.5599975585938
}
],
"animated": false,
@@ -1121,56 +1121,56 @@
"labelPercentage": 0,
"route": [
{
- "x": 481,
+ "x": 403,
"y": 331
},
{
- "x": 481,
+ "x": 402.79998779296875,
"y": 364.6000061035156
},
{
- "x": 481,
+ "x": 402.75,
"y": 396.8999938964844
},
{
- "x": 481,
+ "x": 402.75,
"y": 432.75
},
{
- "x": 481,
+ "x": 402.75,
"y": 468.6000061035156
},
{
- "x": 481,
+ "x": 402.75,
"y": 516.4000244140625
},
{
- "x": 481,
+ "x": 402.75,
"y": 552.25
},
{
- "x": 481,
+ "x": 402.75,
"y": 588.0999755859375
},
{
- "x": 481,
+ "x": 402.75,
"y": 624.0999755859375
},
{
- "x": 481,
+ "x": 402.75,
"y": 642.25
},
{
- "x": 481,
+ "x": 402.75,
"y": 660.4000244140625
},
{
- "x": 524.2999877929688,
- "y": 737.2589721679688
+ "x": 457.3500061035156,
+ "y": 737.6060180664062
},
{
- "x": 697.5,
- "y": 796.2960205078125
+ "x": 675.75,
+ "y": 798.030029296875
}
],
"isCurve": true,
diff --git a/e2etests/testdata/stable/chaos2/dagre/sketch.exp.svg b/e2etests/testdata/stable/chaos2/dagre/sketch.exp.svg
index 11ccd6bec..0b05bcc4d 100644
--- a/e2etests/testdata/stable/chaos2/dagre/sketch.exp.svg
+++ b/e2etests/testdata/stable/chaos2/dagre/sketch.exp.svg
@@ -1,23 +1,23 @@
-aabbllmmnnoocciikkddgghhjjeeff1122 334455667788
-
-
-
-
-
-
-
-
-
+aabbllmmnnoocciikkddgghhjjeeff1122 334455667788
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/e2etests/testdata/stable/container_edges/dagre/board.exp.json b/e2etests/testdata/stable/container_edges/dagre/board.exp.json
index 186672dc6..9fd39e265 100644
--- a/e2etests/testdata/stable/container_edges/dagre/board.exp.json
+++ b/e2etests/testdata/stable/container_edges/dagre/board.exp.json
@@ -7,7 +7,7 @@
"id": "a",
"type": "rectangle",
"pos": {
- "x": 276,
+ "x": 40,
"y": 0
},
"width": 53,
@@ -48,10 +48,10 @@
"id": "g",
"type": "rectangle",
"pos": {
- "x": 193,
+ "x": 0,
"y": 207
},
- "width": 177,
+ "width": 133,
"height": 657,
"opacity": 1,
"strokeDash": 0,
@@ -89,7 +89,7 @@
"id": "g.b",
"type": "rectangle",
"pos": {
- "x": 276,
+ "x": 40,
"y": 236
},
"width": 53,
@@ -130,7 +130,7 @@
"id": "d",
"type": "rectangle",
"pos": {
- "x": 0,
+ "x": 153,
"y": 423
},
"width": 173,
@@ -171,7 +171,7 @@
"id": "d.h",
"type": "rectangle",
"pos": {
- "x": 20,
+ "x": 173,
"y": 488
},
"width": 133,
@@ -212,7 +212,7 @@
"id": "d.h.c",
"type": "rectangle",
"pos": {
- "x": 60,
+ "x": 213,
"y": 520
},
"width": 53,
@@ -253,7 +253,7 @@
"id": "g.e",
"type": "rectangle",
"pos": {
- "x": 233,
+ "x": 40,
"y": 768
},
"width": 53,
@@ -294,7 +294,7 @@
"id": "f",
"type": "rectangle",
"pos": {
- "x": 267,
+ "x": 41,
"y": 964
},
"width": 51,
@@ -358,19 +358,19 @@
"labelPercentage": 0,
"route": [
{
- "x": 302.75,
+ "x": 66.5,
"y": 66
},
{
- "x": 302.75,
+ "x": 66.5,
"y": 106
},
{
- "x": 302.75,
+ "x": 66.5,
"y": 180.10000610351562
},
{
- "x": 302.75,
+ "x": 66.5,
"y": 236.5
}
],
@@ -405,32 +405,32 @@
"labelPercentage": 0,
"route": [
{
- "x": 280.2860107421875,
+ "x": 66.5,
"y": 302.5
},
{
- "x": 253.0570068359375,
+ "x": 66.5,
"y": 326.1000061035156
},
{
- "x": 246.25,
+ "x": 66.5,
"y": 342
},
{
- "x": 246.25,
+ "x": 66.5,
"y": 357
},
{
- "x": 246.25,
+ "x": 66.5,
"y": 372
},
{
- "x": 219.64999389648438,
- "y": 453.5
+ "x": 95.9000015258789,
+ "y": 453.70001220703125
},
{
- "x": 113.25,
- "y": 539.5
+ "x": 213.5,
+ "y": 540.5
}
],
"isCurve": true,
@@ -464,19 +464,19 @@
"labelPercentage": 0,
"route": [
{
- "x": 73.25,
+ "x": 226.25,
"y": 648
},
{
- "x": 203.64999389648438,
+ "x": 79.8499984741211,
"y": 688
},
{
- "x": 239.0500030517578,
+ "x": 46.04999923706055,
"y": 712.0999755859375
},
{
- "x": 250.25,
+ "x": 57.25,
"y": 768.5
}
],
@@ -511,19 +511,19 @@
"labelPercentage": 0,
"route": [
{
- "x": 259.5,
+ "x": 61.23099899291992,
"y": 834.5
},
{
- "x": 259.5,
+ "x": 54.84600067138672,
"y": 858.0999755859375
},
{
- "x": 263.5,
+ "x": 54.849998474121094,
"y": 924
},
{
- "x": 279.5,
+ "x": 61.25,
"y": 964
}
],
@@ -558,19 +558,19 @@
"labelPercentage": 0,
"route": [
{
- "x": 305.968994140625,
+ "x": 75.74299621582031,
"y": 964
},
{
- "x": 321.9930114746094,
+ "x": 86.947998046875,
"y": 924
},
{
- "x": 326,
+ "x": 89.75,
"y": 904
},
{
- "x": 326,
+ "x": 89.75,
"y": 864
}
],
@@ -605,19 +605,19 @@
"labelPercentage": 0,
"route": [
{
- "x": 192.75,
- "y": 713
+ "x": 132.75,
+ "y": 726
},
{
- "x": 126.3499984741211,
- "y": 661
+ "x": 236.75,
+ "y": 663.5999755859375
},
{
- "x": 109.75,
+ "x": 262.75,
"y": 642.0999755859375
},
{
- "x": 109.75,
+ "x": 262.75,
"y": 618.5
}
],
diff --git a/e2etests/testdata/stable/container_edges/dagre/sketch.exp.svg b/e2etests/testdata/stable/container_edges/dagre/sketch.exp.svg
index b7dca0b91..4edd32fe9 100644
--- a/e2etests/testdata/stable/container_edges/dagre/sketch.exp.svg
+++ b/e2etests/testdata/stable/container_edges/dagre/sketch.exp.svg
@@ -1,16 +1,16 @@
-agdfbhec
-
+ .d2-1919566525 .fill-N1{fill:#0A0F25;}
+ .d2-1919566525 .fill-N2{fill:#676C7E;}
+ .d2-1919566525 .fill-N3{fill:#9499AB;}
+ .d2-1919566525 .fill-N4{fill:#CFD2DD;}
+ .d2-1919566525 .fill-N5{fill:#DEE1EB;}
+ .d2-1919566525 .fill-N6{fill:#EEF1F8;}
+ .d2-1919566525 .fill-N7{fill:#FFFFFF;}
+ .d2-1919566525 .fill-B1{fill:#0D32B2;}
+ .d2-1919566525 .fill-B2{fill:#0D32B2;}
+ .d2-1919566525 .fill-B3{fill:#E3E9FD;}
+ .d2-1919566525 .fill-B4{fill:#E3E9FD;}
+ .d2-1919566525 .fill-B5{fill:#EDF0FD;}
+ .d2-1919566525 .fill-B6{fill:#F7F8FE;}
+ .d2-1919566525 .fill-AA2{fill:#4A6FF3;}
+ .d2-1919566525 .fill-AA4{fill:#EDF0FD;}
+ .d2-1919566525 .fill-AA5{fill:#F7F8FE;}
+ .d2-1919566525 .fill-AB4{fill:#EDF0FD;}
+ .d2-1919566525 .fill-AB5{fill:#F7F8FE;}
+ .d2-1919566525 .stroke-N1{stroke:#0A0F25;}
+ .d2-1919566525 .stroke-N2{stroke:#676C7E;}
+ .d2-1919566525 .stroke-N3{stroke:#9499AB;}
+ .d2-1919566525 .stroke-N4{stroke:#CFD2DD;}
+ .d2-1919566525 .stroke-N5{stroke:#DEE1EB;}
+ .d2-1919566525 .stroke-N6{stroke:#EEF1F8;}
+ .d2-1919566525 .stroke-N7{stroke:#FFFFFF;}
+ .d2-1919566525 .stroke-B1{stroke:#0D32B2;}
+ .d2-1919566525 .stroke-B2{stroke:#0D32B2;}
+ .d2-1919566525 .stroke-B3{stroke:#E3E9FD;}
+ .d2-1919566525 .stroke-B4{stroke:#E3E9FD;}
+ .d2-1919566525 .stroke-B5{stroke:#EDF0FD;}
+ .d2-1919566525 .stroke-B6{stroke:#F7F8FE;}
+ .d2-1919566525 .stroke-AA2{stroke:#4A6FF3;}
+ .d2-1919566525 .stroke-AA4{stroke:#EDF0FD;}
+ .d2-1919566525 .stroke-AA5{stroke:#F7F8FE;}
+ .d2-1919566525 .stroke-AB4{stroke:#EDF0FD;}
+ .d2-1919566525 .stroke-AB5{stroke:#F7F8FE;}
+ .d2-1919566525 .background-color-N1{background-color:#0A0F25;}
+ .d2-1919566525 .background-color-N2{background-color:#676C7E;}
+ .d2-1919566525 .background-color-N3{background-color:#9499AB;}
+ .d2-1919566525 .background-color-N4{background-color:#CFD2DD;}
+ .d2-1919566525 .background-color-N5{background-color:#DEE1EB;}
+ .d2-1919566525 .background-color-N6{background-color:#EEF1F8;}
+ .d2-1919566525 .background-color-N7{background-color:#FFFFFF;}
+ .d2-1919566525 .background-color-B1{background-color:#0D32B2;}
+ .d2-1919566525 .background-color-B2{background-color:#0D32B2;}
+ .d2-1919566525 .background-color-B3{background-color:#E3E9FD;}
+ .d2-1919566525 .background-color-B4{background-color:#E3E9FD;}
+ .d2-1919566525 .background-color-B5{background-color:#EDF0FD;}
+ .d2-1919566525 .background-color-B6{background-color:#F7F8FE;}
+ .d2-1919566525 .background-color-AA2{background-color:#4A6FF3;}
+ .d2-1919566525 .background-color-AA4{background-color:#EDF0FD;}
+ .d2-1919566525 .background-color-AA5{background-color:#F7F8FE;}
+ .d2-1919566525 .background-color-AB4{background-color:#EDF0FD;}
+ .d2-1919566525 .background-color-AB5{background-color:#F7F8FE;}
+ .d2-1919566525 .color-N1{color:#0A0F25;}
+ .d2-1919566525 .color-N2{color:#676C7E;}
+ .d2-1919566525 .color-N3{color:#9499AB;}
+ .d2-1919566525 .color-N4{color:#CFD2DD;}
+ .d2-1919566525 .color-N5{color:#DEE1EB;}
+ .d2-1919566525 .color-N6{color:#EEF1F8;}
+ .d2-1919566525 .color-N7{color:#FFFFFF;}
+ .d2-1919566525 .color-B1{color:#0D32B2;}
+ .d2-1919566525 .color-B2{color:#0D32B2;}
+ .d2-1919566525 .color-B3{color:#E3E9FD;}
+ .d2-1919566525 .color-B4{color:#E3E9FD;}
+ .d2-1919566525 .color-B5{color:#EDF0FD;}
+ .d2-1919566525 .color-B6{color:#F7F8FE;}
+ .d2-1919566525 .color-AA2{color:#4A6FF3;}
+ .d2-1919566525 .color-AA4{color:#EDF0FD;}
+ .d2-1919566525 .color-AA5{color:#F7F8FE;}
+ .d2-1919566525 .color-AB4{color:#EDF0FD;}
+ .d2-1919566525 .color-AB5{color:#F7F8FE;}.appendix text.text{fill:#0A0F25}.md{--color-fg-default:#0A0F25;--color-fg-muted:#676C7E;--color-fg-subtle:#9499AB;--color-canvas-default:#FFFFFF;--color-canvas-subtle:#EEF1F8;--color-border-default:#0D32B2;--color-border-muted:#0D32B2;--color-neutral-muted:#EEF1F8;--color-accent-fg:#0D32B2;--color-accent-emphasis:#0D32B2;--color-attention-subtle:#676C7E;--color-danger-fg:red;}.sketch-overlay-B1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B2{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-B3{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-B6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-AA4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AA5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB4{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-AB5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N1{fill:url(#streaks-darker);mix-blend-mode:lighten}.sketch-overlay-N2{fill:url(#streaks-dark);mix-blend-mode:overlay}.sketch-overlay-N3{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N4{fill:url(#streaks-normal);mix-blend-mode:color-burn}.sketch-overlay-N5{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N6{fill:url(#streaks-bright);mix-blend-mode:darken}.sketch-overlay-N7{fill:url(#streaks-bright);mix-blend-mode:darken}.light-code{display: block}.dark-code{display: none}]]>agdfbhec
+
\ No newline at end of file
diff --git a/e2etests/testdata/stable/dagre-container/dagre/board.exp.json b/e2etests/testdata/stable/dagre-container/dagre/board.exp.json
new file mode 100644
index 000000000..ff93ed8e0
--- /dev/null
+++ b/e2etests/testdata/stable/dagre-container/dagre/board.exp.json
@@ -0,0 +1,424 @@
+{
+ "name": "",
+ "isFolderOnly": false,
+ "fontFamily": "SourceSansPro",
+ "shapes": [
+ {
+ "id": "a",
+ "type": "rectangle",
+ "pos": {
+ "x": 0,
+ "y": 41
+ },
+ "width": 359,
+ "height": 125,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "B4",
+ "stroke": "B1",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "a",
+ "fontSize": 28,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 12,
+ "labelHeight": 36,
+ "labelPosition": "OUTSIDE_TOP_CENTER",
+ "zIndex": 0,
+ "level": 1
+ },
+ {
+ "id": "a.a",
+ "type": "rectangle",
+ "pos": {
+ "x": 40,
+ "y": 70
+ },
+ "width": 53,
+ "height": 66,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "B5",
+ "stroke": "B1",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "a",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 8,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 2
+ },
+ {
+ "id": "a.b",
+ "type": "rectangle",
+ "pos": {
+ "x": 153,
+ "y": 70
+ },
+ "width": 53,
+ "height": 66,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "B5",
+ "stroke": "B1",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "b",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 8,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 2
+ },
+ {
+ "id": "a.c",
+ "type": "rectangle",
+ "pos": {
+ "x": 266,
+ "y": 70
+ },
+ "width": 53,
+ "height": 66,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "B5",
+ "stroke": "B1",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "c",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 8,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 2
+ },
+ {
+ "id": "b",
+ "type": "rectangle",
+ "pos": {
+ "x": 0,
+ "y": 307
+ },
+ "width": 359,
+ "height": 125,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "B4",
+ "stroke": "B1",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "b",
+ "fontSize": 28,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 13,
+ "labelHeight": 36,
+ "labelPosition": "OUTSIDE_TOP_CENTER",
+ "zIndex": 0,
+ "level": 1
+ },
+ {
+ "id": "b.a",
+ "type": "rectangle",
+ "pos": {
+ "x": 40,
+ "y": 336
+ },
+ "width": 53,
+ "height": 66,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "B5",
+ "stroke": "B1",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "a",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 8,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 2
+ },
+ {
+ "id": "b.b",
+ "type": "rectangle",
+ "pos": {
+ "x": 153,
+ "y": 336
+ },
+ "width": 53,
+ "height": 66,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "B5",
+ "stroke": "B1",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "b",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 8,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 2
+ },
+ {
+ "id": "b.c",
+ "type": "rectangle",
+ "pos": {
+ "x": 266,
+ "y": 336
+ },
+ "width": 53,
+ "height": 66,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "B5",
+ "stroke": "B1",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "c",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 8,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 2
+ }
+ ],
+ "connections": [
+ {
+ "id": "(a -> b)[0]",
+ "src": "a",
+ "srcArrow": "none",
+ "dst": "b",
+ "dstArrow": "triangle",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "stroke": "B1",
+ "borderRadius": 10,
+ "label": "",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N2",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 0,
+ "labelHeight": 0,
+ "labelPosition": "",
+ "labelPercentage": 0,
+ "route": [
+ {
+ "x": 179.5,
+ "y": 166
+ },
+ {
+ "x": 179.5,
+ "y": 206
+ },
+ {
+ "x": 179.5,
+ "y": 226
+ },
+ {
+ "x": 179.5,
+ "y": 266
+ }
+ ],
+ "isCurve": true,
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 0
+ }
+ ],
+ "root": {
+ "id": "",
+ "type": "",
+ "pos": {
+ "x": 0,
+ "y": 0
+ },
+ "width": 0,
+ "height": 0,
+ "opacity": 0,
+ "strokeDash": 0,
+ "strokeWidth": 0,
+ "borderRadius": 0,
+ "fill": "N7",
+ "stroke": "",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "",
+ "fontSize": 0,
+ "fontFamily": "",
+ "language": "",
+ "color": "",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 0,
+ "labelHeight": 0,
+ "zIndex": 0,
+ "level": 0
+ }
+}
diff --git a/e2etests/testdata/stable/dagre-container/dagre/sketch.exp.svg b/e2etests/testdata/stable/dagre-container/dagre/sketch.exp.svg
new file mode 100644
index 000000000..1bae0098b
--- /dev/null
+++ b/e2etests/testdata/stable/dagre-container/dagre/sketch.exp.svg
@@ -0,0 +1,102 @@
+ababcabc
+
+
+
\ No newline at end of file
diff --git a/e2etests/testdata/stable/dagre-container/elk/board.exp.json b/e2etests/testdata/stable/dagre-container/elk/board.exp.json
new file mode 100644
index 000000000..09e17e037
--- /dev/null
+++ b/e2etests/testdata/stable/dagre-container/elk/board.exp.json
@@ -0,0 +1,415 @@
+{
+ "name": "",
+ "isFolderOnly": false,
+ "fontFamily": "SourceSansPro",
+ "shapes": [
+ {
+ "id": "a",
+ "type": "rectangle",
+ "pos": {
+ "x": 12,
+ "y": 12
+ },
+ "width": 299,
+ "height": 166,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "B4",
+ "stroke": "B1",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "a",
+ "fontSize": 28,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 12,
+ "labelHeight": 36,
+ "labelPosition": "INSIDE_TOP_CENTER",
+ "zIndex": 0,
+ "level": 1
+ },
+ {
+ "id": "a.a",
+ "type": "rectangle",
+ "pos": {
+ "x": 62,
+ "y": 62
+ },
+ "width": 53,
+ "height": 66,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "B5",
+ "stroke": "B1",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "a",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 8,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 2
+ },
+ {
+ "id": "a.b",
+ "type": "rectangle",
+ "pos": {
+ "x": 135,
+ "y": 62
+ },
+ "width": 53,
+ "height": 66,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "B5",
+ "stroke": "B1",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "b",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 8,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 2
+ },
+ {
+ "id": "a.c",
+ "type": "rectangle",
+ "pos": {
+ "x": 208,
+ "y": 62
+ },
+ "width": 53,
+ "height": 66,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "B5",
+ "stroke": "B1",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "c",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 8,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 2
+ },
+ {
+ "id": "b",
+ "type": "rectangle",
+ "pos": {
+ "x": 12,
+ "y": 248
+ },
+ "width": 299,
+ "height": 166,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "B4",
+ "stroke": "B1",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "b",
+ "fontSize": 28,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 13,
+ "labelHeight": 36,
+ "labelPosition": "INSIDE_TOP_CENTER",
+ "zIndex": 0,
+ "level": 1
+ },
+ {
+ "id": "b.a",
+ "type": "rectangle",
+ "pos": {
+ "x": 62,
+ "y": 298
+ },
+ "width": 53,
+ "height": 66,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "B5",
+ "stroke": "B1",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "a",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 8,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 2
+ },
+ {
+ "id": "b.b",
+ "type": "rectangle",
+ "pos": {
+ "x": 135,
+ "y": 298
+ },
+ "width": 53,
+ "height": 66,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "B5",
+ "stroke": "B1",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "b",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 8,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 2
+ },
+ {
+ "id": "b.c",
+ "type": "rectangle",
+ "pos": {
+ "x": 208,
+ "y": 298
+ },
+ "width": 53,
+ "height": 66,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "B5",
+ "stroke": "B1",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "c",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 8,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 2
+ }
+ ],
+ "connections": [
+ {
+ "id": "(a -> b)[0]",
+ "src": "a",
+ "srcArrow": "none",
+ "dst": "b",
+ "dstArrow": "triangle",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "stroke": "B1",
+ "borderRadius": 10,
+ "label": "",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N2",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 0,
+ "labelHeight": 0,
+ "labelPosition": "",
+ "labelPercentage": 0,
+ "route": [
+ {
+ "x": 161.5,
+ "y": 178
+ },
+ {
+ "x": 161.5,
+ "y": 248
+ }
+ ],
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 0
+ }
+ ],
+ "root": {
+ "id": "",
+ "type": "",
+ "pos": {
+ "x": 0,
+ "y": 0
+ },
+ "width": 0,
+ "height": 0,
+ "opacity": 0,
+ "strokeDash": 0,
+ "strokeWidth": 0,
+ "borderRadius": 0,
+ "fill": "N7",
+ "stroke": "",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "",
+ "fontSize": 0,
+ "fontFamily": "",
+ "language": "",
+ "color": "",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 0,
+ "labelHeight": 0,
+ "zIndex": 0,
+ "level": 0
+ }
+}
diff --git a/e2etests/testdata/stable/dagre-container/elk/sketch.exp.svg b/e2etests/testdata/stable/dagre-container/elk/sketch.exp.svg
new file mode 100644
index 000000000..899a5fac2
--- /dev/null
+++ b/e2etests/testdata/stable/dagre-container/elk/sketch.exp.svg
@@ -0,0 +1,102 @@
+ababcabc
+
+
+
\ No newline at end of file