Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

layout with nested grids #1309

Merged
merged 8 commits into from
May 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions ci/release/changelogs/next.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#### Improvements 🧹

- Use shape specific sizing for grid containers [#1294](https://github.com/terrastruct/d2/pull/1294)
- Grid diagrams now support nested shapes or grid diagrams [#1309](https://github.com/terrastruct/d2/pull/1309)
gavin-ts marked this conversation as resolved.
Show resolved Hide resolved
- Grid diagrams will now also use `grid-gap`, `vertical-gap`, and `horizontal-gap` for padding [#1309](https://github.com/terrastruct/d2/pull/1309)
- Watch mode browser uses an error favicon to easily indicate compiler errors. Thanks @sinyo-matu ! [#1240](https://github.com/terrastruct/d2/pull/1240)
- Improves grid layout performance when there are many similarly sized shapes. [#1315](https://github.com/terrastruct/d2/pull/1315)

Expand Down
7 changes: 0 additions & 7 deletions d2compiler/compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -841,13 +841,6 @@ func (c *compiler) validateKey(obj *d2graph.Object, f *d2ir.Field) {
if !in && arrowheadIn {
c.errorf(f.LastPrimaryKey(), fmt.Sprintf(`invalid shape, can only set "%s" for arrowheads`, obj.Shape.Value))
}
case "grid-rows", "grid-columns", "grid-gap", "vertical-gap", "horizontal-gap":
for _, child := range obj.ChildrenArray {
if child.IsContainer() {
c.errorf(f.LastPrimaryKey(),
fmt.Sprintf(`%#v can only be used on containers with one level of nesting right now. (%#v has nested %#v)`, keyword, child.AbsID(), child.ChildrenArray[0].ID))
}
}
}
return
}
Expand Down
12 changes: 9 additions & 3 deletions d2compiler/compile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2373,11 +2373,17 @@ d2/testdata/d2compiler/TestCompile/grid_edge.d2:6:2: edges in grid diagrams are
a
b
c
d.invalid descendant
d.valid descendant
e: {
grid-rows: 1
grid-columns: 2

a
b
}
}
`,
expErr: `d2/testdata/d2compiler/TestCompile/grid_nested.d2:2:2: "grid-rows" can only be used on containers with one level of nesting right now. ("hey.d" has nested "invalid descendant")
d2/testdata/d2compiler/TestCompile/grid_nested.d2:3:2: "grid-columns" can only be used on containers with one level of nesting right now. ("hey.d" has nested "invalid descendant")`,
expErr: ``,
},
{
name: "classes",
Expand Down
102 changes: 102 additions & 0 deletions d2graph/d2graph.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package d2graph

import (
"bytes"
"context"
"errors"
"fmt"
Expand Down Expand Up @@ -1815,3 +1816,104 @@ func (g *Graph) ApplyTheme(themeID int64) error {
g.Theme = &theme
return nil
}

func (obj *Object) MoveWithDescendants(dx, dy float64) {
obj.TopLeft.X += dx
obj.TopLeft.Y += dy
for _, child := range obj.ChildrenArray {
child.MoveWithDescendants(dx, dy)
}
}

func (obj *Object) MoveWithDescendantsTo(x, y float64) {
dx := x - obj.TopLeft.X
dy := y - obj.TopLeft.Y
obj.MoveWithDescendants(dx, dy)
}

func (parent *Object) removeChild(child *Object) {
delete(parent.Children, strings.ToLower(child.ID))
for i := 0; i < len(parent.ChildrenArray); i++ {
if parent.ChildrenArray[i] == child {
parent.ChildrenArray = append(parent.ChildrenArray[:i], parent.ChildrenArray[i+1:]...)
break
}
}
}

// remove obj and all descendants from graph, as a new Graph
func (g *Graph) ExtractAsNestedGraph(obj *Object) *Graph {
descendantObjects, edges := pluckObjAndEdges(g, obj)

tempGraph := NewGraph()
tempGraph.Root.ChildrenArray = []*Object{obj}
tempGraph.Root.Children[strings.ToLower(obj.ID)] = obj

for _, descendantObj := range descendantObjects {
descendantObj.Graph = tempGraph
}
tempGraph.Objects = descendantObjects
tempGraph.Edges = edges

obj.Parent.removeChild(obj)
obj.Parent = tempGraph.Root

return tempGraph
}

func pluckObjAndEdges(g *Graph, obj *Object) (descendantsObjects []*Object, edges []*Edge) {
for i := 0; i < len(g.Edges); i++ {
edge := g.Edges[i]
if edge.Src == obj || edge.Dst == obj {
edges = append(edges, edge)
g.Edges = append(g.Edges[:i], g.Edges[i+1:]...)
i--
}
}

for i := 0; i < len(g.Objects); i++ {
temp := g.Objects[i]
if temp.AbsID() == obj.AbsID() {
descendantsObjects = append(descendantsObjects, obj)
g.Objects = append(g.Objects[:i], g.Objects[i+1:]...)
for _, child := range obj.ChildrenArray {
subObjects, subEdges := pluckObjAndEdges(g, child)
descendantsObjects = append(descendantsObjects, subObjects...)
edges = append(edges, subEdges...)
}
break
}
}

return descendantsObjects, edges
}

func (g *Graph) InjectNestedGraph(tempGraph *Graph, parent *Object) {
obj := tempGraph.Root.ChildrenArray[0]
obj.MoveWithDescendantsTo(0, 0)
obj.Parent = parent
for _, obj := range tempGraph.Objects {
obj.Graph = g
}
g.Objects = append(g.Objects, tempGraph.Objects...)
parent.Children[strings.ToLower(obj.ID)] = obj
parent.ChildrenArray = append(parent.ChildrenArray, obj)
g.Edges = append(g.Edges, tempGraph.Edges...)
}

func (g *Graph) PrintString() string {
buf := &bytes.Buffer{}
fmt.Fprint(buf, "Objects: [")
for _, obj := range g.Objects {
fmt.Fprintf(buf, "%#v @(%v)", obj.AbsID(), obj.TopLeft.ToString())
}
fmt.Fprint(buf, "]")
return buf.String()
}

func (obj *Object) IterDescendants(apply func(parent, child *Object)) {
for _, c := range obj.ChildrenArray {
apply(obj, c)
c.IterDescendants(apply)
}
}
19 changes: 14 additions & 5 deletions d2layouts/d2grid/grid_diagram.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"strings"

"oss.terrastruct.com/d2/d2graph"
"oss.terrastruct.com/d2/lib/geo"
)

type gridDiagram struct {
Expand Down Expand Up @@ -95,22 +96,30 @@ func newGridDiagram(root *d2graph.Object) *gridDiagram {
gd.horizontalGap, _ = strconv.Atoi(root.HorizontalGap.Value)
}

for _, o := range gd.objects {
o.TopLeft = geo.NewPoint(0, 0)
}

return &gd
}

func (gd *gridDiagram) shift(dx, dy float64) {
for _, obj := range gd.objects {
obj.TopLeft.X += dx
obj.TopLeft.Y += dy
obj.MoveWithDescendants(dx, dy)
}
}

func (gd *gridDiagram) cleanup(obj *d2graph.Object, graph *d2graph.Graph) {
obj.Children = make(map[string]*d2graph.Object)
obj.ChildrenArray = make([]*d2graph.Object, 0)

restore := func(parent, child *d2graph.Object) {
parent.Children[strings.ToLower(child.ID)] = child
parent.ChildrenArray = append(parent.ChildrenArray, child)
graph.Objects = append(graph.Objects, child)
}
for _, child := range gd.objects {
obj.Children[strings.ToLower(child.ID)] = child
obj.ChildrenArray = append(obj.ChildrenArray, child)
restore(obj, child)
child.IterDescendants(restore)
}
graph.Objects = append(graph.Objects, gd.objects...)
}
Loading