Merge pull request #1629 from gavin-ts/nested-edges
nested edges within grid cells
This commit is contained in:
commit
f7d48b24a0
12 changed files with 2010 additions and 410 deletions
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
#### Improvements 🧹
|
||||
|
||||
- Grid cells can now contain nested edges [#1629](https://github.com/terrastruct/d2/pull/1629)
|
||||
|
||||
#### Bugfixes ⛑️
|
||||
|
||||
- Grid layout now accounts for each cell's outside labels and icons [#1624](https://github.com/terrastruct/d2/pull/1624)
|
||||
|
|
|
|||
|
|
@ -1089,34 +1089,59 @@ func (c *compiler) validateNear(g *d2graph.Graph) {
|
|||
|
||||
func (c *compiler) validateEdges(g *d2graph.Graph) {
|
||||
for _, edge := range g.Edges {
|
||||
// edges from a grid to something outside is ok
|
||||
// grid -> outside : ok
|
||||
// grid -> grid.cell : not ok
|
||||
// grid -> grid.cell.inner : not ok
|
||||
if edge.Src.IsGridDiagram() && edge.Dst.IsDescendantOf(edge.Src) {
|
||||
c.errorf(edge.GetAstEdge(), "edge from grid diagram %#v cannot enter itself", edge.Src.AbsID())
|
||||
continue
|
||||
}
|
||||
if edge.Dst.IsGridDiagram() && edge.Src.IsDescendantOf(edge.Dst) {
|
||||
c.errorf(edge.GetAstEdge(), "edge from grid diagram %#v cannot enter itself", edge.Dst.AbsID())
|
||||
continue
|
||||
}
|
||||
|
||||
srcGrid := edge.Src.Parent.ClosestGridDiagram()
|
||||
dstGrid := edge.Dst.Parent.ClosestGridDiagram()
|
||||
if srcGrid != nil || dstGrid != nil {
|
||||
if top := srcGrid.TopGridDiagram(); srcGrid != top {
|
||||
// valid: grid.child1 -> grid.child2
|
||||
// invalid: grid.childGrid.child1 -> grid.childGrid.child2
|
||||
c.errorf(edge.GetAstEdge(), "edge must be on direct child of grid diagram %#v", top.AbsID())
|
||||
continue
|
||||
}
|
||||
if top := dstGrid.TopGridDiagram(); dstGrid != top {
|
||||
// valid: grid.child1 -> grid.child2
|
||||
// invalid: grid.childGrid.child1 -> grid.childGrid.child2
|
||||
c.errorf(edge.GetAstEdge(), "edge must be on direct child of grid diagram %#v", top.AbsID())
|
||||
continue
|
||||
}
|
||||
if srcGrid != dstGrid {
|
||||
// valid: a -> grid
|
||||
// invalid: a -> grid.child
|
||||
c.errorf(edge.GetAstEdge(), "edges into grid diagrams are not supported yet")
|
||||
if dstGrid != nil && !(srcGrid != nil && srcGrid.IsDescendantOf(dstGrid)) {
|
||||
c.errorf(edge.GetAstEdge(), "edge cannot enter grid diagram %#v", dstGrid.AbsID())
|
||||
} else {
|
||||
c.errorf(edge.GetAstEdge(), "edge cannot exit grid diagram %#v", srcGrid.AbsID())
|
||||
}
|
||||
continue
|
||||
}
|
||||
if srcGrid != edge.Src.Parent || dstGrid != edge.Dst.Parent {
|
||||
// valid: grid.child1 -> grid.child2
|
||||
// invalid: grid.child1 -> grid.child2.child1
|
||||
c.errorf(edge.GetAstEdge(), "grid diagrams can only have edges between children right now")
|
||||
|
||||
srcCell := edge.Src.ClosestGridCell()
|
||||
dstCell := edge.Dst.ClosestGridCell()
|
||||
// edges within a grid cell are ok now
|
||||
// grid.cell.a -> grid.cell.b : ok
|
||||
// grid.cell.a.c -> grid.cell.b.d : ok
|
||||
// edges between grid cells themselves are ok
|
||||
// grid.cell -> grid.cell2 : ok
|
||||
// grid.cell -> grid.cell.inside : not ok
|
||||
// grid.cell -> grid.cell2.inside : not ok
|
||||
srcIsGridCell := edge.Src == srcCell
|
||||
dstIsGridCell := edge.Dst == dstCell
|
||||
if srcIsGridCell != dstIsGridCell {
|
||||
if srcIsGridCell {
|
||||
c.errorf(edge.GetAstEdge(), "grid cell %#v can only connect to another grid cell", edge.Src.AbsID())
|
||||
} else {
|
||||
c.errorf(edge.GetAstEdge(), "grid cell %#v can only connect to another grid cell", edge.Dst.AbsID())
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if srcCell != dstCell && (!srcIsGridCell || !dstIsGridCell) {
|
||||
c.errorf(edge.GetAstEdge(), "edge cannot exit grid cell %#v", srcCell.AbsID())
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2478,15 +2478,15 @@ d2/testdata/d2compiler/TestCompile/grid_gap_negative.d2:3:16: vertical-gap must
|
|||
grid-rows: 1
|
||||
a -> b: ok
|
||||
}
|
||||
c -> hey.b
|
||||
hey.a -> c
|
||||
hey -> hey.a
|
||||
c -> hey.b
|
||||
hey.a -> c
|
||||
hey -> hey.a
|
||||
|
||||
hey -> c: ok
|
||||
hey -> c: ok
|
||||
`,
|
||||
expErr: `d2/testdata/d2compiler/TestCompile/grid_edge.d2:5:2: edges into grid diagrams are not supported yet
|
||||
d2/testdata/d2compiler/TestCompile/grid_edge.d2:6:2: edges into grid diagrams are not supported yet
|
||||
d2/testdata/d2compiler/TestCompile/grid_edge.d2:7:2: edges into grid diagrams are not supported yet`,
|
||||
expErr: `d2/testdata/d2compiler/TestCompile/grid_edge.d2:5:1: edge cannot enter grid diagram "hey"
|
||||
d2/testdata/d2compiler/TestCompile/grid_edge.d2:6:1: edge cannot exit grid diagram "hey"
|
||||
d2/testdata/d2compiler/TestCompile/grid_edge.d2:7:1: edge from grid diagram "hey" cannot enter itself`,
|
||||
},
|
||||
{
|
||||
name: "grid_deeper_edge",
|
||||
|
|
@ -2494,16 +2494,31 @@ d2/testdata/d2compiler/TestCompile/grid_edge.d2:7:2: edges into grid diagrams ar
|
|||
grid-rows: 1
|
||||
a -> b: ok
|
||||
b: {
|
||||
c -> d: not yet
|
||||
c -> d: ok now
|
||||
c.e -> c.f.g: ok
|
||||
c.e -> d.h: ok
|
||||
c -> d.h: ok
|
||||
}
|
||||
a: {
|
||||
grid-columns: 1
|
||||
e -> f: also not yet
|
||||
e -> f: also ok now
|
||||
e: {
|
||||
g -> h: ok
|
||||
g -> h.h: ok
|
||||
}
|
||||
e -> f.i: not ok
|
||||
e.g -> f.i: not ok
|
||||
}
|
||||
a -> b.c: not yet
|
||||
a.e -> b.c: also not yet
|
||||
a -> a.e: not ok
|
||||
}
|
||||
`,
|
||||
expErr: `d2/testdata/d2compiler/TestCompile/grid_deeper_edge.d2:9:3: edge must be on direct child of grid diagram "hey"
|
||||
d2/testdata/d2compiler/TestCompile/grid_deeper_edge.d2:5:3: grid diagrams can only have edges between children right now`,
|
||||
expErr: `d2/testdata/d2compiler/TestCompile/grid_deeper_edge.d2:17:3: grid cell "hey.a.e" can only connect to another grid cell
|
||||
d2/testdata/d2compiler/TestCompile/grid_deeper_edge.d2:18:3: edge cannot exit grid cell "hey.a.e"
|
||||
d2/testdata/d2compiler/TestCompile/grid_deeper_edge.d2:20:2: grid cell "hey.a" can only connect to another grid cell
|
||||
d2/testdata/d2compiler/TestCompile/grid_deeper_edge.d2:21:2: edge cannot exit grid diagram "hey.a"
|
||||
d2/testdata/d2compiler/TestCompile/grid_deeper_edge.d2:22:2: edge from grid diagram "hey.a" cannot enter itself`,
|
||||
},
|
||||
{
|
||||
name: "grid_nested",
|
||||
|
|
|
|||
|
|
@ -15,6 +15,17 @@ func (obj *Object) ClosestGridDiagram() *Object {
|
|||
return obj.Parent.ClosestGridDiagram()
|
||||
}
|
||||
|
||||
func (obj *Object) ClosestGridCell() *Object {
|
||||
if obj == nil {
|
||||
return nil
|
||||
}
|
||||
// grid cells can be a nested grid diagram
|
||||
if obj.Parent.IsGridDiagram() {
|
||||
return obj
|
||||
}
|
||||
return obj.Parent.ClosestGridCell()
|
||||
}
|
||||
|
||||
// TopGridDiagram returns the least nested (outermost) grid diagram
|
||||
func (obj *Object) TopGridDiagram() *Object {
|
||||
if obj == nil {
|
||||
|
|
|
|||
|
|
@ -106,6 +106,7 @@ func LayoutNested(ctx context.Context, g *d2graph.Graph, graphInfo GraphInfo, co
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
InjectNested(g.Root, nestedGraph, false)
|
||||
restoreOrder()
|
||||
|
||||
|
|
@ -122,15 +123,25 @@ func LayoutNested(ctx context.Context, g *d2graph.Graph, graphInfo GraphInfo, co
|
|||
}
|
||||
curr = obj
|
||||
|
||||
dx := -curr.TopLeft.X
|
||||
dy := -curr.TopLeft.Y
|
||||
// position nested graph (excluding curr) relative to curr
|
||||
dx := 0 - curr.TopLeft.X
|
||||
dy := 0 - curr.TopLeft.Y
|
||||
for _, o := range nestedGraph.Objects {
|
||||
if o.AbsID() == curr.AbsID() {
|
||||
continue
|
||||
}
|
||||
o.TopLeft.X += dx
|
||||
o.TopLeft.Y += dy
|
||||
}
|
||||
for _, e := range nestedGraph.Edges {
|
||||
e.Move(dx, dy)
|
||||
}
|
||||
|
||||
// now we keep the descendants out until after grid layout
|
||||
nestedGraph = ExtractSubgraph(curr, false)
|
||||
|
||||
extracted[id] = nestedGraph
|
||||
extractedOrder = append(extractedOrder, id)
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
@ -326,7 +337,6 @@ func ExtractSubgraph(container *d2graph.Object, includeSelf bool) *d2graph.Graph
|
|||
}
|
||||
|
||||
func InjectNested(container *d2graph.Object, nestedGraph *d2graph.Graph, isRoot bool) {
|
||||
// TODO restore order of objects
|
||||
g := container.Graph
|
||||
for _, obj := range nestedGraph.Root.ChildrenArray {
|
||||
obj.Parent = container
|
||||
|
|
@ -358,6 +368,9 @@ func PositionNested(container *d2graph.Object, nestedGraph *d2graph.Graph) {
|
|||
// Note: assumes nestedGraph's layout has contents positioned relative to 0,0
|
||||
dx := container.TopLeft.X //- tl.X
|
||||
dy := container.TopLeft.Y //- tl.Y
|
||||
if dx == 0 && dy == 0 {
|
||||
return
|
||||
}
|
||||
for _, o := range nestedGraph.Objects {
|
||||
o.TopLeft.X += dx
|
||||
o.TopLeft.Y += dy
|
||||
|
|
|
|||
|
|
@ -8,18 +8,18 @@ outer-grid: {
|
|||
|
||||
container: {
|
||||
label.near: top-left
|
||||
# edges not yet supported here since they must be direct grid children
|
||||
a
|
||||
b
|
||||
c
|
||||
(** -> **)[*].class: red
|
||||
# edges on grid descendant now supported
|
||||
a -> b -> c -> a
|
||||
d -> e -> g.h.i
|
||||
d -> f -> g.h
|
||||
b -> g
|
||||
}
|
||||
|
||||
inner-grid: {
|
||||
grid-rows: 1
|
||||
1
|
||||
2
|
||||
3
|
||||
# edges here are not supported yet since this is inside another grid
|
||||
# edges inside another grid now supported
|
||||
1 -> 2 -> 3: {class: red}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -41,3 +41,5 @@ outer-container: {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
classes.red.style.stroke: red
|
||||
|
|
|
|||
968
e2etests/testdata/stable/grid_nested_simple_edges/dagre/board.exp.json
generated
vendored
968
e2etests/testdata/stable/grid_nested_simple_edges/dagre/board.exp.json
generated
vendored
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 32 KiB |
862
e2etests/testdata/stable/grid_nested_simple_edges/elk/board.exp.json
generated
vendored
862
e2etests/testdata/stable/grid_nested_simple_edges/elk/board.exp.json
generated
vendored
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 32 KiB |
20
testdata/d2compiler/TestCompile/grid_deeper_edge.exp.json
generated
vendored
20
testdata/d2compiler/TestCompile/grid_deeper_edge.exp.json
generated
vendored
|
|
@ -3,12 +3,24 @@
|
|||
"err": {
|
||||
"errs": [
|
||||
{
|
||||
"range": "d2/testdata/d2compiler/TestCompile/grid_deeper_edge.d2,8:2:86-8:8:92",
|
||||
"errmsg": "d2/testdata/d2compiler/TestCompile/grid_deeper_edge.d2:9:3: edge must be on direct child of grid diagram \"hey\""
|
||||
"range": "d2/testdata/d2compiler/TestCompile/grid_deeper_edge.d2,16:2:199-16:10:207",
|
||||
"errmsg": "d2/testdata/d2compiler/TestCompile/grid_deeper_edge.d2:17:3: grid cell \"hey.a.e\" can only connect to another grid cell"
|
||||
},
|
||||
{
|
||||
"range": "d2/testdata/d2compiler/TestCompile/grid_deeper_edge.d2,4:2:41-4:8:47",
|
||||
"errmsg": "d2/testdata/d2compiler/TestCompile/grid_deeper_edge.d2:5:3: grid diagrams can only have edges between children right now"
|
||||
"range": "d2/testdata/d2compiler/TestCompile/grid_deeper_edge.d2,17:2:218-17:12:228",
|
||||
"errmsg": "d2/testdata/d2compiler/TestCompile/grid_deeper_edge.d2:18:3: edge cannot exit grid cell \"hey.a.e\""
|
||||
},
|
||||
{
|
||||
"range": "d2/testdata/d2compiler/TestCompile/grid_deeper_edge.d2,19:1:241-19:9:249",
|
||||
"errmsg": "d2/testdata/d2compiler/TestCompile/grid_deeper_edge.d2:20:2: grid cell \"hey.a\" can only connect to another grid cell"
|
||||
},
|
||||
{
|
||||
"range": "d2/testdata/d2compiler/TestCompile/grid_deeper_edge.d2,20:1:260-20:11:270",
|
||||
"errmsg": "d2/testdata/d2compiler/TestCompile/grid_deeper_edge.d2:21:2: edge cannot exit grid diagram \"hey.a\""
|
||||
},
|
||||
{
|
||||
"range": "d2/testdata/d2compiler/TestCompile/grid_deeper_edge.d2,21:1:286-21:9:294",
|
||||
"errmsg": "d2/testdata/d2compiler/TestCompile/grid_deeper_edge.d2:22:2: edge from grid diagram \"hey.a\" cannot enter itself"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
12
testdata/d2compiler/TestCompile/grid_edge.exp.json
generated
vendored
12
testdata/d2compiler/TestCompile/grid_edge.exp.json
generated
vendored
|
|
@ -3,16 +3,16 @@
|
|||
"err": {
|
||||
"errs": [
|
||||
{
|
||||
"range": "d2/testdata/d2compiler/TestCompile/grid_edge.d2,4:1:36-4:11:46",
|
||||
"errmsg": "d2/testdata/d2compiler/TestCompile/grid_edge.d2:5:2: edges into grid diagrams are not supported yet"
|
||||
"range": "d2/testdata/d2compiler/TestCompile/grid_edge.d2,4:0:35-4:10:45",
|
||||
"errmsg": "d2/testdata/d2compiler/TestCompile/grid_edge.d2:5:1: edge cannot enter grid diagram \"hey\""
|
||||
},
|
||||
{
|
||||
"range": "d2/testdata/d2compiler/TestCompile/grid_edge.d2,5:1:48-5:11:58",
|
||||
"errmsg": "d2/testdata/d2compiler/TestCompile/grid_edge.d2:6:2: edges into grid diagrams are not supported yet"
|
||||
"range": "d2/testdata/d2compiler/TestCompile/grid_edge.d2,5:0:46-5:10:56",
|
||||
"errmsg": "d2/testdata/d2compiler/TestCompile/grid_edge.d2:6:1: edge cannot exit grid diagram \"hey\""
|
||||
},
|
||||
{
|
||||
"range": "d2/testdata/d2compiler/TestCompile/grid_edge.d2,6:1:60-6:13:72",
|
||||
"errmsg": "d2/testdata/d2compiler/TestCompile/grid_edge.d2:7:2: edges into grid diagrams are not supported yet"
|
||||
"range": "d2/testdata/d2compiler/TestCompile/grid_edge.d2,6:0:57-6:12:69",
|
||||
"errmsg": "d2/testdata/d2compiler/TestCompile/grid_edge.d2:7:1: edge from grid diagram \"hey\" cannot enter itself"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue