diff --git a/ci/release/changelogs/next.md b/ci/release/changelogs/next.md
index da2797bf4..11102d489 100644
--- a/ci/release/changelogs/next.md
+++ b/ci/release/changelogs/next.md
@@ -17,6 +17,7 @@ Sketch mode's subtle hand-drawn texture adapts to background colors.
- CLI reports when a feature is incompatible with layout engine, instead of silently ignoring. [#845](https://github.com/terrastruct/d2/pull/845)
- `near` key set to direct parent or ancestor throws an appropriate error message. [#851](https://github.com/terrastruct/d2/pull/851)
- Dimensions and positions are able to be set from API. [#853](https://github.com/terrastruct/d2/pull/853)
+- Improves label legibility for dagre containers by stopping container edges early if they would run into the label. [#880](https://github.com/terrastruct/d2/pull/880)
#### Bugfixes ⛑️
diff --git a/d2layouts/d2dagrelayout/layout.go b/d2layouts/d2dagrelayout/layout.go
index d46da1e7c..a1b279d83 100644
--- a/d2layouts/d2dagrelayout/layout.go
+++ b/d2layouts/d2dagrelayout/layout.go
@@ -425,7 +425,36 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
// trace the edge to the specific shape's border
points[startIndex] = shape.TraceToShapeBorder(srcShape, start, points[startIndex+1])
- points[endIndex] = shape.TraceToShapeBorder(dstShape, end, points[endIndex-1])
+
+ // if an edge to a container runs into its label, stop the edge at the label instead
+ overlapsContainerLabel := false
+ if edge.Dst.IsContainer() && edge.Dst.Attributes.Label.Value != "" {
+ // assumes LabelPosition, LabelWidth, LabelHeight are all set if there is a label
+ labelWidth := float64(*edge.Dst.LabelWidth)
+ labelHeight := float64(*edge.Dst.LabelHeight)
+ labelTL := label.Position(*edge.Dst.LabelPosition).
+ GetPointOnBox(edge.Dst.Box, label.PADDING, labelWidth, labelHeight)
+
+ endingSegment := geo.Segment{Start: points[endIndex-1], End: points[endIndex]}
+ labelBox := geo.NewBox(labelTL, labelWidth, labelHeight)
+ // add left/right padding to box
+ labelBox.TopLeft.X -= label.PADDING
+ labelBox.Width += 2 * label.PADDING
+ if intersections := labelBox.Intersections(endingSegment); len(intersections) > 0 {
+ overlapsContainerLabel = true
+ // move ending segment to label intersection point
+ points[endIndex] = intersections[0]
+ endingSegment.End = intersections[0]
+ // if the segment becomes too short, just merge it with the previous segment
+ if endIndex-1 > 0 && endingSegment.Length() < MIN_SEGMENT_LEN {
+ points[endIndex-1] = points[endIndex]
+ endIndex--
+ }
+ }
+ }
+ if !overlapsContainerLabel {
+ points[endIndex] = shape.TraceToShapeBorder(dstShape, end, points[endIndex-1])
+ }
points = points[startIndex : endIndex+1]
// build a curved path from the dagre route
diff --git a/e2etests/testdata/regression/dagre_broken_arrowhead/dagre/board.exp.json b/e2etests/testdata/regression/dagre_broken_arrowhead/dagre/board.exp.json
index 46f9a77c0..1c875fbb8 100644
--- a/e2etests/testdata/regression/dagre_broken_arrowhead/dagre/board.exp.json
+++ b/e2etests/testdata/regression/dagre_broken_arrowhead/dagre/board.exp.json
@@ -333,11 +333,11 @@
},
{
"x": 179,
- "y": 326.4
+ "y": 248
},
{
"x": 179,
- "y": 356
+ "y": 320
}
],
"isCurve": true,
diff --git a/e2etests/testdata/regression/dagre_broken_arrowhead/dagre/sketch.exp.svg b/e2etests/testdata/regression/dagre_broken_arrowhead/dagre/sketch.exp.svg
index 09df89c52..7e1f2e0a4 100644
--- a/e2etests/testdata/regression/dagre_broken_arrowhead/dagre/sketch.exp.svg
+++ b/e2etests/testdata/regression/dagre_broken_arrowhead/dagre/sketch.exp.svg
@@ -51,7 +51,7 @@
svgEl.setAttribute("height", height * ratio - 16);
}
});
-]]>abc12d line 1line 2line 3line 4
+]]>abc12d line 1line 2line 3line 4
\ No newline at end of file
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 4a30d438f..09a8de6d8 100644
--- a/e2etests/testdata/regression/overlapping-edge-label/dagre/board.exp.json
+++ b/e2etests/testdata/regression/overlapping-edge-label/dagre/board.exp.json
@@ -545,11 +545,11 @@
},
{
"x": 217,
- "y": 246.9
+ "y": 238.7
},
{
"x": 217,
- "y": 328.5
+ "y": 287.5
}
],
"isCurve": true,
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 b6c7ee69f..a0bbd2cf2 100644
--- a/e2etests/testdata/regression/overlapping-edge-label/dagre/sketch.exp.svg
+++ b/e2etests/testdata/regression/overlapping-edge-label/dagre/sketch.exp.svg
@@ -51,10 +51,10 @@
svgEl.setAttribute("height", height * ratio - 16);
}
});
-]]>Kubernetesopensvck8s-master1k8s-master2k8s-master3k8s-worker1k8s-worker2k8s-worker3VM1VM2 keycloakheptapodharborvault
+]]>Kubernetesopensvck8s-master1k8s-master2k8s-master3k8s-worker1k8s-worker2k8s-worker3VM1VM2 keycloakheptapodharborvault
-
+
\ No newline at end of file
diff --git a/e2etests/testdata/stable/direction/dagre/board.exp.json b/e2etests/testdata/stable/direction/dagre/board.exp.json
index da7c82b71..9ebda9816 100644
--- a/e2etests/testdata/stable/direction/dagre/board.exp.json
+++ b/e2etests/testdata/stable/direction/dagre/board.exp.json
@@ -654,11 +654,11 @@
},
{
"x": 140.25,
- "y": 134.2
+ "y": 126
},
{
"x": 140.25,
- "y": 207
+ "y": 166
}
],
"isCurve": true,
@@ -837,11 +837,11 @@
},
{
"x": 97,
- "y": 369.7
+ "y": 362.5
},
{
"x": 97,
- "y": 438.5
+ "y": 402.5
}
],
"isCurve": true,
diff --git a/e2etests/testdata/stable/direction/dagre/sketch.exp.svg b/e2etests/testdata/stable/direction/dagre/sketch.exp.svg
index 51e859c8a..d71065442 100644
--- a/e2etests/testdata/stable/direction/dagre/sketch.exp.svg
+++ b/e2etests/testdata/stable/direction/dagre/sketch.exp.svg
@@ -44,7 +44,7 @@
svgEl.setAttribute("height", height * ratio - 16);
}
});
-]]>abcde12345abcde
+]]>abcde12345abcde
\ No newline at end of file
diff --git a/e2etests/testdata/todo/container_label_edge_adjustment/dagre/board.exp.json b/e2etests/testdata/todo/container_label_edge_adjustment/dagre/board.exp.json
new file mode 100644
index 000000000..b07c4e59e
--- /dev/null
+++ b/e2etests/testdata/todo/container_label_edge_adjustment/dagre/board.exp.json
@@ -0,0 +1,535 @@
+{
+ "name": "",
+ "fontFamily": "SourceSansPro",
+ "shapes": [
+ {
+ "id": "a",
+ "type": "rectangle",
+ "pos": {
+ "x": 14,
+ "y": 0
+ },
+ "width": 53,
+ "height": 66,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "B6",
+ "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": 1
+ },
+ {
+ "id": "b",
+ "type": "cloud",
+ "pos": {
+ "x": 0,
+ "y": 207
+ },
+ "width": 397,
+ "height": 125,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "N7",
+ "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 container label",
+ "fontSize": 28,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 195,
+ "labelHeight": 36,
+ "labelPosition": "OUTSIDE_TOP_CENTER",
+ "zIndex": 0,
+ "level": 1
+ },
+ {
+ "id": "b.c",
+ "type": "rectangle",
+ "pos": {
+ "x": 183,
+ "y": 236
+ },
+ "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": "d",
+ "type": "rectangle",
+ "pos": {
+ "x": 182,
+ "y": 432
+ },
+ "width": 54,
+ "height": 66,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "B6",
+ "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": "d",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 9,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 1
+ },
+ {
+ "id": "e",
+ "type": "rectangle",
+ "pos": {
+ "x": 127,
+ "y": 0
+ },
+ "width": 53,
+ "height": 66,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "B6",
+ "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": "e",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 8,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 1
+ },
+ {
+ "id": "f",
+ "type": "rectangle",
+ "pos": {
+ "x": 240,
+ "y": 0
+ },
+ "width": 51,
+ "height": 66,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "B6",
+ "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": "f",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 6,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 1
+ },
+ {
+ "id": "g",
+ "type": "rectangle",
+ "pos": {
+ "x": 351,
+ "y": 0
+ },
+ "width": 54,
+ "height": 66,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "B6",
+ "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": "g",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 9,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 1
+ }
+ ],
+ "connections": [
+ {
+ "id": "(a -> b.c)[0]",
+ "src": "a",
+ "srcArrow": "none",
+ "srcLabel": "",
+ "dst": "b.c",
+ "dstArrow": "filled-diamond",
+ "dstLabel": "",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 8,
+ "stroke": "B1",
+ "label": "",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N2",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 0,
+ "labelHeight": 0,
+ "labelPosition": "",
+ "labelPercentage": 0,
+ "route": [
+ {
+ "x": 40,
+ "y": 66
+ },
+ {
+ "x": 40,
+ "y": 106
+ },
+ {
+ "x": 68.5,
+ "y": 184.09704142011833
+ },
+ {
+ "x": 182.5,
+ "y": 256.4852071005917
+ }
+ ],
+ "isCurve": true,
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 0
+ },
+ {
+ "id": "(b.c -> d)[0]",
+ "src": "b.c",
+ "srcArrow": "none",
+ "srcLabel": "",
+ "dst": "d",
+ "dstArrow": "filled-diamond",
+ "dstLabel": "",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 8,
+ "stroke": "B1",
+ "label": "",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N2",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 0,
+ "labelHeight": 0,
+ "labelPosition": "",
+ "labelPercentage": 0,
+ "route": [
+ {
+ "x": 209,
+ "y": 302.5
+ },
+ {
+ "x": 209,
+ "y": 326.1
+ },
+ {
+ "x": 209,
+ "y": 392
+ },
+ {
+ "x": 209,
+ "y": 432
+ }
+ ],
+ "isCurve": true,
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 0
+ },
+ {
+ "id": "(e -> b.c)[0]",
+ "src": "e",
+ "srcArrow": "none",
+ "srcLabel": "",
+ "dst": "b.c",
+ "dstArrow": "filled-diamond",
+ "dstLabel": "",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 8,
+ "stroke": "B1",
+ "label": "",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N2",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 0,
+ "labelHeight": 0,
+ "labelPosition": "",
+ "labelPercentage": 0,
+ "route": [
+ {
+ "x": 153,
+ "y": 66
+ },
+ {
+ "x": 153,
+ "y": 106
+ },
+ {
+ "x": 159.8,
+ "y": 180.1
+ },
+ {
+ "x": 187,
+ "y": 236.5
+ }
+ ],
+ "isCurve": true,
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 0
+ },
+ {
+ "id": "(f -> b)[0]",
+ "src": "f",
+ "srcArrow": "none",
+ "srcLabel": "",
+ "dst": "b",
+ "dstArrow": "filled-diamond",
+ "dstLabel": "",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 8,
+ "stroke": "red",
+ "label": "",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N2",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 0,
+ "labelHeight": 0,
+ "labelPosition": "",
+ "labelPercentage": 0,
+ "route": [
+ {
+ "x": 265,
+ "y": 66
+ },
+ {
+ "x": 265,
+ "y": 106
+ },
+ {
+ "x": 265,
+ "y": 126
+ },
+ {
+ "x": 265,
+ "y": 166
+ }
+ ],
+ "isCurve": true,
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 0
+ },
+ {
+ "id": "(g -> b)[0]",
+ "src": "g",
+ "srcArrow": "none",
+ "srcLabel": "",
+ "dst": "b",
+ "dstArrow": "filled-diamond",
+ "dstLabel": "",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 8,
+ "stroke": "B1",
+ "label": "",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N2",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 0,
+ "labelHeight": 0,
+ "labelPosition": "",
+ "labelPercentage": 0,
+ "route": [
+ {
+ "x": 377.5,
+ "y": 66
+ },
+ {
+ "x": 377.5,
+ "y": 106
+ },
+ {
+ "x": 377.6,
+ "y": 145.2
+ },
+ {
+ "x": 378,
+ "y": 262
+ }
+ ],
+ "isCurve": true,
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 0
+ }
+ ]
+}
diff --git a/e2etests/testdata/todo/container_label_edge_adjustment/dagre/sketch.exp.svg b/e2etests/testdata/todo/container_label_edge_adjustment/dagre/sketch.exp.svg
new file mode 100644
index 000000000..eef6f80c8
--- /dev/null
+++ b/e2etests/testdata/todo/container_label_edge_adjustment/dagre/sketch.exp.svg
@@ -0,0 +1,50 @@
+
\ No newline at end of file
diff --git a/e2etests/testdata/todo/container_label_edge_adjustment/elk/board.exp.json b/e2etests/testdata/todo/container_label_edge_adjustment/elk/board.exp.json
new file mode 100644
index 000000000..c124141e8
--- /dev/null
+++ b/e2etests/testdata/todo/container_label_edge_adjustment/elk/board.exp.json
@@ -0,0 +1,514 @@
+{
+ "name": "",
+ "fontFamily": "SourceSansPro",
+ "shapes": [
+ {
+ "id": "a",
+ "type": "rectangle",
+ "pos": {
+ "x": 12,
+ "y": 12
+ },
+ "width": 53,
+ "height": 66,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "B6",
+ "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": 1
+ },
+ {
+ "id": "b",
+ "type": "cloud",
+ "pos": {
+ "x": 26,
+ "y": 213
+ },
+ "width": 155,
+ "height": 166,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "N7",
+ "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 container label",
+ "fontSize": 28,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 195,
+ "labelHeight": 36,
+ "labelPosition": "INSIDE_TOP_CENTER",
+ "zIndex": 0,
+ "level": 1
+ },
+ {
+ "id": "b.c",
+ "type": "rectangle",
+ "pos": {
+ "x": 76,
+ "y": 263
+ },
+ "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": "d",
+ "type": "rectangle",
+ "pos": {
+ "x": 75,
+ "y": 454
+ },
+ "width": 54,
+ "height": 66,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "B6",
+ "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": "d",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 9,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 1
+ },
+ {
+ "id": "e",
+ "type": "rectangle",
+ "pos": {
+ "x": 85,
+ "y": 12
+ },
+ "width": 53,
+ "height": 66,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "B6",
+ "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": "e",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 8,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 1
+ },
+ {
+ "id": "f",
+ "type": "rectangle",
+ "pos": {
+ "x": 158,
+ "y": 12
+ },
+ "width": 51,
+ "height": 66,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "B6",
+ "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": "f",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 6,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 1
+ },
+ {
+ "id": "g",
+ "type": "rectangle",
+ "pos": {
+ "x": 229,
+ "y": 12
+ },
+ "width": 54,
+ "height": 66,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "B6",
+ "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": "g",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 9,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 1
+ }
+ ],
+ "connections": [
+ {
+ "id": "(a -> b.c)[0]",
+ "src": "a",
+ "srcArrow": "none",
+ "srcLabel": "",
+ "dst": "b.c",
+ "dstArrow": "filled-diamond",
+ "dstLabel": "",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 8,
+ "stroke": "B1",
+ "label": "",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N2",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 0,
+ "labelHeight": 0,
+ "labelPosition": "",
+ "labelPercentage": 0,
+ "route": [
+ {
+ "x": 38.5,
+ "y": 78
+ },
+ {
+ "x": 38.5,
+ "y": 118
+ },
+ {
+ "x": 93.83333333333333,
+ "y": 118
+ },
+ {
+ "x": 93.83333333333333,
+ "y": 263
+ }
+ ],
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 0
+ },
+ {
+ "id": "(b.c -> d)[0]",
+ "src": "b.c",
+ "srcArrow": "none",
+ "srcLabel": "",
+ "dst": "d",
+ "dstArrow": "filled-diamond",
+ "dstLabel": "",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 8,
+ "stroke": "B1",
+ "label": "",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N2",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 0,
+ "labelHeight": 0,
+ "labelPosition": "",
+ "labelPercentage": 0,
+ "route": [
+ {
+ "x": 102.66666666666666,
+ "y": 329
+ },
+ {
+ "x": 102.66666666666666,
+ "y": 454
+ }
+ ],
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 0
+ },
+ {
+ "id": "(e -> b.c)[0]",
+ "src": "e",
+ "srcArrow": "none",
+ "srcLabel": "",
+ "dst": "b.c",
+ "dstArrow": "filled-diamond",
+ "dstLabel": "",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 8,
+ "stroke": "B1",
+ "label": "",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N2",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 0,
+ "labelHeight": 0,
+ "labelPosition": "",
+ "labelPercentage": 0,
+ "route": [
+ {
+ "x": 111.5,
+ "y": 78
+ },
+ {
+ "x": 111.5,
+ "y": 263
+ }
+ ],
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 0
+ },
+ {
+ "id": "(f -> b)[0]",
+ "src": "f",
+ "srcArrow": "none",
+ "srcLabel": "",
+ "dst": "b",
+ "dstArrow": "filled-diamond",
+ "dstLabel": "",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 8,
+ "stroke": "red",
+ "label": "",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N2",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 0,
+ "labelHeight": 0,
+ "labelPosition": "",
+ "labelPercentage": 0,
+ "route": [
+ {
+ "x": 183.5,
+ "y": 78
+ },
+ {
+ "x": 183.5,
+ "y": 118
+ },
+ {
+ "x": 121.5,
+ "y": 118
+ },
+ {
+ "x": 122,
+ "y": 213
+ }
+ ],
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 0
+ },
+ {
+ "id": "(g -> b)[0]",
+ "src": "g",
+ "srcArrow": "none",
+ "srcLabel": "",
+ "dst": "b",
+ "dstArrow": "filled-diamond",
+ "dstLabel": "",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 8,
+ "stroke": "B1",
+ "label": "",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N2",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 0,
+ "labelHeight": 0,
+ "labelPosition": "",
+ "labelPercentage": 0,
+ "route": [
+ {
+ "x": 256,
+ "y": 78
+ },
+ {
+ "x": 256,
+ "y": 168
+ },
+ {
+ "x": 131.5,
+ "y": 168
+ },
+ {
+ "x": 131,
+ "y": 218
+ }
+ ],
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 0
+ }
+ ]
+}
diff --git a/e2etests/testdata/todo/container_label_edge_adjustment/elk/sketch.exp.svg b/e2etests/testdata/todo/container_label_edge_adjustment/elk/sketch.exp.svg
new file mode 100644
index 000000000..934011400
--- /dev/null
+++ b/e2etests/testdata/todo/container_label_edge_adjustment/elk/sketch.exp.svg
@@ -0,0 +1,50 @@
+
\ No newline at end of file
diff --git a/e2etests/testdata/todo/container_label_edge_adjustment2/dagre/board.exp.json b/e2etests/testdata/todo/container_label_edge_adjustment2/dagre/board.exp.json
new file mode 100644
index 000000000..d4f3880c9
--- /dev/null
+++ b/e2etests/testdata/todo/container_label_edge_adjustment2/dagre/board.exp.json
@@ -0,0 +1,179 @@
+{
+ "name": "",
+ "fontFamily": "SourceSansPro",
+ "shapes": [
+ {
+ "id": "x",
+ "type": "rectangle",
+ "pos": {
+ "x": 40,
+ "y": 0
+ },
+ "width": 53,
+ "height": 66,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "B6",
+ "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": "x",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 8,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 1
+ },
+ {
+ "id": "y",
+ "type": "rectangle",
+ "pos": {
+ "x": 0,
+ "y": 207
+ },
+ "width": 132,
+ "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": "bar",
+ "fontSize": 28,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 38,
+ "labelHeight": 36,
+ "labelPosition": "OUTSIDE_TOP_CENTER",
+ "zIndex": 0,
+ "level": 1
+ },
+ {
+ "id": "y.z",
+ "type": "rectangle",
+ "pos": {
+ "x": 40,
+ "y": 236
+ },
+ "width": 52,
+ "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": "z",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 7,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 2
+ }
+ ],
+ "connections": [
+ {
+ "id": "(x -> y)[0]",
+ "src": "x",
+ "srcArrow": "none",
+ "srcLabel": "",
+ "dst": "y",
+ "dstArrow": "filled-diamond",
+ "dstLabel": "foo",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "stroke": "B1",
+ "label": "",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N2",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 0,
+ "labelHeight": 0,
+ "labelPosition": "",
+ "labelPercentage": 0,
+ "route": [
+ {
+ "x": 66,
+ "y": 66
+ },
+ {
+ "x": 66,
+ "y": 106
+ },
+ {
+ "x": 66,
+ "y": 126
+ },
+ {
+ "x": 66,
+ "y": 166
+ }
+ ],
+ "isCurve": true,
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 0
+ }
+ ]
+}
diff --git a/e2etests/testdata/todo/container_label_edge_adjustment2/dagre/sketch.exp.svg b/e2etests/testdata/todo/container_label_edge_adjustment2/dagre/sketch.exp.svg
new file mode 100644
index 000000000..76828dacf
--- /dev/null
+++ b/e2etests/testdata/todo/container_label_edge_adjustment2/dagre/sketch.exp.svg
@@ -0,0 +1,57 @@
+
\ No newline at end of file
diff --git a/e2etests/testdata/todo/container_label_edge_adjustment2/elk/board.exp.json b/e2etests/testdata/todo/container_label_edge_adjustment2/elk/board.exp.json
new file mode 100644
index 000000000..219d55620
--- /dev/null
+++ b/e2etests/testdata/todo/container_label_edge_adjustment2/elk/board.exp.json
@@ -0,0 +1,170 @@
+{
+ "name": "",
+ "fontFamily": "SourceSansPro",
+ "shapes": [
+ {
+ "id": "x",
+ "type": "rectangle",
+ "pos": {
+ "x": 61,
+ "y": 12
+ },
+ "width": 53,
+ "height": 66,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "B6",
+ "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": "x",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 8,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 1
+ },
+ {
+ "id": "y",
+ "type": "rectangle",
+ "pos": {
+ "x": 12,
+ "y": 148
+ },
+ "width": 152,
+ "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": "bar",
+ "fontSize": 28,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 38,
+ "labelHeight": 36,
+ "labelPosition": "INSIDE_TOP_CENTER",
+ "zIndex": 0,
+ "level": 1
+ },
+ {
+ "id": "y.z",
+ "type": "rectangle",
+ "pos": {
+ "x": 62,
+ "y": 198
+ },
+ "width": 52,
+ "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": "z",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N1",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 7,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 2
+ }
+ ],
+ "connections": [
+ {
+ "id": "(x -> y)[0]",
+ "src": "x",
+ "srcArrow": "none",
+ "srcLabel": "",
+ "dst": "y",
+ "dstArrow": "filled-diamond",
+ "dstLabel": "foo",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "stroke": "B1",
+ "label": "",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "N2",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 0,
+ "labelHeight": 0,
+ "labelPosition": "",
+ "labelPercentage": 0,
+ "route": [
+ {
+ "x": 88,
+ "y": 78
+ },
+ {
+ "x": 88,
+ "y": 148
+ }
+ ],
+ "animated": false,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 0
+ }
+ ]
+}
diff --git a/e2etests/testdata/todo/container_label_edge_adjustment2/elk/sketch.exp.svg b/e2etests/testdata/todo/container_label_edge_adjustment2/elk/sketch.exp.svg
new file mode 100644
index 000000000..af97bacba
--- /dev/null
+++ b/e2etests/testdata/todo/container_label_edge_adjustment2/elk/sketch.exp.svg
@@ -0,0 +1,57 @@
+
\ No newline at end of file
diff --git a/e2etests/todo_test.go b/e2etests/todo_test.go
index 17903edbd..24b52e03d 100644
--- a/e2etests/todo_test.go
+++ b/e2etests/todo_test.go
@@ -220,6 +220,37 @@ Office chatter: {
a
}
}
+`,
+ },
+ {
+ name: "container_label_edge_adjustment",
+ script: `
+a -> b.c -> d: {style.stroke-width: 8; target-arrowhead.shape: diamond; target-arrowhead.style.filled: true}
+b.shape: cloud
+e -> b.c: {style.stroke-width: 8; target-arrowhead.shape: diamond; target-arrowhead.style.filled: true}
+f -> b: {
+ style: {
+ stroke: red
+ stroke-width: 8
+ }
+ target-arrowhead.shape: diamond
+ target-arrowhead.style.filled: true
+}
+g -> b: {style.stroke-width: 8; target-arrowhead.shape: diamond; target-arrowhead.style.filled: true}
+b: a container label
+`,
+ },
+ {
+ name: "container_label_edge_adjustment2",
+ script: `
+x -> y: {
+ target-arrowhead: foo {
+ shape: diamond
+ style.filled: true
+ }
+}
+
+y: bar {z}
`,
},
}