diff --git a/d2layouts/d2dagrelayout/layout.go b/d2layouts/d2dagrelayout/layout.go index 7ac2a44e4..201509cee 100644 --- a/d2layouts/d2dagrelayout/layout.go +++ b/d2layouts/d2dagrelayout/layout.go @@ -30,7 +30,10 @@ var setupJS string //go:embed dagre.js var dagreJS string -const MIN_SEGMENT_LEN = 10 +const ( + MIN_SEGMENT_LEN = 10 + MIN_RANK_SEP = 100 +) type ConfigurableOpts struct { NodeSep int `json:"nodesep"` @@ -112,7 +115,7 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err } maxLabelSize = go2.Max(maxLabelSize, size) } - rootAttrs.ranksep = go2.Max(100, maxLabelSize+40) + rootAttrs.ranksep = go2.Max(MIN_RANK_SEP, maxLabelSize+40) configJS := setGraphAttrs(rootAttrs) if _, err := vm.RunString(configJS); err != nil { diff --git a/d2layouts/d2elklayout/layout.go b/d2layouts/d2elklayout/layout.go index 909a7eab1..671fc2790 100644 --- a/d2layouts/d2elklayout/layout.go +++ b/d2layouts/d2elklayout/layout.go @@ -132,7 +132,7 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err elkGraph := &ELKGraph{ ID: "root", LayoutOptions: &elkOpts{ - Thoroughness: 20, + Thoroughness: 8, EdgeEdgeBetweenLayersSpacing: 50, HierarchyHandling: "INCLUDE_CHILDREN", ConsiderModelOrder: "NODES_AND_EDGES", @@ -188,7 +188,7 @@ func Layout(ctx context.Context, g *d2graph.Graph, opts *ConfigurableOpts) (err if len(obj.ChildrenArray) > 0 { n.LayoutOptions = &elkOpts{ ForceNodeModelOrder: true, - Thoroughness: 20, + Thoroughness: 8, EdgeEdgeBetweenLayersSpacing: 50, HierarchyHandling: "INCLUDE_CHILDREN", ConsiderModelOrder: "NODES_AND_EDGES", diff --git a/d2layouts/d2sequence/constants.go b/d2layouts/d2sequence/constants.go index 95de80681..690c54ecc 100644 --- a/d2layouts/d2sequence/constants.go +++ b/d2layouts/d2sequence/constants.go @@ -1,21 +1,21 @@ package d2sequence -// leaves at least 25 units of space on the left/right when computing the space required between actors -const HORIZONTAL_PAD = 50. +const HORIZONTAL_PAD = 40. -// leaves at least 25 units of space on the top/bottom when computing the space required between messages -const VERTICAL_PAD = 50. +const VERTICAL_PAD = 20. -const MIN_ACTOR_DISTANCE = 250. +const MIN_ACTOR_DISTANCE = 150. -const MIN_ACTOR_WIDTH = 150. +const MIN_ACTOR_WIDTH = 100. -const SELF_MESSAGE_HORIZONTAL_TRAVEL = 100. +const SELF_MESSAGE_HORIZONTAL_TRAVEL = 74 const GROUP_CONTAINER_PADDING = 24. +const GROUP_LABEL_PADDING = 20 + // min vertical distance between messages -const MIN_MESSAGE_DISTANCE = 80. +const MIN_MESSAGE_DISTANCE = 40. // default size const SPAN_BASE_WIDTH = 12. @@ -24,13 +24,13 @@ const SPAN_BASE_WIDTH = 12. const SPAN_DEPTH_GROWTH_FACTOR = 8. // when a span has a single messages -const MIN_SPAN_HEIGHT = 80. +const MIN_SPAN_HEIGHT = 60. const SPAN_MESSAGE_PAD = 16. const LIFELINE_STROKE_WIDTH int = 2 -const LIFELINE_STROKE_DASH int = 6 +const LIFELINE_STROKE_DASH int = 4 // pad when the actor has the label placed OutsideMiddleBottom so that the lifeline is not so close to the text const LIFELINE_LABEL_PAD = 5. diff --git a/d2layouts/d2sequence/sequence_diagram.go b/d2layouts/d2sequence/sequence_diagram.go index b2cbc5481..46e978cab 100644 --- a/d2layouts/d2sequence/sequence_diagram.go +++ b/d2layouts/d2sequence/sequence_diagram.go @@ -217,11 +217,55 @@ func (sd *sequenceDiagram) placeGroup(group *d2graph.Object) { maxX := math.Inf(-1) maxY := math.Inf(-1) + labelHeight := 0 + if group.LabelHeight != nil { + labelHeight = *group.LabelHeight + } + padBelow := float64(labelHeight + GROUP_LABEL_PADDING) + + // Make sure the label height fits + line := getObjEarliestLineNum(group) + for _, m := range sd.messages { + if getEdgeEarliestLineNum(m) > line { + for _, p := range m.Route { + p.Y += padBelow + } + for _, s := range sd.spans { + if getObjEarliestLineNum(s) >= line { + continue + } + if m.Src == s || m.Dst == s { + s.Height += padBelow + break + } + } + } + } + for _, n := range sd.notes { + if getObjEarliestLineNum(n) > line { + n.TopLeft.Y += padBelow + } + } + for _, s := range sd.spans { + if getObjEarliestLineNum(s) > line { + s.TopLeft.Y += padBelow + } + } + + for _, g := range sd.groups { + if g.Box == nil || g.Box.TopLeft == nil { + continue + } + if getObjEarliestLineNum(g) > line { + g.TopLeft.Y += padBelow + } + } + for _, m := range sd.messages { if m.ContainedBy(group) { for _, p := range m.Route { minX = math.Min(minX, p.X-HORIZONTAL_PAD) - minY = math.Min(minY, p.Y-MIN_MESSAGE_DISTANCE/2.) + minY = math.Min(minY, p.Y-math.Max(MIN_MESSAGE_DISTANCE/2., float64(labelHeight+GROUP_LABEL_PADDING))) maxX = math.Max(maxX, p.X+HORIZONTAL_PAD) maxY = math.Max(maxY, p.Y+MIN_MESSAGE_DISTANCE/2.) } @@ -245,9 +289,9 @@ func (sd *sequenceDiagram) placeGroup(group *d2graph.Object) { } if inGroup { minX = math.Min(minX, n.TopLeft.X-HORIZONTAL_PAD) - minY = math.Min(minY, n.TopLeft.Y-MIN_MESSAGE_DISTANCE/2.) - maxY = math.Max(maxY, n.TopLeft.Y+n.Height+HORIZONTAL_PAD) - maxX = math.Max(maxX, n.TopLeft.X+n.Width+MIN_MESSAGE_DISTANCE/2.) + minY = math.Min(minY, n.TopLeft.Y-math.Max(MIN_MESSAGE_DISTANCE/2., float64(labelHeight+GROUP_LABEL_PADDING))) + maxX = math.Max(maxX, n.TopLeft.X+n.Width+HORIZONTAL_PAD) + maxY = math.Max(maxY, n.TopLeft.Y+n.Height+MIN_MESSAGE_DISTANCE/2.) } } @@ -255,7 +299,7 @@ func (sd *sequenceDiagram) placeGroup(group *d2graph.Object) { for _, g := range sd.groups { if ch == g { minX = math.Min(minX, ch.TopLeft.X-GROUP_CONTAINER_PADDING) - minY = math.Min(minY, ch.TopLeft.Y-GROUP_CONTAINER_PADDING) + minY = math.Min(minY, ch.TopLeft.Y-math.Max(GROUP_CONTAINER_PADDING, float64(labelHeight+GROUP_LABEL_PADDING))) maxX = math.Max(maxX, ch.TopLeft.X+ch.Width+GROUP_CONTAINER_PADDING) maxY = math.Max(maxY, ch.TopLeft.Y+ch.Height+GROUP_CONTAINER_PADDING) break @@ -263,6 +307,17 @@ func (sd *sequenceDiagram) placeGroup(group *d2graph.Object) { } } + // for _, g := range sd.groups { + // if g.Box == nil || g.TopLeft == nil { + // continue + // } + // + // if g.Parent != group.Parent { + // continue + // } + // minY = math.Max(minY, g.TopLeft.Y+g.Height+GROUP_CONTAINER_PADDING) + // } + group.Box = geo.NewBox( geo.NewPoint( minX,