d2/d2layouts/d2sequence/layout.go

80 lines
2.3 KiB
Go
Raw Normal View History

package d2sequence
import (
"context"
2022-12-01 00:11:02 +00:00
"strings"
2023-01-28 07:05:42 +00:00
"oss.terrastruct.com/util-go/go2"
"oss.terrastruct.com/d2/d2graph"
2022-12-01 00:11:02 +00:00
"oss.terrastruct.com/d2/d2target"
"oss.terrastruct.com/d2/lib/geo"
2022-12-02 17:11:02 +00:00
"oss.terrastruct.com/d2/lib/label"
)
2023-04-03 18:45:45 +00:00
// Layout runs the sequence diagram layout engine on objects of shape sequence_diagram
//
2023-09-22 04:00:02 +00:00
// 1. Run layout on sequence diagrams
// 2. Set the resulting dimensions to the main graph shape
2023-04-03 18:45:45 +00:00
func Layout(ctx context.Context, g *d2graph.Graph, layout d2graph.LayoutGraph) error {
2023-09-15 23:50:27 +00:00
// used in layout code
g.Root.Shape.Value = d2target.ShapeSequenceDiagram
sd, err := layoutSequenceDiagram(g, g.Root)
if err != nil {
return err
}
g.Root.Box = geo.NewBox(nil, sd.getWidth()+GROUP_CONTAINER_PADDING*2, sd.getHeight()+GROUP_CONTAINER_PADDING*2)
// the sequence diagram is the only layout engine if the whole diagram is
// shape: sequence_diagram
g.Root.TopLeft = geo.NewPoint(0, 0)
obj := g.Root
2023-07-17 21:21:36 +00:00
obj.LabelPosition = go2.Pointer(label.InsideTopCenter.String())
2023-09-15 23:50:27 +00:00
// shift the sequence diagrams as they are always placed at (0, 0) with some padding
sd.shift(
geo.NewPoint(
obj.TopLeft.X+GROUP_CONTAINER_PADDING,
obj.TopLeft.Y+GROUP_CONTAINER_PADDING,
),
)
obj.Children = make(map[string]*d2graph.Object)
obj.ChildrenArray = make([]*d2graph.Object, 0)
for _, child := range sd.actors {
obj.Children[strings.ToLower(child.ID)] = child
obj.ChildrenArray = append(obj.ChildrenArray, child)
}
for _, child := range sd.groups {
if child.Parent.AbsID() == obj.AbsID() {
obj.Children[strings.ToLower(child.ID)] = child
obj.ChildrenArray = append(obj.ChildrenArray, child)
}
}
g.Edges = append(g.Edges, sd.lifelines...)
return nil
}
// layoutSequenceDiagram finds the edges inside the sequence diagram and performs the layout on the object descendants
2022-12-03 17:38:08 +00:00
func layoutSequenceDiagram(g *d2graph.Graph, obj *d2graph.Object) (*sequenceDiagram, error) {
var edges []*d2graph.Edge
for _, edge := range g.Edges {
// both Src and Dst must be inside the sequence diagram
2022-12-19 04:03:07 +00:00
if obj == g.Root || (strings.HasPrefix(edge.Src.AbsID(), obj.AbsID()+".") && strings.HasPrefix(edge.Dst.AbsID(), obj.AbsID()+".")) {
edges = append(edges, edge)
}
}
sd, err := newSequenceDiagram(obj.ChildrenArray, edges)
if err != nil {
return nil, err
}
err = sd.layout()
2022-12-03 17:38:08 +00:00
return sd, err
}