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 @@ + +VPC 1 10.1.0.0./16Availability Zone AFirewall Subnet A + + + \ 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">