diff --git a/d2graph/d2graph.go b/d2graph/d2graph.go index 8379d184b2..df9d12a9a0 100644 --- a/d2graph/d2graph.go +++ b/d2graph/d2graph.go @@ -57,6 +57,9 @@ type Graph struct { Steps []*Graph `json:"steps,omitempty"` Theme *d2themes.Theme `json:"theme,omitempty"` + + // Object.Level uses the location of a nested graph + RootLevel int `json:"rootLevel,omitempty"` } func NewGraph() *Graph { @@ -529,7 +532,7 @@ func (obj *Object) GetStroke(dashGapSize interface{}) string { func (obj *Object) Level() ContainerLevel { if obj.Parent == nil { - return 0 + return ContainerLevel(obj.Graph.RootLevel) } return 1 + obj.Parent.Level() } diff --git a/d2graph/layout.go b/d2graph/layout.go index 4d50efc1d7..51b3206b99 100644 --- a/d2graph/layout.go +++ b/d2graph/layout.go @@ -41,6 +41,7 @@ func (g *Graph) ExtractAsNestedGraph(obj *Object) *Graph { descendantObjects, edges := pluckObjAndEdges(g, obj) tempGraph := NewGraph() + tempGraph.RootLevel = int(obj.Level()) - 1 tempGraph.Root.ChildrenArray = []*Object{obj} tempGraph.Root.Children[strings.ToLower(obj.ID)] = obj diff --git a/e2etests/regression_test.go b/e2etests/regression_test.go index 24a0d0edd1..f1d20808f4 100644 --- a/e2etests/regression_test.go +++ b/e2etests/regression_test.go @@ -1037,6 +1037,7 @@ cf many required: { loadFromFile(t, "grid_with_latex"), loadFromFile(t, "icons_on_top"), loadFromFile(t, "dagre_disconnected_edge"), + loadFromFile(t, "outside_grid_label_position"), } runa(t, tcs) diff --git a/e2etests/testdata/files/outside_grid_label_position.d2 b/e2etests/testdata/files/outside_grid_label_position.d2 new file mode 100644 index 0000000000..7394f81aa9 --- /dev/null +++ b/e2etests/testdata/files/outside_grid_label_position.d2 @@ -0,0 +1,23 @@ +container1: { + container2: { + container3: { + grid-rows: 1 + + first: { + label.near: outside-top-center + child: { + label.near: outside-bottom-center + } + } + second: { + label.near: outside-top-center + child: { + label.near: outside-bottom-center + } + } + third: { + label.near: outside-top-center + } + } + } +} diff --git a/e2etests/testdata/files/outside_grid_label_position.svg b/e2etests/testdata/files/outside_grid_label_position.svg new file mode 100644 index 0000000000..a3add516fd --- /dev/null +++ b/e2etests/testdata/files/outside_grid_label_position.svg @@ -0,0 +1,108 @@ +nat1Availability Zone 5Master SubnetNode SubnetPod Subnet10.68.8.0/2310.68.12.0/23 + + + + + + + + +UNLICENSED COPY diff --git a/e2etests/testdata/regression/outside_grid_label_position/dagre/board.exp.json b/e2etests/testdata/regression/outside_grid_label_position/dagre/board.exp.json new file mode 100644 index 0000000000..e4d63f30e2 --- /dev/null +++ b/e2etests/testdata/regression/outside_grid_label_position/dagre/board.exp.json @@ -0,0 +1,376 @@ +{ + "name": "", + "isFolderOnly": false, + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "container1", + "type": "rectangle", + "pos": { + "x": 0, + "y": 29 + }, + "width": 681, + "height": 390, + "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": "container1", + "fontSize": 28, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 125, + "labelHeight": 36, + "labelPosition": "OUTSIDE_TOP_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "container1.container2", + "type": "rectangle", + "pos": { + "x": 30, + "y": 70 + }, + "width": 621, + "height": 319, + "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": "container2", + "fontSize": 24, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 107, + "labelHeight": 31, + "labelPosition": "OUTSIDE_TOP_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "container1.container2.container3", + "type": "rectangle", + "pos": { + "x": 60, + "y": 100 + }, + "width": 561, + "height": 259, + "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": "container3", + "fontSize": 20, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 90, + "labelHeight": 26, + "labelPosition": "INSIDE_TOP_CENTER", + "zIndex": 0, + "level": 3 + }, + { + "id": "container1.container2.container3.first", + "type": "rectangle", + "pos": { + "x": 120, + "y": 172 + }, + "width": 140, + "height": 127, + "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": "first", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 27, + "labelHeight": 21, + "labelPosition": "OUTSIDE_TOP_CENTER", + "zIndex": 0, + "level": 4 + }, + { + "id": "container1.container2.container3.first.child", + "type": "rectangle", + "pos": { + "x": 150, + "y": 202 + }, + "width": 80, + "height": 66, + "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": "child", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 35, + "labelHeight": 21, + "labelPosition": "OUTSIDE_BOTTOM_CENTER", + "zIndex": 0, + "level": 5 + }, + { + "id": "container1.container2.container3.second", + "type": "rectangle", + "pos": { + "x": 300, + "y": 172 + }, + "width": 140, + "height": 127, + "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": "second", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 48, + "labelHeight": 21, + "labelPosition": "OUTSIDE_TOP_CENTER", + "zIndex": 0, + "level": 4 + }, + { + "id": "container1.container2.container3.second.child", + "type": "rectangle", + "pos": { + "x": 330, + "y": 202 + }, + "width": 80, + "height": 66, + "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": "child", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 35, + "labelHeight": 21, + "labelPosition": "OUTSIDE_BOTTOM_CENTER", + "zIndex": 0, + "level": 5 + }, + { + "id": "container1.container2.container3.third", + "type": "rectangle", + "pos": { + "x": 480, + "y": 172 + }, + "width": 81, + "height": 127, + "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": "third", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 36, + "labelHeight": 21, + "labelPosition": "OUTSIDE_TOP_CENTER", + "zIndex": 0, + "level": 4 + } + ], + "connections": [], + "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/regression/outside_grid_label_position/dagre/sketch.exp.svg b/e2etests/testdata/regression/outside_grid_label_position/dagre/sketch.exp.svg new file mode 100644 index 0000000000..dbdf014d91 --- /dev/null +++ b/e2etests/testdata/regression/outside_grid_label_position/dagre/sketch.exp.svg @@ -0,0 +1,109 @@ +container1container2container3firstsecondthirdchildchild + + + + + + + + + + \ No newline at end of file diff --git a/e2etests/testdata/regression/outside_grid_label_position/elk/board.exp.json b/e2etests/testdata/regression/outside_grid_label_position/elk/board.exp.json new file mode 100644 index 0000000000..26f38abc96 --- /dev/null +++ b/e2etests/testdata/regression/outside_grid_label_position/elk/board.exp.json @@ -0,0 +1,376 @@ +{ + "name": "", + "isFolderOnly": false, + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "container1", + "type": "rectangle", + "pos": { + "x": 12, + "y": 12 + }, + "width": 841, + "height": 498, + "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": "container1", + "fontSize": 28, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 125, + "labelHeight": 36, + "labelPosition": "INSIDE_TOP_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "container1.container2", + "type": "rectangle", + "pos": { + "x": 62, + "y": 62 + }, + "width": 741, + "height": 398, + "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": "container2", + "fontSize": 24, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 107, + "labelHeight": 31, + "labelPosition": "INSIDE_TOP_CENTER", + "zIndex": 0, + "level": 2 + }, + { + "id": "container1.container2.container3", + "type": "rectangle", + "pos": { + "x": 112, + "y": 112 + }, + "width": 641, + "height": 298, + "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": "container3", + "fontSize": 20, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 90, + "labelHeight": 26, + "labelPosition": "INSIDE_TOP_CENTER", + "zIndex": 0, + "level": 3 + }, + { + "id": "container1.container2.container3.first", + "type": "rectangle", + "pos": { + "x": 172, + "y": 184 + }, + "width": 180, + "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": "first", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 27, + "labelHeight": 21, + "labelPosition": "OUTSIDE_TOP_CENTER", + "zIndex": 0, + "level": 4 + }, + { + "id": "container1.container2.container3.first.child", + "type": "rectangle", + "pos": { + "x": 222, + "y": 234 + }, + "width": 80, + "height": 66, + "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": "child", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 35, + "labelHeight": 21, + "labelPosition": "OUTSIDE_BOTTOM_CENTER", + "zIndex": 0, + "level": 5 + }, + { + "id": "container1.container2.container3.second", + "type": "rectangle", + "pos": { + "x": 392, + "y": 184 + }, + "width": 180, + "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": "second", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": false, + "underline": false, + "labelWidth": 48, + "labelHeight": 21, + "labelPosition": "OUTSIDE_TOP_CENTER", + "zIndex": 0, + "level": 4 + }, + { + "id": "container1.container2.container3.second.child", + "type": "rectangle", + "pos": { + "x": 442, + "y": 234 + }, + "width": 80, + "height": 66, + "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": "child", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 35, + "labelHeight": 21, + "labelPosition": "OUTSIDE_BOTTOM_CENTER", + "zIndex": 0, + "level": 5 + }, + { + "id": "container1.container2.container3.third", + "type": "rectangle", + "pos": { + "x": 612, + "y": 184 + }, + "width": 81, + "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": "third", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "N1", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 36, + "labelHeight": 21, + "labelPosition": "OUTSIDE_TOP_CENTER", + "zIndex": 0, + "level": 4 + } + ], + "connections": [], + "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/regression/outside_grid_label_position/elk/sketch.exp.svg b/e2etests/testdata/regression/outside_grid_label_position/elk/sketch.exp.svg new file mode 100644 index 0000000000..1e49a662f1 --- /dev/null +++ b/e2etests/testdata/regression/outside_grid_label_position/elk/sketch.exp.svg @@ -0,0 +1,109 @@ +container1container2container3firstsecondthirdchildchild + + + + + + + + + + \ No newline at end of file