diff --git a/d2graph/d2graph.go b/d2graph/d2graph.go index 21562dbfe..8b147bf9f 100644 --- a/d2graph/d2graph.go +++ b/d2graph/d2graph.go @@ -403,10 +403,6 @@ func (obj *Object) IsContainer() bool { return len(obj.Children) > 0 } -func (obj *Object) IsSequenceDiagram() bool { - return obj != nil && obj.Attributes.Shape.Value == d2target.ShapeSequenceDiagram -} - func (obj *Object) AbsID() string { if obj.Parent != nil && obj.Parent.ID != "" { return obj.Parent.AbsID() + "." + obj.ID @@ -715,16 +711,6 @@ func (e *Edge) AbsID() string { return fmt.Sprintf("%s(%s %s %s)[%d]", commonKey, strings.Join(srcIDA, "."), e.ArrowString(), strings.Join(dstIDA, "."), e.Index) } -func (obj *Object) outerSequenceDiagram() *Object { - for obj != nil { - obj = obj.Parent - if obj.IsSequenceDiagram() { - return obj - } - } - return nil -} - func (obj *Object) Connect(srcID, dstID []string, srcArrow, dstArrow bool, label string) (*Edge, error) { srcObj, srcID, err := ResolveUnderscoreKey(srcID, obj) if err != nil { diff --git a/d2graph/seqdiagram.go b/d2graph/seqdiagram.go new file mode 100644 index 000000000..5052f5c45 --- /dev/null +++ b/d2graph/seqdiagram.go @@ -0,0 +1,58 @@ +package d2graph + +import "oss.terrastruct.com/d2/d2target" + +func (obj *Object) IsSequenceDiagram() bool { + return obj != nil && obj.Attributes.Shape.Value == d2target.ShapeSequenceDiagram +} + +func (obj *Object) outerSequenceDiagram() *Object { + for obj != nil { + obj = obj.Parent + if obj.IsSequenceDiagram() { + return obj + } + } + return nil +} + +// notes are descendant of actors with no edges and no children +func (obj *Object) IsSequenceDiagramNote() bool { + sd := obj.outerSequenceDiagram() + if sd == nil { + return false + } + return !obj.hasEdgeRef() && !obj.ContainsAnyEdge(obj.Graph.Edges) && len(obj.ChildrenArray) == 0 +} + +func (obj *Object) hasEdgeRef() bool { + for _, ref := range obj.References { + if ref.MapKey != nil && len(ref.MapKey.Edges) > 0 { + return true + } + } + + return false +} + +func (obj *Object) ContainsAnyEdge(edges []*Edge) bool { + for _, e := range edges { + if e.ContainedBy(obj) { + return true + } + } + return false +} + +func (e *Edge) ContainedBy(obj *Object) bool { + for _, ref := range e.References { + curr := ref.ScopeObj + for curr != nil { + if curr == obj { + return true + } + curr = curr.Parent + } + } + return false +} diff --git a/d2layouts/d2sequence/sequence_diagram.go b/d2layouts/d2sequence/sequence_diagram.go index 359109b47..d4d24e030 100644 --- a/d2layouts/d2sequence/sequence_diagram.go +++ b/d2layouts/d2sequence/sequence_diagram.go @@ -60,38 +60,6 @@ func getEdgeEarliestLineNum(e *d2graph.Edge) int { return min } -func hasEdge(o *d2graph.Object) bool { - for _, ref := range o.References { - if ref.MapKey != nil && len(ref.MapKey.Edges) > 0 { - return true - } - } - - return false -} - -func containsAnyMessage(o *d2graph.Object, messages []*d2graph.Edge) bool { - for _, m := range messages { - if containsMessage(o, m) { - return true - } - } - return false -} - -func containsMessage(o *d2graph.Object, m *d2graph.Edge) bool { - for _, ref := range m.References { - curr := ref.ScopeObj - for curr != nil { - if curr == o { - return true - } - curr = curr.Parent - } - } - return false -} - func newSequenceDiagram(objects []*d2graph.Object, messages []*d2graph.Edge) *sequenceDiagram { var actors []*d2graph.Object var groups []*d2graph.Object @@ -107,7 +75,7 @@ func newSequenceDiagram(objects []*d2graph.Object, messages []*d2graph.Edge) *se hasNote := false for _, ch := range obj.ChildrenArray { // if the child contains a message, it's a span, not a note - if !containsAnyMessage(ch, messages) { + if !ch.ContainsAnyEdge(messages) { hasNote = true break } @@ -161,22 +129,21 @@ func newSequenceDiagram(objects []*d2graph.Object, messages []*d2graph.Edge) *se queue = queue[1:] // spans are children of actors that have edges - // notes are children of actors with no edges and no children // edge groups are children of actors with no edges and children edges - if hasEdge(child) && !containsAnyMessage(child, sd.messages) { - // spans have no labels - // TODO why not? Spans should be able to - child.Attributes.Label = d2graph.Scalar{Value: ""} - child.Attributes.Shape = d2graph.Scalar{Value: shape.SQUARE_TYPE} - sd.spans = append(sd.spans, child) - sd.objectRank[child] = rank - } else { + if child.IsSequenceDiagramNote() { sd.verticalIndices[child.AbsID()] = getObjEarliestLineNum(child) // TODO change to page type when it doesn't look deformed child.Attributes.Shape = d2graph.Scalar{Value: shape.SQUARE_TYPE} sd.notes = append(sd.notes, child) sd.objectRank[child] = rank child.LabelPosition = go2.Pointer(string(label.InsideMiddleCenter)) + } else { + // spans have no labels + // TODO why not? Spans should be able to + child.Attributes.Label = d2graph.Scalar{Value: ""} + child.Attributes.Shape = d2graph.Scalar{Value: shape.SQUARE_TYPE} + sd.spans = append(sd.spans, child) + sd.objectRank[child] = rank } queue = append(queue, child.ChildrenArray...) @@ -233,7 +200,7 @@ func (sd *sequenceDiagram) placeGroup(group *d2graph.Object) { maxY := math.Inf(-1) for _, m := range sd.messages { - if containsMessage(group, m) { + if m.ContainedBy(group) { for _, p := range m.Route { minX = math.Min(minX, p.X) minY = math.Min(minY, p.Y)