diff --git a/d2layouts/d2near/layout.go b/d2layouts/d2near/layout.go index e05709169..85ef8ff72 100644 --- a/d2layouts/d2near/layout.go +++ b/d2layouts/d2near/layout.go @@ -27,12 +27,12 @@ func Layout(ctx context.Context, g *d2graph.Graph, constantNears []*d2graph.Obje // So place the center ones first, then the later ones will consider them for bounding box for _, processCenters := range []bool{true, false} { for _, obj := range constantNears { - if processCenters == strings.Contains(d2graph.Key(obj.Attributes.NearKey)[0], "center") { + if processCenters == strings.Contains(d2graph.Key(obj.Attributes.NearKey)[0], "-center") { obj.TopLeft = geo.NewPoint(place(obj)) } } for _, obj := range constantNears { - if processCenters == strings.Contains(d2graph.Key(obj.Attributes.NearKey)[0], "center") { + if processCenters == strings.Contains(d2graph.Key(obj.Attributes.NearKey)[0], "-center") { // The z-index for constant nears does not matter, as it will not collide g.Objects = append(g.Objects, obj) obj.Parent.Children[obj.ID] = obj diff --git a/d2layouts/d2sequence/layout.go b/d2layouts/d2sequence/layout.go index 49ae00b43..14e4c6f80 100644 --- a/d2layouts/d2sequence/layout.go +++ b/d2layouts/d2sequence/layout.go @@ -17,43 +17,45 @@ func WithoutSequenceDiagrams(ctx context.Context, g *d2graph.Graph) (map[string] edgesToRemove := make(map[*d2graph.Edge]struct{}) sequenceDiagrams := make(map[string]*sequenceDiagram) - queue := make([]*d2graph.Object, 1, len(g.Objects)) - queue[0] = g.Root - for len(queue) > 0 { - obj := queue[0] - queue = queue[1:] - if len(obj.ChildrenArray) == 0 { - continue - } - if obj.Attributes.Shape.Value != d2target.ShapeSequenceDiagram { - queue = append(queue, obj.ChildrenArray...) - continue - } + if len(g.Objects) > 0 { + queue := make([]*d2graph.Object, 1, len(g.Objects)) + queue[0] = g.Root + for len(queue) > 0 { + obj := queue[0] + queue = queue[1:] + if len(obj.ChildrenArray) == 0 { + continue + } + if obj.Attributes.Shape.Value != d2target.ShapeSequenceDiagram { + queue = append(queue, obj.ChildrenArray...) + continue + } - sd, err := layoutSequenceDiagram(g, obj) - if err != nil { - return nil, nil, nil, err - } - obj.Children = make(map[string]*d2graph.Object) - obj.ChildrenArray = nil - obj.Box = geo.NewBox(nil, sd.getWidth()+GROUP_CONTAINER_PADDING*2, sd.getHeight()+GROUP_CONTAINER_PADDING*2) - obj.LabelPosition = go2.Pointer(string(label.InsideTopCenter)) - sequenceDiagrams[obj.AbsID()] = sd + sd, err := layoutSequenceDiagram(g, obj) + if err != nil { + return nil, nil, nil, err + } + obj.Children = make(map[string]*d2graph.Object) + obj.ChildrenArray = nil + obj.Box = geo.NewBox(nil, sd.getWidth()+GROUP_CONTAINER_PADDING*2, sd.getHeight()+GROUP_CONTAINER_PADDING*2) + obj.LabelPosition = go2.Pointer(string(label.InsideTopCenter)) + sequenceDiagrams[obj.AbsID()] = sd - for _, edge := range sd.messages { - edgesToRemove[edge] = struct{}{} - } - for _, obj := range sd.actors { - objectsToRemove[obj] = struct{}{} - } - for _, obj := range sd.notes { - objectsToRemove[obj] = struct{}{} - } - for _, obj := range sd.groups { - objectsToRemove[obj] = struct{}{} - } - for _, obj := range sd.spans { - objectsToRemove[obj] = struct{}{} + for _, edge := range sd.messages { + edgesToRemove[edge] = struct{}{} + } + for _, obj := range sd.actors { + objectsToRemove[obj] = struct{}{} + } + for _, obj := range sd.notes { + objectsToRemove[obj] = struct{}{} + } + for _, obj := range sd.groups { + objectsToRemove[obj] = struct{}{} + } + for _, obj := range sd.spans { + objectsToRemove[obj] = struct{}{} + } } } diff --git a/e2etests/stable_test.go b/e2etests/stable_test.go index fb9f7399a..7ec142f3a 100644 --- a/e2etests/stable_test.go +++ b/e2etests/stable_test.go @@ -1815,6 +1815,20 @@ x.y -> a.b: { style.animated: true target-arrowhead.shape: cf-many } +`, + }, + { + name: "near-alone", + script: ` +x: { + near: top-center +} +y: { + near: bottom-center +} +z: { + near: center-left +} `, }, } diff --git a/e2etests/testdata/stable/near-alone/dagre/board.exp.json b/e2etests/testdata/stable/near-alone/dagre/board.exp.json new file mode 100644 index 000000000..dba43ee30 --- /dev/null +++ b/e2etests/testdata/stable/near-alone/dagre/board.exp.json @@ -0,0 +1,127 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "x", + "type": "", + "pos": { + "x": -56, + "y": -146 + }, + "width": 113, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "x", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 13, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "y", + "type": "", + "pos": { + "x": -57, + "y": 20 + }, + "width": 114, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "y", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 14, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "z", + "type": "", + "pos": { + "x": -189, + "y": 0 + }, + "width": 112, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "z", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 12, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + } + ], + "connections": [] +} diff --git a/e2etests/testdata/stable/near-alone/dagre/sketch.exp.svg b/e2etests/testdata/stable/near-alone/dagre/sketch.exp.svg new file mode 100644 index 000000000..3944c699c --- /dev/null +++ b/e2etests/testdata/stable/near-alone/dagre/sketch.exp.svg @@ -0,0 +1,52 @@ + +xyz + + + \ No newline at end of file diff --git a/e2etests/testdata/stable/near-alone/elk/board.exp.json b/e2etests/testdata/stable/near-alone/elk/board.exp.json new file mode 100644 index 000000000..dba43ee30 --- /dev/null +++ b/e2etests/testdata/stable/near-alone/elk/board.exp.json @@ -0,0 +1,127 @@ +{ + "name": "", + "fontFamily": "SourceSansPro", + "shapes": [ + { + "id": "x", + "type": "", + "pos": { + "x": -56, + "y": -146 + }, + "width": 113, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "x", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 13, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "y", + "type": "", + "pos": { + "x": -57, + "y": 20 + }, + "width": 114, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "y", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 14, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + }, + { + "id": "z", + "type": "", + "pos": { + "x": -189, + "y": 0 + }, + "width": 112, + "height": 126, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "blend": false, + "fields": null, + "methods": null, + "columns": null, + "label": "z", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 12, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "zIndex": 0, + "level": 1 + } + ], + "connections": [] +} diff --git a/e2etests/testdata/stable/near-alone/elk/sketch.exp.svg b/e2etests/testdata/stable/near-alone/elk/sketch.exp.svg new file mode 100644 index 000000000..3944c699c --- /dev/null +++ b/e2etests/testdata/stable/near-alone/elk/sketch.exp.svg @@ -0,0 +1,52 @@ + +xyz + + + \ No newline at end of file