This commit is contained in:
Gavin Nishizawa 2023-09-21 21:00:02 -07:00
parent 9ecbc61945
commit cee6a92722
No known key found for this signature in database
GPG key ID: AE3B177777CE55CD
7 changed files with 10 additions and 553 deletions

View file

@ -17,9 +17,8 @@ import (
"oss.terrastruct.com/d2/d2compiler"
"oss.terrastruct.com/d2/d2exporter"
"oss.terrastruct.com/d2/d2graph"
"oss.terrastruct.com/d2/d2layouts"
"oss.terrastruct.com/d2/d2layouts/d2dagrelayout"
"oss.terrastruct.com/d2/d2layouts/d2grid"
"oss.terrastruct.com/d2/d2layouts/d2sequence"
"oss.terrastruct.com/d2/d2lib"
"oss.terrastruct.com/d2/d2target"
"oss.terrastruct.com/d2/lib/geo"
@ -235,7 +234,8 @@ func run(t *testing.T, tc testCase) {
err = g.SetDimensions(nil, ruler, nil)
assert.JSON(t, nil, err)
err = d2sequence.Layout(ctx, g, d2grid.Layout(ctx, g, d2dagrelayout.DefaultLayout))
graphInfo := d2layouts.NestedGraphInfo(g.Root)
err = d2layouts.LayoutNested(ctx, g, graphInfo, d2dagrelayout.DefaultLayout)
if err != nil {
t.Fatal(err)
}

View file

@ -5,7 +5,6 @@ import (
"context"
"fmt"
"math"
"sort"
"oss.terrastruct.com/d2/d2graph"
"oss.terrastruct.com/d2/d2target"
@ -21,42 +20,15 @@ const (
// Layout runs the grid layout on containers with rows/columns
// Note: children are not allowed edges or descendants
//
// 1. Traverse graph from root, skip objects with no rows/columns
// 2. Construct a grid with the container children
// 3. Remove the children from the main graph
// 4. Run grid layout
// 5. Set the resulting dimensions to the main graph shape
// 6. Run core layouts (without grid children)
// 7. Put grid children back in correct location
func Layout(ctx context.Context, g *d2graph.Graph, layout d2graph.LayoutGraph) d2graph.LayoutGraph {
return func(ctx context.Context, g *d2graph.Graph) error {
gridDiagrams, objectOrder, edgeOrder, err := withoutGridDiagrams(ctx, g, layout)
if err != nil {
return err
}
if g.Root.IsGridDiagram() && len(g.Root.ChildrenArray) != 0 {
g.Root.TopLeft = geo.NewPoint(0, 0)
} else if err := layout(ctx, g); err != nil {
return err
}
cleanup(g, gridDiagrams, objectOrder, edgeOrder)
return nil
}
}
func Layout2(ctx context.Context, g *d2graph.Graph) error {
// 1. Run grid layout on the graph root
// 2. Set the resulting dimensions to the graph root
func Layout(ctx context.Context, g *d2graph.Graph) error {
obj := g.Root
gd, err := layoutGrid(g, obj)
if err != nil {
return err
}
// obj.Children = make(map[string]*d2graph.Object)
// obj.ChildrenArray = nil
if obj.Box != nil {
// CONTAINER_PADDING is default, but use gap value if set
@ -163,13 +135,11 @@ func Layout2(ctx context.Context, g *d2graph.Graph) error {
// simple straight line edge routing between grid objects
for _, e := range g.Edges {
// edgeOrder[e.AbsID()] = i
if !e.Src.Parent.IsDescendantOf(obj) && !e.Dst.Parent.IsDescendantOf(obj) {
continue
}
// if edge is within grid, remove it from outer layout
gd.edges = append(gd.edges, e)
// edgeToRemove[e] = struct{}{}
if e.Src.Parent != obj || e.Dst.Parent != obj {
continue
@ -206,233 +176,6 @@ func Layout2(ctx context.Context, g *d2graph.Graph) error {
return nil
}
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{})
edgeToRemove := make(map[*d2graph.Edge]struct{})
gridDiagrams = make(map[string]*gridDiagram)
objectOrder = make(map[string]int)
for i, obj := range g.Objects {
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
processGrid = func(obj *d2graph.Object) error {
for _, child := range obj.ChildrenArray {
if len(child.ChildrenArray) == 0 {
continue
}
if child.IsGridDiagram() {
if err := processGrid(child); err != nil {
return err
}
} else {
tempGraph := g.ExtractAsNestedGraph(child)
if err := layout(ctx, tempGraph); err != nil {
return err
}
g.InjectNestedGraph(tempGraph, obj)
sort.SliceStable(g.Objects, func(i, j int) bool {
return objectOrder[g.Objects[i].AbsID()] < objectOrder[g.Objects[j].AbsID()]
})
sort.SliceStable(child.ChildrenArray, func(i, j int) bool {
return objectOrder[child.ChildrenArray[i].AbsID()] < objectOrder[child.ChildrenArray[j].AbsID()]
})
sort.SliceStable(obj.ChildrenArray, func(i, j int) bool {
return objectOrder[obj.ChildrenArray[i].AbsID()] < objectOrder[obj.ChildrenArray[j].AbsID()]
})
sort.SliceStable(g.Edges, func(i, j int) bool {
return edgeOrder[g.Edges[i].AbsID()] < edgeOrder[g.Edges[j].AbsID()]
})
for _, o := range tempGraph.Objects {
toRemove[o] = struct{}{}
}
}
}
gd, err := layoutGrid(g, obj)
if err != nil {
return err
}
obj.Children = make(map[string]*d2graph.Object)
obj.ChildrenArray = nil
if obj.Box != nil {
// CONTAINER_PADDING is default, but use gap value if set
horizontalPadding, verticalPadding := CONTAINER_PADDING, CONTAINER_PADDING
if obj.GridGap != nil || obj.HorizontalGap != nil {
horizontalPadding = gd.horizontalGap
}
if obj.GridGap != nil || obj.VerticalGap != nil {
verticalPadding = gd.verticalGap
}
// size shape according to grid
obj.SizeToContent(gd.width, gd.height, float64(2*horizontalPadding), float64(2*verticalPadding))
// compute where the grid should be placed inside shape
s := obj.ToShape()
innerBox := s.GetInnerBox()
if innerBox.TopLeft.X != 0 || innerBox.TopLeft.Y != 0 {
gd.shift(innerBox.TopLeft.X, innerBox.TopLeft.Y)
}
// compute how much space the label and icon occupy
var occupiedWidth, occupiedHeight float64
if obj.Icon != nil {
iconSpace := float64(d2target.MAX_ICON_SIZE + 2*label.PADDING)
occupiedWidth = iconSpace
occupiedHeight = iconSpace
}
var dx, dy float64
if obj.LabelDimensions.Height != 0 {
occupiedHeight = math.Max(
occupiedHeight,
float64(obj.LabelDimensions.Height)+2*label.PADDING,
)
}
if obj.LabelDimensions.Width != 0 {
// . ├────┤───────├────┤
// . icon label icon
// with an icon in top left we need 2x the space to fit the label in the center
occupiedWidth *= 2
occupiedWidth += float64(obj.LabelDimensions.Width) + 2*label.PADDING
if occupiedWidth > obj.Width {
dx = (occupiedWidth - obj.Width) / 2
obj.Width = occupiedWidth
}
}
// also check for grid cells with outside top labels or icons
// the first grid object is at the top (and always exists)
topY := gd.objects[0].TopLeft.Y
highestOutside := topY
for _, o := range gd.objects {
// we only want to compute label positions for objects at the top of the grid
if o.TopLeft.Y > topY {
if gd.rowDirected {
// if the grid is rowDirected (row1, row2, etc) we can stop after finishing the first row
break
} else {
// otherwise we continue until the next column
continue
}
}
if o.LabelPosition != nil {
labelPosition := label.Position(*o.LabelPosition)
if labelPosition.IsOutside() {
labelTL := o.GetLabelTopLeft()
if labelTL.Y < highestOutside {
highestOutside = labelTL.Y
}
}
}
if o.IconPosition != nil {
switch label.Position(*o.IconPosition) {
case label.OutsideTopLeft, label.OutsideTopCenter, label.OutsideTopRight:
iconSpace := float64(d2target.MAX_ICON_SIZE + label.PADDING)
if topY-iconSpace < highestOutside {
highestOutside = topY - iconSpace
}
}
}
}
if highestOutside < topY {
occupiedHeight += topY - highestOutside + 2*label.PADDING
}
if occupiedHeight > float64(verticalPadding) {
// if the label doesn't fit within the padding, we need to add more
dy = occupiedHeight - float64(verticalPadding)
obj.Height += dy
}
// we need to center children if we have to expand to fit the container label
if dx != 0 || dy != 0 {
gd.shift(dx, dy)
}
}
if obj.HasLabel() {
obj.LabelPosition = go2.Pointer(string(label.InsideTopCenter))
}
if obj.Icon != nil {
obj.IconPosition = go2.Pointer(string(label.InsideTopLeft))
}
gridDiagrams[obj.AbsID()] = gd
for _, o := range gd.objects {
toRemove[o] = struct{}{}
}
// simple straight line edge routing between grid objects
for i, e := range g.Edges {
edgeOrder[e.AbsID()] = i
if !e.Src.Parent.IsDescendantOf(obj) && !e.Dst.Parent.IsDescendantOf(obj) {
continue
}
// if edge is within grid, remove it from outer layout
gd.edges = append(gd.edges, e)
edgeToRemove[e] = struct{}{}
if e.Src.Parent != obj || e.Dst.Parent != obj {
continue
}
// if edge is grid child, use simple routing
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))
}
}
return nil
}
if len(g.Objects) > 0 {
queue := make([]*d2graph.Object, 1, len(g.Objects))
queue[0] = g.Root
for len(queue) > 0 {
obj := queue[0]
queue = queue[1:]
if len(obj.ChildrenArray) == 0 {
continue
}
if !obj.IsGridDiagram() {
queue = append(queue, obj.ChildrenArray...)
continue
}
if err := processGrid(obj); err != nil {
return nil, nil, nil, err
}
}
}
layoutObjects := make([]*d2graph.Object, 0, len(toRemove))
for _, obj := range g.Objects {
if _, exists := toRemove[obj]; !exists {
layoutObjects = append(layoutObjects, obj)
}
}
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, edgeOrder, nil
}
func layoutGrid(g *d2graph.Graph, obj *d2graph.Object) (*gridDiagram, error) {
gd := newGridDiagram(obj)
@ -1128,57 +871,3 @@ func getDistToTarget(layout [][]*d2graph.Object, targetSize float64, horizontalG
}
return totalDelta
}
// cleanup restores the graph after the core layout engine finishes
// - translating the grid to its position placed by the core layout engine
// - restore the children of the grid
// - sorts objects to their original graph order
func cleanup(graph *d2graph.Graph, gridDiagrams map[string]*gridDiagram, objectsOrder, edgeOrder map[string]int) {
defer func() {
sort.SliceStable(graph.Objects, func(i, j int) bool {
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)
restore = func(obj *d2graph.Object) {
gd, exists := gridDiagrams[obj.AbsID()]
if !exists {
return
}
obj.LabelPosition = go2.Pointer(string(label.InsideTopCenter))
horizontalPadding, verticalPadding := CONTAINER_PADDING, CONTAINER_PADDING
if obj.GridGap != nil || obj.HorizontalGap != nil {
horizontalPadding = gd.horizontalGap
}
if obj.GridGap != nil || obj.VerticalGap != nil {
verticalPadding = gd.verticalGap
}
// shift the grid from (0, 0)
gd.shift(
obj.TopLeft.X+float64(horizontalPadding),
obj.TopLeft.Y+float64(verticalPadding),
)
gd.cleanup(obj, graph)
for _, child := range obj.ChildrenArray {
restore(child)
}
}
if graph.Root.IsGridDiagram() {
gd, exists := gridDiagrams[graph.Root.AbsID()]
if exists {
gd.cleanup(graph.Root, graph)
}
}
for _, obj := range graph.Objects {
restore(obj)
}
}

View file

@ -168,13 +168,13 @@ func LayoutNested(ctx context.Context, g *d2graph.Graph, graphInfo GraphInfo, co
switch graphInfo.DiagramType {
case GridDiagram:
log.Debug(ctx, "layout grid", slog.F("rootlevel", g.RootLevel), slog.F("shapes", g.PrintString()))
if err = d2grid.Layout2(ctx, g); err != nil {
if err = d2grid.Layout(ctx, g); err != nil {
return err
}
case SequenceDiagram:
log.Debug(ctx, "layout sequence", slog.F("rootlevel", g.RootLevel), slog.F("shapes", g.PrintString()))
err = d2sequence.Layout2(ctx, g, coreLayout)
err = d2sequence.Layout(ctx, g, coreLayout)
if err != nil {
return err
}

View file

@ -91,10 +91,6 @@ func Layout(ctx context.Context, g *d2graph.Graph, constantNearGraphs []*d2graph
return nil
}
func Place(obj *d2graph.Object) (float64, float64) {
return place(obj)
}
// place returns the position of obj, taking into consideration its near value and the diagram
func place(obj *d2graph.Object) (float64, float64) {
tl, br := boundingBox(obj.Graph)
@ -149,28 +145,6 @@ func place(obj *d2graph.Object) (float64, float64) {
return x, y
}
// WithoutConstantNears plucks out the graph objects which have "near" set to a constant value
// This is to be called before layout engines so they don't take part in regular positioning
func WithoutConstantNears(ctx context.Context, g *d2graph.Graph) (constantNearGraphs []*d2graph.Graph) {
for i := 0; i < len(g.Objects); i++ {
obj := g.Objects[i]
if obj.NearKey == nil {
continue
}
_, isKey := g.Root.HasChild(d2graph.Key(obj.NearKey))
if isKey {
continue
}
_, isConst := d2graph.NearConstants[d2graph.Key(obj.NearKey)[0]]
if isConst {
tempGraph := g.ExtractAsNestedGraph(obj)
constantNearGraphs = append(constantNearGraphs, tempGraph)
i--
}
}
return constantNearGraphs
}
// boundingBox gets the center of the graph as defined by shapes
// The bounds taking into consideration only shapes gives more of a feeling of true center
// It differs from d2target.BoundingBox which needs to include every visible thing

View file

@ -2,7 +2,6 @@ package d2sequence
import (
"context"
"sort"
"strings"
"oss.terrastruct.com/util-go/go2"
@ -15,32 +14,9 @@ import (
// Layout runs the sequence diagram layout engine on objects of shape sequence_diagram
//
// 1. Traverse graph from root, skip objects with shape not `sequence_diagram`
// 2. Construct a sequence diagram from all descendant objects and edges
// 3. Remove those objects and edges from the main graph
// 4. Run layout on sequence diagrams
// 5. Set the resulting dimensions to the main graph shape
// 6. Run core layouts (still without sequence diagram innards)
// 7. Put back sequence diagram innards in correct location
// 1. Run layout on sequence diagrams
// 2. Set the resulting dimensions to the main graph shape
func Layout(ctx context.Context, g *d2graph.Graph, layout d2graph.LayoutGraph) error {
sequenceDiagrams, objectOrder, edgeOrder, err := WithoutSequenceDiagrams(ctx, g)
if err != nil {
return err
}
if g.Root.IsSequenceDiagram() {
// the sequence diagram is the only layout engine if the whole diagram is
// shape: sequence_diagram
g.Root.TopLeft = geo.NewPoint(0, 0)
} else if err := layout(ctx, g); err != nil {
return err
}
cleanup(g, sequenceDiagrams, objectOrder, edgeOrder)
return nil
}
func Layout2(ctx context.Context, g *d2graph.Graph, layout d2graph.LayoutGraph) error {
// used in layout code
g.Root.Shape.Value = d2target.ShapeSequenceDiagram
@ -84,62 +60,6 @@ func Layout2(ctx context.Context, g *d2graph.Graph, layout d2graph.LayoutGraph)
return nil
}
func WithoutSequenceDiagrams(ctx context.Context, g *d2graph.Graph) (map[string]*sequenceDiagram, map[string]int, map[string]int, error) {
objectsToRemove := make(map[*d2graph.Object]struct{})
edgesToRemove := make(map[*d2graph.Edge]struct{})
sequenceDiagrams := make(map[string]*sequenceDiagram)
if len(g.Objects) > 0 {
queue := make([]*d2graph.Object, 1, len(g.Objects))
queue[0] = g.Root
for len(queue) > 0 {
obj := queue[0]
queue = queue[1:]
if len(obj.ChildrenArray) == 0 {
continue
}
if obj.Shape.Value != d2target.ShapeSequenceDiagram {
queue = append(queue, obj.ChildrenArray...)
continue
}
sd, err := layoutSequenceDiagram(g, obj)
if err != nil {
return nil, nil, nil, err
}
obj.Children = make(map[string]*d2graph.Object)
obj.ChildrenArray = nil
obj.Box = geo.NewBox(nil, sd.getWidth()+GROUP_CONTAINER_PADDING*2, sd.getHeight()+GROUP_CONTAINER_PADDING*2)
obj.LabelPosition = go2.Pointer(string(label.InsideTopCenter))
sequenceDiagrams[obj.AbsID()] = sd
for _, edge := range sd.messages {
edgesToRemove[edge] = struct{}{}
}
for _, obj := range sd.actors {
objectsToRemove[obj] = struct{}{}
}
for _, obj := range sd.notes {
objectsToRemove[obj] = struct{}{}
}
for _, obj := range sd.groups {
objectsToRemove[obj] = struct{}{}
}
for _, obj := range sd.spans {
objectsToRemove[obj] = struct{}{}
}
}
}
layoutEdges, edgeOrder := getLayoutEdges(g, edgesToRemove)
g.Edges = layoutEdges
layoutObjects, objectOrder := getLayoutObjects(g, objectsToRemove)
// TODO this isn't a proper deletion because the objects still appear as children of the object
g.Objects = layoutObjects
return sequenceDiagrams, objectOrder, edgeOrder, nil
}
// layoutSequenceDiagram finds the edges inside the sequence diagram and performs the layout on the object descendants
func layoutSequenceDiagram(g *d2graph.Graph, obj *d2graph.Object) (*sequenceDiagram, error) {
var edges []*d2graph.Edge
@ -157,97 +77,3 @@ func layoutSequenceDiagram(g *d2graph.Graph, obj *d2graph.Object) (*sequenceDiag
err = sd.layout()
return sd, err
}
func getLayoutEdges(g *d2graph.Graph, toRemove map[*d2graph.Edge]struct{}) ([]*d2graph.Edge, map[string]int) {
edgeOrder := make(map[string]int)
layoutEdges := make([]*d2graph.Edge, 0, len(g.Edges)-len(toRemove))
for i, edge := range g.Edges {
edgeOrder[edge.AbsID()] = i
if _, exists := toRemove[edge]; !exists {
layoutEdges = append(layoutEdges, edge)
}
}
return layoutEdges, edgeOrder
}
func getLayoutObjects(g *d2graph.Graph, toRemove map[*d2graph.Object]struct{}) ([]*d2graph.Object, map[string]int) {
objectOrder := make(map[string]int)
layoutObjects := make([]*d2graph.Object, 0, len(toRemove))
for i, obj := range g.Objects {
objectOrder[obj.AbsID()] = i
if _, exists := toRemove[obj]; !exists {
layoutObjects = append(layoutObjects, obj)
}
}
return layoutObjects, objectOrder
}
// cleanup restores the graph after the core layout engine finishes
// - translating the sequence diagram to its position placed by the core layout engine
// - restore the children of the sequence diagram graph object
// - adds the sequence diagram edges (messages) back to the graph
// - adds the sequence diagram lifelines to the graph edges
// - adds the sequence diagram descendants back to the graph objects
// - sorts edges and objects to their original graph order
func cleanup(g *d2graph.Graph, sequenceDiagrams map[string]*sequenceDiagram, objectsOrder, edgesOrder map[string]int) {
var objects []*d2graph.Object
if g.Root.IsSequenceDiagram() {
objects = []*d2graph.Object{g.Root}
} else {
objects = g.Objects
}
for _, obj := range objects {
sd, exists := sequenceDiagrams[obj.AbsID()]
if !exists {
continue
}
obj.LabelPosition = go2.Pointer(string(label.InsideTopCenter))
// 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.messages...)
g.Edges = append(g.Edges, sd.lifelines...)
g.Objects = append(g.Objects, sd.actors...)
g.Objects = append(g.Objects, sd.notes...)
g.Objects = append(g.Objects, sd.groups...)
g.Objects = append(g.Objects, sd.spans...)
}
// no new objects, so just keep the same position
sort.SliceStable(g.Objects, func(i, j int) bool {
return objectsOrder[g.Objects[i].AbsID()] < objectsOrder[g.Objects[j].AbsID()]
})
// sequence diagrams add lifelines, and they must be the last ones in this slice
sort.SliceStable(g.Edges, func(i, j int) bool {
iOrder, iExists := edgesOrder[g.Edges[i].AbsID()]
jOrder, jExists := edgesOrder[g.Edges[j].AbsID()]
if iExists && jExists {
return iOrder < jOrder
} else if iExists && !jExists {
return true
}
// either both don't exist or i doesn't exist and j exists
return false
})
}

View file

@ -12,9 +12,6 @@ import (
"oss.terrastruct.com/d2/d2graph"
"oss.terrastruct.com/d2/d2layouts"
"oss.terrastruct.com/d2/d2layouts/d2dagrelayout"
"oss.terrastruct.com/d2/d2layouts/d2grid"
"oss.terrastruct.com/d2/d2layouts/d2near"
"oss.terrastruct.com/d2/d2layouts/d2sequence"
"oss.terrastruct.com/d2/d2renderers/d2fonts"
"oss.terrastruct.com/d2/d2renderers/d2svg"
"oss.terrastruct.com/d2/d2target"
@ -90,29 +87,6 @@ func compile(ctx context.Context, g *d2graph.Graph, compileOpts *CompileOptions,
if err != nil {
return nil, err
}
if false {
constantNearGraphs := d2near.WithoutConstantNears(ctx, g)
layoutWithGrids := d2grid.Layout(ctx, g, coreLayout)
// run core layout for constantNears
for _, tempGraph := range constantNearGraphs {
if err = layoutWithGrids(ctx, tempGraph); err != nil {
return nil, err
}
}
err = d2sequence.Layout(ctx, g, layoutWithGrids)
if err != nil {
return nil, err
}
err = d2near.Layout(ctx, g, constantNearGraphs)
if err != nil {
return nil, err
}
}
}
d, err := d2exporter.Export(ctx, g, compileOpts.FontFamily)

View file

@ -21,8 +21,6 @@ import (
"oss.terrastruct.com/d2/d2graph"
"oss.terrastruct.com/d2/d2layouts/d2dagrelayout"
"oss.terrastruct.com/d2/d2layouts/d2elklayout"
"oss.terrastruct.com/d2/d2layouts/d2near"
"oss.terrastruct.com/d2/d2layouts/d2sequence"
"oss.terrastruct.com/d2/d2lib"
"oss.terrastruct.com/d2/d2plugin"
"oss.terrastruct.com/d2/d2renderers/d2animate"
@ -108,8 +106,6 @@ func runa(t *testing.T, tcs []testCase) {
// serde exercises serializing and deserializing the graph
// We want to run all the steps leading up to serialization in the course of regular layout
func serde(t *testing.T, tc testCase, ruler *textmeasure.Ruler) {
ctx := context.Background()
ctx = log.WithTB(ctx, t, nil)
g, _, err := d2compiler.Compile("", strings.NewReader(tc.script), &d2compiler.CompileOptions{
UTF16Pos: false,
})
@ -117,8 +113,6 @@ func serde(t *testing.T, tc testCase, ruler *textmeasure.Ruler) {
if len(g.Objects) > 0 {
err = g.SetDimensions(nil, ruler, nil)
trequire.Nil(t, err)
d2near.WithoutConstantNears(ctx, g)
d2sequence.WithoutSequenceDiagrams(ctx, g)
}
b, err := d2graph.SerializeGraph(g)
trequire.Nil(t, err)