Merge pull request #1618 from gavin-ts/layout-fixes
layout + serialization fixes
This commit is contained in:
commit
88ac888a59
2 changed files with 73 additions and 30 deletions
|
|
@ -13,6 +13,7 @@ type SerializedGraph struct {
|
||||||
Root SerializedObject `json:"root"`
|
Root SerializedObject `json:"root"`
|
||||||
Edges []SerializedEdge `json:"edges"`
|
Edges []SerializedEdge `json:"edges"`
|
||||||
Objects []SerializedObject `json:"objects"`
|
Objects []SerializedObject `json:"objects"`
|
||||||
|
RootLevel int `json:"rootLevel"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SerializedObject map[string]interface{}
|
type SerializedObject map[string]interface{}
|
||||||
|
|
@ -30,6 +31,7 @@ func DeserializeGraph(bytes []byte, g *Graph) error {
|
||||||
convert(sg.Root, &root)
|
convert(sg.Root, &root)
|
||||||
g.Root = &root
|
g.Root = &root
|
||||||
root.Graph = g
|
root.Graph = g
|
||||||
|
g.RootLevel = sg.RootLevel
|
||||||
|
|
||||||
idToObj := make(map[string]*Object)
|
idToObj := make(map[string]*Object)
|
||||||
idToObj[""] = g.Root
|
idToObj[""] = g.Root
|
||||||
|
|
@ -39,6 +41,7 @@ func DeserializeGraph(bytes []byte, g *Graph) error {
|
||||||
if err := convert(so, &o); err != nil {
|
if err := convert(so, &o); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
o.Graph = g
|
||||||
objects = append(objects, &o)
|
objects = append(objects, &o)
|
||||||
idToObj[so["AbsID"].(string)] = &o
|
idToObj[so["AbsID"].(string)] = &o
|
||||||
}
|
}
|
||||||
|
|
@ -91,6 +94,7 @@ func SerializeGraph(g *Graph) ([]byte, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
sg.Root = root
|
sg.Root = root
|
||||||
|
sg.RootLevel = g.RootLevel
|
||||||
|
|
||||||
var sobjects []SerializedObject
|
var sobjects []SerializedObject
|
||||||
for _, o := range g.Objects {
|
for _, o := range g.Objects {
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package d2layouts
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
@ -77,8 +78,8 @@ func LayoutNested(ctx context.Context, g *d2graph.Graph, graphInfo GraphInfo, co
|
||||||
g.Root.Box = &geo.Box{}
|
g.Root.Box = &geo.Box{}
|
||||||
|
|
||||||
// Before we can layout these nodes, we need to handle all nested diagrams first.
|
// Before we can layout these nodes, we need to handle all nested diagrams first.
|
||||||
extracted := make(map[*d2graph.Object]*d2graph.Graph)
|
extracted := make(map[string]*d2graph.Graph)
|
||||||
var extractedOrder []*d2graph.Object
|
var extractedOrder []string
|
||||||
|
|
||||||
var constantNears []*d2graph.Graph
|
var constantNears []*d2graph.Graph
|
||||||
restoreOrder := SaveOrder(g)
|
restoreOrder := SaveOrder(g)
|
||||||
|
|
@ -100,12 +101,27 @@ func LayoutNested(ctx context.Context, g *d2graph.Graph, graphInfo GraphInfo, co
|
||||||
// if we are in a grid diagram, and our children have descendants
|
// if we are in a grid diagram, and our children have descendants
|
||||||
// we need to run layout on them first, even if they are not special diagram types
|
// we need to run layout on them first, even if they are not special diagram types
|
||||||
nestedGraph := ExtractSubgraph(curr, true)
|
nestedGraph := ExtractSubgraph(curr, true)
|
||||||
|
id := curr.AbsID()
|
||||||
err := LayoutNested(ctx, nestedGraph, GraphInfo{}, coreLayout)
|
err := LayoutNested(ctx, nestedGraph, GraphInfo{}, coreLayout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
InjectNested(g.Root, nestedGraph, false)
|
InjectNested(g.Root, nestedGraph, false)
|
||||||
restoreOrder()
|
restoreOrder()
|
||||||
|
|
||||||
|
// need to update curr *Object incase layout changed it
|
||||||
|
var obj *d2graph.Object
|
||||||
|
for _, o := range g.Objects {
|
||||||
|
if o.AbsID() == id {
|
||||||
|
obj = o
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if obj == nil {
|
||||||
|
return fmt.Errorf("could not find object %#v after layout", id)
|
||||||
|
}
|
||||||
|
curr = obj
|
||||||
|
|
||||||
dx := -curr.TopLeft.X
|
dx := -curr.TopLeft.X
|
||||||
dy := -curr.TopLeft.Y
|
dy := -curr.TopLeft.Y
|
||||||
for _, o := range nestedGraph.Objects {
|
for _, o := range nestedGraph.Objects {
|
||||||
|
|
@ -140,6 +156,11 @@ func LayoutNested(ctx context.Context, g *d2graph.Graph, graphInfo GraphInfo, co
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
// coreLayout can overwrite graph contents with newly created *Object pointers
|
||||||
|
// so we need to update `curr` with nestedGraph's value
|
||||||
|
if gi.IsConstantNear {
|
||||||
|
curr = nestedGraph.Root.ChildrenArray[0]
|
||||||
|
}
|
||||||
|
|
||||||
if gi.IsConstantNear {
|
if gi.IsConstantNear {
|
||||||
curr.NearKey = nearKey
|
curr.NearKey = nearKey
|
||||||
|
|
@ -153,8 +174,10 @@ func LayoutNested(ctx context.Context, g *d2graph.Graph, graphInfo GraphInfo, co
|
||||||
constantNears = append(constantNears, nestedGraph)
|
constantNears = append(constantNears, nestedGraph)
|
||||||
} else {
|
} else {
|
||||||
// We will restore the contents after running layout with child as the placeholder
|
// We will restore the contents after running layout with child as the placeholder
|
||||||
extracted[curr] = nestedGraph
|
// We need to reference using ID because there may be a new object to use after coreLayout
|
||||||
extractedOrder = append(extractedOrder, curr)
|
id := curr.AbsID()
|
||||||
|
extracted[id] = nestedGraph
|
||||||
|
extractedOrder = append(extractedOrder, id)
|
||||||
}
|
}
|
||||||
} else if len(curr.ChildrenArray) > 0 {
|
} else if len(curr.ChildrenArray) > 0 {
|
||||||
queue = append(queue, curr.ChildrenArray...)
|
queue = append(queue, curr.ChildrenArray...)
|
||||||
|
|
@ -164,6 +187,7 @@ func LayoutNested(ctx context.Context, g *d2graph.Graph, graphInfo GraphInfo, co
|
||||||
// We can now run layout with accurate sizes of nested layout containers
|
// We can now run layout with accurate sizes of nested layout containers
|
||||||
// Layout according to the type of diagram
|
// Layout according to the type of diagram
|
||||||
var err error
|
var err error
|
||||||
|
if len(g.Objects) > 0 {
|
||||||
switch graphInfo.DiagramType {
|
switch graphInfo.DiagramType {
|
||||||
case GridDiagram:
|
case GridDiagram:
|
||||||
log.Debug(ctx, "layout grid", slog.F("rootlevel", g.RootLevel), slog.F("shapes", g.PrintString()))
|
log.Debug(ctx, "layout grid", slog.F("rootlevel", g.RootLevel), slog.F("shapes", g.PrintString()))
|
||||||
|
|
@ -184,19 +208,31 @@ func LayoutNested(ctx context.Context, g *d2graph.Graph, graphInfo GraphInfo, co
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if len(constantNears) > 0 {
|
if len(constantNears) > 0 {
|
||||||
err := d2near.Layout(ctx, g, constantNears)
|
err = d2near.Layout(ctx, g, constantNears)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// With the layout set, inject all the extracted graphs
|
// With the layout set, inject all the extracted graphs
|
||||||
for _, n := range extractedOrder {
|
for _, id := range extractedOrder {
|
||||||
nestedGraph := extracted[n]
|
nestedGraph := extracted[id]
|
||||||
InjectNested(n, nestedGraph, true)
|
// we have to find the object by ID because coreLayout can replace the Objects in graph
|
||||||
PositionNested(n, nestedGraph)
|
var obj *d2graph.Object
|
||||||
|
for _, o := range g.Objects {
|
||||||
|
if o.AbsID() == id {
|
||||||
|
obj = o
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if obj == nil {
|
||||||
|
return fmt.Errorf("could not find object %#v after layout", id)
|
||||||
|
}
|
||||||
|
InjectNested(obj, nestedGraph, true)
|
||||||
|
PositionNested(obj, nestedGraph)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debug(ctx, "done", slog.F("rootlevel", g.RootLevel), slog.F("shapes", g.PrintString()))
|
log.Debug(ctx, "done", slog.F("rootlevel", g.RootLevel), slog.F("shapes", g.PrintString()))
|
||||||
|
|
@ -294,6 +330,9 @@ func InjectNested(container *d2graph.Object, nestedGraph *d2graph.Graph, isRoot
|
||||||
g := container.Graph
|
g := container.Graph
|
||||||
for _, obj := range nestedGraph.Root.ChildrenArray {
|
for _, obj := range nestedGraph.Root.ChildrenArray {
|
||||||
obj.Parent = container
|
obj.Parent = container
|
||||||
|
if container.Children == nil {
|
||||||
|
container.Children = make(map[string]*d2graph.Object)
|
||||||
|
}
|
||||||
container.Children[strings.ToLower(obj.ID)] = obj
|
container.Children[strings.ToLower(obj.ID)] = obj
|
||||||
container.ChildrenArray = append(container.ChildrenArray, obj)
|
container.ChildrenArray = append(container.ChildrenArray, obj)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue