diff --git a/d2layouts/d2dagrelayout/layout.go b/d2layouts/d2dagrelayout/layout.go
index a3d943200..f04d26a57 100644
--- a/d2layouts/d2dagrelayout/layout.go
+++ b/d2layouts/d2dagrelayout/layout.go
@@ -115,6 +115,11 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
if obj.LabelHeight != nil {
maxContainerLabelHeight = go2.Max(maxContainerLabelHeight, *obj.LabelHeight+label.PADDING)
}
+
+ if obj.Attributes.Icon != nil {
+ iconSize := d2target.GetIconSize(obj.Box, string(label.InsideTopLeft))
+ maxContainerLabelHeight = go2.Max(maxContainerLabelHeight, iconSize+label.PADDING)
+ }
}
maxLabelSize := 0
@@ -219,7 +224,11 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
}
}
if obj.Attributes.Icon != nil {
- obj.IconPosition = go2.Pointer(string(label.InsideMiddleCenter))
+ if len(obj.ChildrenArray) > 0 {
+ obj.IconPosition = go2.Pointer(string(label.InsideTopLeft))
+ } else {
+ obj.IconPosition = go2.Pointer(string(label.InsideMiddleCenter))
+ }
}
}
diff --git a/d2layouts/d2elklayout/layout.go b/d2layouts/d2elklayout/layout.go
index 886d3424a..d42f82d24 100644
--- a/d2layouts/d2elklayout/layout.go
+++ b/d2layouts/d2elklayout/layout.go
@@ -186,6 +186,7 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
}
if len(obj.ChildrenArray) > 0 {
+
n.LayoutOptions = &elkOpts{
ForceNodeModelOrder: true,
Thoroughness: 8,
@@ -199,6 +200,21 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
Padding: opts.Padding,
},
}
+
+ if n.LayoutOptions.Padding == DefaultOpts.Padding {
+ // Default
+ paddingTop := 50
+ if obj.LabelHeight != nil {
+ paddingTop = go2.Max(paddingTop, *obj.LabelHeight+label.PADDING)
+ }
+ if obj.Attributes.Icon != nil {
+ iconSize := d2target.GetIconSize(obj.Box, string(label.InsideTopLeft))
+ paddingTop = go2.Max(paddingTop, iconSize+label.PADDING)
+ }
+ n.LayoutOptions.Padding = fmt.Sprintf("[top=%d,left=50,bottom=50,right=50]",
+ paddingTop,
+ )
+ }
}
if obj.LabelWidth != nil && obj.LabelHeight != nil {
@@ -310,7 +326,11 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err
}
}
if obj.Attributes.Icon != nil {
- obj.IconPosition = go2.Pointer(string(label.InsideMiddleCenter))
+ if len(obj.ChildrenArray) > 0 {
+ obj.IconPosition = go2.Pointer(string(label.InsideTopLeft))
+ } else {
+ obj.IconPosition = go2.Pointer(string(label.InsideMiddleCenter))
+ }
}
byID[obj.AbsID()] = obj
diff --git a/d2renderers/d2svg/d2svg.go b/d2renderers/d2svg/d2svg.go
index 25c5dd88e..0b5192b7c 100644
--- a/d2renderers/d2svg/d2svg.go
+++ b/d2renderers/d2svg/d2svg.go
@@ -883,7 +883,7 @@ func drawShape(writer io.Writer, targetShape d2target.Shape, sketchRunner *d2ske
} else {
box = s.GetInnerBox()
}
- iconSize := targetShape.GetIconSize(box)
+ iconSize := d2target.GetIconSize(box, targetShape.IconPosition)
tl := iconPosition.GetPointOnBox(box, label.PADDING, float64(iconSize), float64(iconSize))
diff --git a/d2target/d2target.go b/d2target/d2target.go
index e5cf20cdb..20207c121 100644
--- a/d2target/d2target.go
+++ b/d2target/d2target.go
@@ -538,8 +538,8 @@ func init() {
}
}
-func (s *Shape) GetIconSize(box *geo.Box) int {
- iconPosition := label.Position(s.IconPosition)
+func GetIconSize(box *geo.Box, position string) int {
+ iconPosition := label.Position(position)
minDimension := int(math.Min(box.Width, box.Height))
halfMinDimension := int(math.Ceil(0.5 * float64(minDimension)))
diff --git a/e2etests/stable_test.go b/e2etests/stable_test.go
index bca51d2e7..cf1b25ea6 100644
--- a/e2etests/stable_test.go
+++ b/e2etests/stable_test.go
@@ -895,6 +895,31 @@ b: {
icon: https://icons.terrastruct.com/essentials/004-picture.svg
}
a -> b
+`,
+ },
+ {
+ name: "icon-containers",
+ script: `vpc: VPC 1 10.1.0.0./16 {
+ icon: https://icons.terrastruct.com/aws%2FNetworking%20&%20Content%20Delivery%2FAmazon-VPC.svg
+ style: {
+ stroke: green
+ font-color: green
+ }
+ az: Availability Zone A {
+ style: {
+ stroke: blue
+ font-color: blue
+ stroke-dash: 3
+ }
+ firewall: Firewall Subnet A {
+ icon: https://icons.terrastruct.com/aws%2FNetworking%20&%20Content%20Delivery%2FAmazon-Route-53_Hosted-Zone_light-bg.svg
+ style: {
+ stroke: purple
+ font-color: purple
+ }
+ }
+ }
+}
`,
},
{
diff --git a/e2etests/testdata/stable/font_sizes_containers_large/elk/board.exp.json b/e2etests/testdata/stable/font_sizes_containers_large/elk/board.exp.json
index 99a69e14e..d2f308a09 100644
--- a/e2etests/testdata/stable/font_sizes_containers_large/elk/board.exp.json
+++ b/e2etests/testdata/stable/font_sizes_containers_large/elk/board.exp.json
@@ -10,7 +10,7 @@
"y": 12
},
"width": 464,
- "height": 456,
+ "height": 572,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
@@ -48,10 +48,10 @@
"type": "rectangle",
"pos": {
"x": 62,
- "y": 62
+ "y": 142
},
"width": 364,
- "height": 356,
+ "height": 392,
"opacity": 1,
"strokeDash": 0,
"strokeWidth": 2,
@@ -89,7 +89,7 @@
"type": "rectangle",
"pos": {
"x": 112,
- "y": 112
+ "y": 228
},
"width": 264,
"height": 256,
@@ -130,7 +130,7 @@
"type": "rectangle",
"pos": {
"x": 162,
- "y": 162
+ "y": 278
},
"width": 164,
"height": 156,
@@ -171,7 +171,7 @@
"type": "rectangle",
"pos": {
"x": 212,
- "y": 212
+ "y": 328
},
"width": 64,
"height": 56,
diff --git a/e2etests/testdata/stable/font_sizes_containers_large/elk/sketch.exp.svg b/e2etests/testdata/stable/font_sizes_containers_large/elk/sketch.exp.svg
index b26de5af0..13fb0bb7d 100644
--- a/e2etests/testdata/stable/font_sizes_containers_large/elk/sketch.exp.svg
+++ b/e2etests/testdata/stable/font_sizes_containers_large/elk/sketch.exp.svg
@@ -3,7 +3,7 @@
id="d2-svg"
style="background: white;"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
-width="668" height="660" viewBox="-90 -90 668 660">VPC 1 10.1.0.0./16Availability Zone AFirewall Subnet A
+
+
+
\ No newline at end of file
diff --git a/e2etests/testdata/stable/icon-containers/elk/board.exp.json b/e2etests/testdata/stable/icon-containers/elk/board.exp.json
new file mode 100644
index 000000000..1bd4989d1
--- /dev/null
+++ b/e2etests/testdata/stable/icon-containers/elk/board.exp.json
@@ -0,0 +1,152 @@
+{
+ "name": "",
+ "fontFamily": "SourceSansPro",
+ "shapes": [
+ {
+ "id": "vpc",
+ "type": "rectangle",
+ "pos": {
+ "x": 12,
+ "y": 12
+ },
+ "width": 395,
+ "height": 334,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "#E3E9FD",
+ "stroke": "green",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": {
+ "Scheme": "https",
+ "Opaque": "",
+ "User": null,
+ "Host": "icons.terrastruct.com",
+ "Path": "/aws/Networking & Content Delivery/Amazon-VPC.svg",
+ "RawPath": "/aws%2FNetworking%20&%20Content%20Delivery%2FAmazon-VPC.svg",
+ "ForceQuery": false,
+ "RawQuery": "",
+ "Fragment": "",
+ "RawFragment": ""
+ },
+ "iconPosition": "INSIDE_TOP_LEFT",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "VPC 1 10.1.0.0./16",
+ "fontSize": 28,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "green",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 206,
+ "labelHeight": 36,
+ "labelPosition": "INSIDE_TOP_CENTER",
+ "zIndex": 0,
+ "level": 1
+ },
+ {
+ "id": "vpc.az",
+ "type": "rectangle",
+ "pos": {
+ "x": 62,
+ "y": 78
+ },
+ "width": 295,
+ "height": 218,
+ "opacity": 1,
+ "strokeDash": 3,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "#EDF0FD",
+ "stroke": "blue",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "Availability Zone A",
+ "fontSize": 24,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "blue",
+ "italic": false,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 185,
+ "labelHeight": 31,
+ "labelPosition": "INSIDE_TOP_CENTER",
+ "zIndex": 0,
+ "level": 2
+ },
+ {
+ "id": "vpc.az.firewall",
+ "type": "rectangle",
+ "pos": {
+ "x": 112,
+ "y": 128
+ },
+ "width": 195,
+ "height": 118,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "#F7F8FE",
+ "stroke": "purple",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "double-border": false,
+ "tooltip": "",
+ "link": "",
+ "icon": {
+ "Scheme": "https",
+ "Opaque": "",
+ "User": null,
+ "Host": "icons.terrastruct.com",
+ "Path": "/aws/Networking & Content Delivery/Amazon-Route-53_Hosted-Zone_light-bg.svg",
+ "RawPath": "/aws%2FNetworking%20&%20Content%20Delivery%2FAmazon-Route-53_Hosted-Zone_light-bg.svg",
+ "ForceQuery": false,
+ "RawQuery": "",
+ "Fragment": "",
+ "RawFragment": ""
+ },
+ "iconPosition": "INSIDE_MIDDLE_CENTER",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "Firewall Subnet A",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "purple",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 124,
+ "labelHeight": 21,
+ "labelPosition": "INSIDE_TOP_CENTER",
+ "zIndex": 0,
+ "level": 3
+ }
+ ],
+ "connections": []
+}
diff --git a/e2etests/testdata/stable/icon-containers/elk/sketch.exp.svg b/e2etests/testdata/stable/icon-containers/elk/sketch.exp.svg
new file mode 100644
index 000000000..041aa82c1
--- /dev/null
+++ b/e2etests/testdata/stable/icon-containers/elk/sketch.exp.svg
@@ -0,0 +1,59 @@
+
+
\ No newline at end of file
diff --git a/e2etests/testdata/todo/container_icon_label/dagre/board.exp.json b/e2etests/testdata/todo/container_icon_label/dagre/board.exp.json
index 46d342706..542f6cbae 100644
--- a/e2etests/testdata/todo/container_icon_label/dagre/board.exp.json
+++ b/e2etests/testdata/todo/container_icon_label/dagre/board.exp.json
@@ -35,7 +35,7 @@
"Fragment": "",
"RawFragment": ""
},
- "iconPosition": "INSIDE_MIDDLE_CENTER",
+ "iconPosition": "INSIDE_TOP_LEFT",
"blend": false,
"fields": null,
"methods": null,
diff --git a/e2etests/testdata/todo/container_icon_label/dagre/sketch.exp.svg b/e2etests/testdata/todo/container_icon_label/dagre/sketch.exp.svg
index a515d2ca5..8dc30a6d4 100644
--- a/e2etests/testdata/todo/container_icon_label/dagre/sketch.exp.svg
+++ b/e2etests/testdata/todo/container_icon_label/dagre/sketch.exp.svg
@@ -39,7 +39,7 @@ width="377" height="800" viewBox="-102 -100 377 800">