update grid layout with simple edge routing

This commit is contained in:
Gavin Nishizawa 2023-09-12 16:54:38 -07:00
parent c51834df24
commit a17013a323
No known key found for this signature in database
GPG key ID: AE3B177777CE55CD
2 changed files with 41 additions and 6 deletions

View file

@ -11,6 +11,7 @@ import (
type gridDiagram struct { type gridDiagram struct {
root *d2graph.Object root *d2graph.Object
objects []*d2graph.Object objects []*d2graph.Object
edges []*d2graph.Edge
rows int rows int
columns int columns int
@ -122,4 +123,7 @@ func (gd *gridDiagram) cleanup(obj *d2graph.Object, graph *d2graph.Graph) {
restore(obj, child) restore(obj, child)
child.IterDescendants(restore) child.IterDescendants(restore)
} }
for _, e := range gd.edges {
graph.Edges = append(graph.Edges, e)
}
} }

View file

@ -31,7 +31,7 @@ const (
// 7. Put grid children back in correct location // 7. Put grid children back in correct location
func Layout(ctx context.Context, g *d2graph.Graph, layout d2graph.LayoutGraph) d2graph.LayoutGraph { func Layout(ctx context.Context, g *d2graph.Graph, layout d2graph.LayoutGraph) d2graph.LayoutGraph {
return func(ctx context.Context, g *d2graph.Graph) error { return func(ctx context.Context, g *d2graph.Graph) error {
gridDiagrams, objectOrder, err := withoutGridDiagrams(ctx, g, layout) gridDiagrams, objectOrder, edgeOrder, err := withoutGridDiagrams(ctx, g, layout)
if err != nil { if err != nil {
return err return err
} }
@ -42,19 +42,24 @@ func Layout(ctx context.Context, g *d2graph.Graph, layout d2graph.LayoutGraph) d
return err return err
} }
cleanup(g, gridDiagrams, objectOrder) cleanup(g, gridDiagrams, objectOrder, edgeOrder)
return nil return nil
} }
} }
func withoutGridDiagrams(ctx context.Context, g *d2graph.Graph, layout d2graph.LayoutGraph) (gridDiagrams map[string]*gridDiagram, objectOrder map[string]int, err error) { func withoutGridDiagrams(ctx context.Context, g *d2graph.Graph, layout d2graph.LayoutGraph) (gridDiagrams map[string]*gridDiagram, objectOrder, edgeOrder map[string]int, err error) {
toRemove := make(map[*d2graph.Object]struct{}) toRemove := make(map[*d2graph.Object]struct{})
edgeToRemove := make(map[*d2graph.Edge]struct{})
gridDiagrams = make(map[string]*gridDiagram) gridDiagrams = make(map[string]*gridDiagram)
objectOrder = make(map[string]int) objectOrder = make(map[string]int)
for i, obj := range g.Objects { for i, obj := range g.Objects {
objectOrder[obj.AbsID()] = i objectOrder[obj.AbsID()] = i
} }
edgeOrder = make(map[string]int)
for i, edge := range g.Edges {
edgeOrder[edge.AbsID()] = i
}
var processGrid func(obj *d2graph.Object) error var processGrid func(obj *d2graph.Object) error
processGrid = func(obj *d2graph.Object) error { processGrid = func(obj *d2graph.Object) error {
@ -200,6 +205,22 @@ func withoutGridDiagrams(ctx context.Context, g *d2graph.Graph, layout d2graph.L
for _, o := range gd.objects { for _, o := range gd.objects {
toRemove[o] = struct{}{} toRemove[o] = struct{}{}
} }
// simple straight line edge routing between grid objects
for i, e := range g.Edges {
edgeOrder[e.AbsID()] = i
if e.Dst.ClosestGridDiagram() != obj {
continue
}
e.Route = []*geo.Point{e.Src.Center(), e.Dst.Center()}
e.TraceToShape(e.Route, 0, 1)
if e.Label.Value != "" {
e.LabelPosition = go2.Pointer(string(label.InsideMiddleCenter))
}
gd.edges = append(gd.edges, e)
edgeToRemove[e] = struct{}{}
}
return nil return nil
} }
@ -218,7 +239,7 @@ func withoutGridDiagrams(ctx context.Context, g *d2graph.Graph, layout d2graph.L
} }
if err := processGrid(obj); err != nil { if err := processGrid(obj); err != nil {
return nil, nil, err return nil, nil, nil, err
} }
} }
} }
@ -230,8 +251,15 @@ func withoutGridDiagrams(ctx context.Context, g *d2graph.Graph, layout d2graph.L
} }
} }
g.Objects = layoutObjects g.Objects = layoutObjects
layoutEdges := make([]*d2graph.Edge, 0, len(edgeToRemove))
for _, e := range g.Edges {
if _, exists := edgeToRemove[e]; !exists {
layoutEdges = append(layoutEdges, e)
}
}
g.Edges = layoutEdges
return gridDiagrams, objectOrder, nil return gridDiagrams, objectOrder, edgeOrder, nil
} }
func layoutGrid(g *d2graph.Graph, obj *d2graph.Object) (*gridDiagram, error) { func layoutGrid(g *d2graph.Graph, obj *d2graph.Object) (*gridDiagram, error) {
@ -940,11 +968,14 @@ func getDistToTarget(layout [][]*d2graph.Object, targetSize float64, horizontalG
// - translating the grid to its position placed by the core layout engine // - translating the grid to its position placed by the core layout engine
// - restore the children of the grid // - restore the children of the grid
// - sorts objects to their original graph order // - sorts objects to their original graph order
func cleanup(graph *d2graph.Graph, gridDiagrams map[string]*gridDiagram, objectsOrder map[string]int) { func cleanup(graph *d2graph.Graph, gridDiagrams map[string]*gridDiagram, objectsOrder, edgeOrder map[string]int) {
defer func() { defer func() {
sort.SliceStable(graph.Objects, func(i, j int) bool { sort.SliceStable(graph.Objects, func(i, j int) bool {
return objectsOrder[graph.Objects[i].AbsID()] < objectsOrder[graph.Objects[j].AbsID()] return objectsOrder[graph.Objects[i].AbsID()] < objectsOrder[graph.Objects[j].AbsID()]
}) })
sort.SliceStable(graph.Edges, func(i, j int) bool {
return edgeOrder[graph.Edges[i].AbsID()] < edgeOrder[graph.Edges[j].AbsID()]
})
}() }()
var restore func(obj *d2graph.Object) var restore func(obj *d2graph.Object)