Merge pull request #336 from ejulio-ts/sequence-diagram-self-edges
sequence diagram: self edges
This commit is contained in:
commit
b07fe2b956
12 changed files with 1630 additions and 80 deletions
|
|
@ -37,7 +37,10 @@ func Layout(ctx context.Context, g *d2graph.Graph, layout func(ctx context.Conte
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
sd := layoutSequenceDiagram(g, obj)
|
sd, err := layoutSequenceDiagram(g, obj)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
obj.Children = make(map[string]*d2graph.Object)
|
obj.Children = make(map[string]*d2graph.Object)
|
||||||
obj.ChildrenArray = nil
|
obj.ChildrenArray = nil
|
||||||
obj.Box = geo.NewBox(nil, sd.getWidth(), sd.getHeight())
|
obj.Box = geo.NewBox(nil, sd.getWidth(), sd.getHeight())
|
||||||
|
|
@ -76,7 +79,7 @@ func Layout(ctx context.Context, g *d2graph.Graph, layout func(ctx context.Conte
|
||||||
}
|
}
|
||||||
|
|
||||||
// layoutSequenceDiagram finds the edges inside the sequence diagram and performs the layout on the object descendants
|
// 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 {
|
func layoutSequenceDiagram(g *d2graph.Graph, obj *d2graph.Object) (*sequenceDiagram, error) {
|
||||||
var edges []*d2graph.Edge
|
var edges []*d2graph.Edge
|
||||||
for _, edge := range g.Edges {
|
for _, edge := range g.Edges {
|
||||||
// both Src and Dst must be inside the sequence diagram
|
// both Src and Dst must be inside the sequence diagram
|
||||||
|
|
@ -86,8 +89,8 @@ func layoutSequenceDiagram(g *d2graph.Graph, obj *d2graph.Object) *sequenceDiagr
|
||||||
}
|
}
|
||||||
|
|
||||||
sd := newSequenceDiagram(obj.ChildrenArray, edges)
|
sd := newSequenceDiagram(obj.ChildrenArray, edges)
|
||||||
sd.layout()
|
err := sd.layout()
|
||||||
return sd
|
return sd, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func getLayoutEdges(g *d2graph.Graph, toRemove map[*d2graph.Edge]struct{}) ([]*d2graph.Edge, map[string]int) {
|
func getLayoutEdges(g *d2graph.Graph, toRemove map[*d2graph.Edge]struct{}) ([]*d2graph.Edge, map[string]int) {
|
||||||
|
|
|
||||||
|
|
@ -159,6 +159,7 @@ func TestSpansSequenceDiagram(t *testing.T) {
|
||||||
// ├┐──────────────────────►
|
// ├┐──────────────────────►
|
||||||
// t2 ││ │
|
// t2 ││ │
|
||||||
// ├┘◄─────────────────────┤
|
// ├┘◄─────────────────────┤
|
||||||
|
|
||||||
input := `
|
input := `
|
||||||
shape: sequence_diagram
|
shape: sequence_diagram
|
||||||
a: { shape: person }
|
a: { shape: person }
|
||||||
|
|
@ -182,7 +183,6 @@ b -> a.t2`
|
||||||
|
|
||||||
a, has := g.Root.HasChild([]string{"a"})
|
a, has := g.Root.HasChild([]string{"a"})
|
||||||
assert.True(t, has)
|
assert.True(t, has)
|
||||||
a.Box = geo.NewBox(nil, 100, 100)
|
|
||||||
|
|
||||||
a_t1, has := a.HasChild([]string{"t1"})
|
a_t1, has := a.HasChild([]string{"t1"})
|
||||||
assert.True(t, has)
|
assert.True(t, has)
|
||||||
|
|
@ -197,6 +197,12 @@ b -> a.t2`
|
||||||
b_t1, has := b.HasChild([]string{"t1"})
|
b_t1, has := b.HasChild([]string{"t1"})
|
||||||
assert.True(t, has)
|
assert.True(t, has)
|
||||||
|
|
||||||
|
a.Box = geo.NewBox(nil, 100, 100)
|
||||||
|
a_t1.Box = geo.NewBox(nil, 100, 100)
|
||||||
|
a_t2.Box = geo.NewBox(nil, 100, 100)
|
||||||
|
b.Box = geo.NewBox(nil, 30, 30)
|
||||||
|
b_t1.Box = geo.NewBox(nil, 100, 100)
|
||||||
|
|
||||||
d2sequence.Layout(ctx, g, func(ctx context.Context, g *d2graph.Graph) error {
|
d2sequence.Layout(ctx, g, func(ctx context.Context, g *d2graph.Graph) error {
|
||||||
// just set some position as if it had been properly placed
|
// just set some position as if it had been properly placed
|
||||||
for _, obj := range g.Objects {
|
for _, obj := range g.Objects {
|
||||||
|
|
@ -304,6 +310,7 @@ container -> c: edge 1
|
||||||
|
|
||||||
a_t1, has := a.HasChild([]string{"t1"})
|
a_t1, has := a.HasChild([]string{"t1"})
|
||||||
assert.True(t, has)
|
assert.True(t, has)
|
||||||
|
a_t1.Box = geo.NewBox(nil, 100, 100)
|
||||||
|
|
||||||
b, has := container.HasChild([]string{"b"})
|
b, has := container.HasChild([]string{"b"})
|
||||||
assert.True(t, has)
|
assert.True(t, has)
|
||||||
|
|
@ -311,6 +318,7 @@ container -> c: edge 1
|
||||||
|
|
||||||
b_t1, has := b.HasChild([]string{"t1"})
|
b_t1, has := b.HasChild([]string{"t1"})
|
||||||
assert.True(t, has)
|
assert.True(t, has)
|
||||||
|
b_t1.Box = geo.NewBox(nil, 100, 100)
|
||||||
|
|
||||||
c := g.Root.EnsureChild([]string{"c"})
|
c := g.Root.EnsureChild([]string{"c"})
|
||||||
c.Box = geo.NewBox(nil, 100, 100)
|
c.Box = geo.NewBox(nil, 100, 100)
|
||||||
|
|
@ -366,3 +374,90 @@ container -> c: edge 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSelfEdges(t *testing.T) {
|
||||||
|
g := d2graph.NewGraph(nil)
|
||||||
|
g.Root.Attributes.Shape = d2graph.Scalar{Value: d2target.ShapeSequenceDiagram}
|
||||||
|
n1 := g.Root.EnsureChild([]string{"n1"})
|
||||||
|
n1.Box = geo.NewBox(nil, 100, 100)
|
||||||
|
|
||||||
|
g.Edges = []*d2graph.Edge{
|
||||||
|
{
|
||||||
|
Src: n1,
|
||||||
|
Dst: n1,
|
||||||
|
Index: 0,
|
||||||
|
Attributes: d2graph.Attributes{
|
||||||
|
Label: d2graph.Scalar{Value: "left to right"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := log.WithTB(context.Background(), t, nil)
|
||||||
|
Layout(ctx, g, func(ctx context.Context, g *d2graph.Graph) error {
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
route := g.Edges[0].Route
|
||||||
|
if len(route) != 4 {
|
||||||
|
t.Fatalf("expected route to have 4 points, got %d", len(route))
|
||||||
|
}
|
||||||
|
|
||||||
|
if route[0].X != route[3].X {
|
||||||
|
t.Fatalf("route does not end at the same actor, start at %.5f, end at %.5f", route[0].X, route[3].X)
|
||||||
|
}
|
||||||
|
|
||||||
|
if route[3].Y-route[0].Y != MIN_MESSAGE_DISTANCE {
|
||||||
|
t.Fatalf("expected route height to be %.f5, got %.5f", MIN_MESSAGE_DISTANCE, route[3].Y-route[0].Y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSequenceToDescendant(t *testing.T) {
|
||||||
|
g := d2graph.NewGraph(nil)
|
||||||
|
g.Root.Attributes.Shape = d2graph.Scalar{Value: d2target.ShapeSequenceDiagram}
|
||||||
|
a := g.Root.EnsureChild([]string{"a"})
|
||||||
|
a.Box = geo.NewBox(nil, 100, 100)
|
||||||
|
a.Attributes = d2graph.Attributes{
|
||||||
|
Shape: d2graph.Scalar{Value: shape.PERSON_TYPE},
|
||||||
|
}
|
||||||
|
a_t1 := a.EnsureChild([]string{"t1"})
|
||||||
|
a_t1.Box = geo.NewBox(nil, 16, 80)
|
||||||
|
|
||||||
|
g.Edges = []*d2graph.Edge{
|
||||||
|
{
|
||||||
|
Src: a,
|
||||||
|
Dst: a_t1,
|
||||||
|
Index: 0,
|
||||||
|
}, {
|
||||||
|
Src: a_t1,
|
||||||
|
Dst: a,
|
||||||
|
Index: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := log.WithTB(context.Background(), t, nil)
|
||||||
|
Layout(ctx, g, func(ctx context.Context, g *d2graph.Graph) error {
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
route1 := g.Edges[0].Route
|
||||||
|
if len(route1) != 4 {
|
||||||
|
t.Fatal("expected route with 4 points")
|
||||||
|
}
|
||||||
|
if route1[0].X != a.Center().X {
|
||||||
|
t.Fatal("expected route to start at `a` lifeline")
|
||||||
|
}
|
||||||
|
if route1[3].X != a_t1.TopLeft.X+a_t1.Width {
|
||||||
|
t.Fatal("expected route to end at `a.t1` right side")
|
||||||
|
}
|
||||||
|
|
||||||
|
route2 := g.Edges[1].Route
|
||||||
|
if len(route2) != 4 {
|
||||||
|
t.Fatal("expected route with 4 points")
|
||||||
|
}
|
||||||
|
if route2[0].X != a_t1.TopLeft.X+a_t1.Width {
|
||||||
|
t.Fatal("expected route to start at `a.t1` right side")
|
||||||
|
}
|
||||||
|
if route2[3].X != a.Center().X {
|
||||||
|
t.Fatal("expected route to end at `a` lifeline")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"oss.terrastruct.com/util-go/go2"
|
"oss.terrastruct.com/util-go/go2"
|
||||||
|
|
||||||
|
|
@ -28,9 +29,8 @@ type sequenceDiagram struct {
|
||||||
objectRank map[*d2graph.Object]int
|
objectRank map[*d2graph.Object]int
|
||||||
|
|
||||||
// keep track of the first and last message of a given actor/span
|
// keep track of the first and last message of a given actor/span
|
||||||
// the message rank is the order in which it appears from top to bottom
|
firstMessage map[*d2graph.Object]*d2graph.Edge
|
||||||
minMessageRank map[*d2graph.Object]int
|
lastMessage map[*d2graph.Object]*d2graph.Edge
|
||||||
maxMessageRank map[*d2graph.Object]int
|
|
||||||
|
|
||||||
yStep float64
|
yStep float64
|
||||||
actorXStep float64
|
actorXStep float64
|
||||||
|
|
@ -137,8 +137,8 @@ func newSequenceDiagram(objects []*d2graph.Object, messages []*d2graph.Edge) *se
|
||||||
notes: nil,
|
notes: nil,
|
||||||
lifelines: nil,
|
lifelines: nil,
|
||||||
objectRank: make(map[*d2graph.Object]int),
|
objectRank: make(map[*d2graph.Object]int),
|
||||||
minMessageRank: make(map[*d2graph.Object]int),
|
firstMessage: make(map[*d2graph.Object]*d2graph.Edge),
|
||||||
maxMessageRank: make(map[*d2graph.Object]int),
|
lastMessage: make(map[*d2graph.Object]*d2graph.Edge),
|
||||||
yStep: MIN_MESSAGE_DISTANCE,
|
yStep: MIN_MESSAGE_DISTANCE,
|
||||||
actorXStep: MIN_ACTOR_DISTANCE,
|
actorXStep: MIN_ACTOR_DISTANCE,
|
||||||
maxActorHeight: 0.,
|
maxActorHeight: 0.,
|
||||||
|
|
@ -185,18 +185,28 @@ func newSequenceDiagram(objects []*d2graph.Object, messages []*d2graph.Edge) *se
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for rank, message := range sd.messages {
|
for _, message := range sd.messages {
|
||||||
sd.verticalIndices[message.AbsID()] = getEdgeEarliestLineNum(message)
|
sd.verticalIndices[message.AbsID()] = getEdgeEarliestLineNum(message)
|
||||||
sd.yStep = math.Max(sd.yStep, float64(message.LabelDimensions.Height))
|
sd.yStep = math.Max(sd.yStep, float64(message.LabelDimensions.Height))
|
||||||
|
|
||||||
sd.setMinMaxMessageRank(message.Src, rank)
|
|
||||||
sd.setMinMaxMessageRank(message.Dst, rank)
|
|
||||||
|
|
||||||
// ensures that long labels, spanning over multiple actors, don't make for large gaps between actors
|
// ensures that long labels, spanning over multiple actors, don't make for large gaps between actors
|
||||||
// by distributing the label length across the actors rank difference
|
// by distributing the label length across the actors rank difference
|
||||||
rankDiff := math.Abs(float64(sd.objectRank[message.Src]) - float64(sd.objectRank[message.Dst]))
|
rankDiff := math.Abs(float64(sd.objectRank[message.Src]) - float64(sd.objectRank[message.Dst]))
|
||||||
distributedLabelWidth := float64(message.LabelDimensions.Width) / rankDiff
|
if rankDiff != 0 {
|
||||||
sd.actorXStep = math.Max(sd.actorXStep, distributedLabelWidth+HORIZONTAL_PAD)
|
// rankDiff = 0 for self edges
|
||||||
|
distributedLabelWidth := float64(message.LabelDimensions.Width) / rankDiff
|
||||||
|
sd.actorXStep = math.Max(sd.actorXStep, distributedLabelWidth+HORIZONTAL_PAD)
|
||||||
|
|
||||||
|
}
|
||||||
|
sd.lastMessage[message.Src] = message
|
||||||
|
if _, exists := sd.firstMessage[message.Src]; !exists {
|
||||||
|
sd.firstMessage[message.Src] = message
|
||||||
|
}
|
||||||
|
sd.lastMessage[message.Dst] = message
|
||||||
|
if _, exists := sd.firstMessage[message.Dst]; !exists {
|
||||||
|
sd.firstMessage[message.Dst] = message
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sd.yStep += VERTICAL_PAD
|
sd.yStep += VERTICAL_PAD
|
||||||
|
|
@ -208,23 +218,17 @@ func newSequenceDiagram(objects []*d2graph.Object, messages []*d2graph.Edge) *se
|
||||||
return sd
|
return sd
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sd *sequenceDiagram) setMinMaxMessageRank(actor *d2graph.Object, rank int) {
|
func (sd *sequenceDiagram) layout() error {
|
||||||
if minRank, exists := sd.minMessageRank[actor]; exists {
|
|
||||||
sd.minMessageRank[actor] = go2.IntMin(minRank, rank)
|
|
||||||
} else {
|
|
||||||
sd.minMessageRank[actor] = rank
|
|
||||||
}
|
|
||||||
|
|
||||||
sd.maxMessageRank[actor] = go2.IntMax(sd.maxMessageRank[actor], rank)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sd *sequenceDiagram) layout() {
|
|
||||||
sd.placeActors()
|
sd.placeActors()
|
||||||
sd.placeSpans()
|
|
||||||
sd.placeNotes()
|
sd.placeNotes()
|
||||||
sd.routeMessages()
|
if err := sd.routeMessages(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
sd.placeSpans()
|
||||||
|
sd.adjustRouteEndpoints()
|
||||||
sd.placeGroups()
|
sd.placeGroups()
|
||||||
sd.addLifelineEdges()
|
sd.addLifelineEdges()
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sd *sequenceDiagram) placeGroups() {
|
func (sd *sequenceDiagram) placeGroups() {
|
||||||
|
|
@ -313,11 +317,10 @@ func (sd *sequenceDiagram) placeActors() {
|
||||||
// │
|
// │
|
||||||
// │
|
// │
|
||||||
func (sd *sequenceDiagram) addLifelineEdges() {
|
func (sd *sequenceDiagram) addLifelineEdges() {
|
||||||
|
lastRoute := sd.messages[len(sd.messages)-1].Route
|
||||||
endY := 0.
|
endY := 0.
|
||||||
for _, m := range sd.messages {
|
for _, p := range lastRoute {
|
||||||
for _, p := range m.Route {
|
endY = math.Max(endY, p.Y)
|
||||||
endY = math.Max(endY, p.Y)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for _, note := range sd.notes {
|
for _, note := range sd.notes {
|
||||||
endY = math.Max(endY, note.TopLeft.Y+note.Height)
|
endY = math.Max(endY, note.TopLeft.Y+note.Height)
|
||||||
|
|
@ -415,12 +418,21 @@ func (sd *sequenceDiagram) placeSpans() {
|
||||||
|
|
||||||
// finds the position if there are messages to this span
|
// finds the position if there are messages to this span
|
||||||
minMessageY := math.Inf(1)
|
minMessageY := math.Inf(1)
|
||||||
if minRank, exists := sd.minMessageRank[span]; exists {
|
if firstMessage, exists := sd.firstMessage[span]; exists {
|
||||||
minMessageY = sd.getMessageY(minRank)
|
// needs to check Src/Dst because of self-edges or edges to/from descendants
|
||||||
|
if span == firstMessage.Src {
|
||||||
|
minMessageY = firstMessage.Route[0].Y
|
||||||
|
} else {
|
||||||
|
minMessageY = firstMessage.Route[len(firstMessage.Route)-1].Y
|
||||||
|
}
|
||||||
}
|
}
|
||||||
maxMessageY := math.Inf(-1)
|
maxMessageY := math.Inf(-1)
|
||||||
if maxRank, exists := sd.maxMessageRank[span]; exists {
|
if lastMessage, exists := sd.lastMessage[span]; exists {
|
||||||
maxMessageY = sd.getMessageY(maxRank)
|
if span == lastMessage.Src {
|
||||||
|
maxMessageY = lastMessage.Route[0].Y
|
||||||
|
} else {
|
||||||
|
maxMessageY = lastMessage.Route[len(lastMessage.Route)-1].Y
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if it is the same as the child top left, add some padding
|
// if it is the same as the child top left, add some padding
|
||||||
|
|
@ -442,52 +454,89 @@ func (sd *sequenceDiagram) placeSpans() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// routeMessages routes horizontal edges (messages) from Src to Dst
|
// routeMessages routes horizontal edges (messages) from Src to Dst lifeline (actor/span center)
|
||||||
func (sd *sequenceDiagram) routeMessages() {
|
// in another step, routes are adjusted to spans borders when necessary
|
||||||
for rank, message := range sd.messages {
|
func (sd *sequenceDiagram) routeMessages() error {
|
||||||
message.ZIndex = 2
|
messageOffset := sd.maxActorHeight + sd.yStep
|
||||||
isLeftToRight := message.Src.TopLeft.X < message.Dst.TopLeft.X
|
for _, message := range sd.messages {
|
||||||
|
noteOffset := 0.
|
||||||
// finds the proper anchor point based on the message direction
|
|
||||||
var startX, endX float64
|
|
||||||
if sd.isActor(message.Src) {
|
|
||||||
startX = message.Src.Center().X
|
|
||||||
} else if isLeftToRight {
|
|
||||||
startX = message.Src.TopLeft.X + message.Src.Width
|
|
||||||
} else {
|
|
||||||
startX = message.Src.TopLeft.X
|
|
||||||
}
|
|
||||||
|
|
||||||
if sd.isActor(message.Dst) {
|
|
||||||
endX = message.Dst.Center().X
|
|
||||||
} else if isLeftToRight {
|
|
||||||
endX = message.Dst.TopLeft.X
|
|
||||||
} else {
|
|
||||||
endX = message.Dst.TopLeft.X + message.Dst.Width
|
|
||||||
}
|
|
||||||
|
|
||||||
messageY := sd.getMessageY(rank)
|
|
||||||
|
|
||||||
for _, note := range sd.notes {
|
for _, note := range sd.notes {
|
||||||
if sd.verticalIndices[note.AbsID()] < sd.verticalIndices[message.AbsID()] {
|
if sd.verticalIndices[note.AbsID()] < sd.verticalIndices[message.AbsID()] {
|
||||||
messageY += note.Height + sd.yStep
|
noteOffset += note.Height + sd.yStep
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
startY := messageOffset + noteOffset
|
||||||
|
|
||||||
message.Route = []*geo.Point{
|
message.ZIndex = 2
|
||||||
geo.NewPoint(startX, messageY),
|
var startX, endX float64
|
||||||
geo.NewPoint(endX, messageY),
|
if startCenter := getCenter(message.Src); startCenter != nil {
|
||||||
|
startX = startCenter.X
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("could not find center of %s", message.Src.AbsID())
|
||||||
}
|
}
|
||||||
|
if endCenter := getCenter(message.Dst); endCenter != nil {
|
||||||
|
endX = endCenter.X
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("could not find center of %s", message.Dst.AbsID())
|
||||||
|
}
|
||||||
|
isToDescendant := strings.HasPrefix(message.Dst.AbsID(), message.Src.AbsID())
|
||||||
|
isFromDescendant := strings.HasPrefix(message.Src.AbsID(), message.Dst.AbsID())
|
||||||
|
isSelfMessage := message.Src == message.Dst
|
||||||
|
|
||||||
|
if isSelfMessage || isToDescendant || isFromDescendant {
|
||||||
|
midX := startX + MIN_MESSAGE_DISTANCE
|
||||||
|
endY := startY + MIN_MESSAGE_DISTANCE
|
||||||
|
message.Route = []*geo.Point{
|
||||||
|
geo.NewPoint(startX, startY),
|
||||||
|
geo.NewPoint(midX, startY),
|
||||||
|
geo.NewPoint(midX, endY),
|
||||||
|
geo.NewPoint(endX, endY),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
message.Route = []*geo.Point{
|
||||||
|
geo.NewPoint(startX, startY),
|
||||||
|
geo.NewPoint(endX, startY),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
messageOffset += sd.yStep
|
||||||
|
|
||||||
if message.Attributes.Label.Value != "" {
|
if message.Attributes.Label.Value != "" {
|
||||||
message.LabelPosition = go2.Pointer(string(label.InsideMiddleCenter))
|
message.LabelPosition = go2.Pointer(string(label.InsideMiddleCenter))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sd *sequenceDiagram) getMessageY(rank int) float64 {
|
func getCenter(obj *d2graph.Object) *geo.Point {
|
||||||
// +1 so that the first message has the top padding for its label
|
if obj == nil {
|
||||||
return ((float64(rank) + 1.) * sd.yStep) + sd.maxActorHeight
|
return nil
|
||||||
|
} else if obj.TopLeft != nil {
|
||||||
|
return obj.Center()
|
||||||
|
}
|
||||||
|
return getCenter(obj.Parent)
|
||||||
|
}
|
||||||
|
|
||||||
|
// adjustRouteEndpoints adjust the first and last points of message routes when they are spans
|
||||||
|
// routeMessages() will route to the actor lifelife as a reference point and this function
|
||||||
|
// adjust to span width when necessary
|
||||||
|
func (sd *sequenceDiagram) adjustRouteEndpoints() {
|
||||||
|
for _, message := range sd.messages {
|
||||||
|
route := message.Route
|
||||||
|
if !sd.isActor(message.Src) {
|
||||||
|
if sd.objectRank[message.Src] <= sd.objectRank[message.Dst] {
|
||||||
|
route[0].X += message.Src.Width / 2.
|
||||||
|
} else {
|
||||||
|
route[0].X -= message.Src.Width / 2.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !sd.isActor(message.Dst) {
|
||||||
|
if sd.objectRank[message.Src] < sd.objectRank[message.Dst] {
|
||||||
|
route[len(route)-1].X -= message.Dst.Width / 2.
|
||||||
|
} else {
|
||||||
|
route[len(route)-1].X += message.Dst.Width / 2.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sd *sequenceDiagram) isActor(obj *d2graph.Object) bool {
|
func (sd *sequenceDiagram) isActor(obj *d2graph.Object) bool {
|
||||||
|
|
@ -501,8 +550,7 @@ func (sd *sequenceDiagram) getWidth() float64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sd *sequenceDiagram) getHeight() float64 {
|
func (sd *sequenceDiagram) getHeight() float64 {
|
||||||
// the layout is always placed starting at 0, so the height is just the last message
|
return sd.lifelines[0].Route[1].Y
|
||||||
return sd.getMessageY(len(sd.messages))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sd *sequenceDiagram) shift(tl *geo.Point) {
|
func (sd *sequenceDiagram) shift(tl *geo.Point) {
|
||||||
|
|
|
||||||
|
|
@ -1325,6 +1325,16 @@ s -> t`,
|
||||||
z -> y
|
z -> y
|
||||||
z -> z: hello
|
z -> z: hello
|
||||||
`,
|
`,
|
||||||
|
}, {
|
||||||
|
name: "sequence_diagram_self_edges",
|
||||||
|
script: `shape: sequence_diagram
|
||||||
|
a -> a: a self edge here
|
||||||
|
a -> b: between actors
|
||||||
|
b -> b.1: to descendant
|
||||||
|
b.1 -> b.1.2: to deeper descendant
|
||||||
|
b.1.2 -> b: to parent
|
||||||
|
b -> a.1.2: actor
|
||||||
|
a.1 -> b.3`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "icon-label",
|
name: "icon-label",
|
||||||
|
|
|
||||||
6
e2etests/testdata/stable/sequence_diagram_real/dagre/board.exp.json
generated
vendored
6
e2etests/testdata/stable/sequence_diagram_real/dagre/board.exp.json
generated
vendored
|
|
@ -9,7 +9,7 @@
|
||||||
"y": 0
|
"y": 0
|
||||||
},
|
},
|
||||||
"width": 3633,
|
"width": 3633,
|
||||||
"height": 2055,
|
"height": 2311,
|
||||||
"opacity": 1,
|
"opacity": 1,
|
||||||
"strokeDash": 0,
|
"strokeDash": 0,
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
|
|
@ -357,7 +357,7 @@
|
||||||
"type": "rectangle",
|
"type": "rectangle",
|
||||||
"pos": {
|
"pos": {
|
||||||
"x": 1304,
|
"x": 1304,
|
||||||
"y": 869
|
"y": 1125
|
||||||
},
|
},
|
||||||
"width": 20,
|
"width": 20,
|
||||||
"height": 422,
|
"height": 422,
|
||||||
|
|
@ -473,7 +473,7 @@
|
||||||
"type": "rectangle",
|
"type": "rectangle",
|
||||||
"pos": {
|
"pos": {
|
||||||
"x": 1727,
|
"x": 1727,
|
||||||
"y": 1649
|
"y": 1905
|
||||||
},
|
},
|
||||||
"width": 20,
|
"width": 20,
|
||||||
"height": 292,
|
"height": 292,
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 479 KiB After Width: | Height: | Size: 479 KiB |
6
e2etests/testdata/stable/sequence_diagram_real/elk/board.exp.json
generated
vendored
6
e2etests/testdata/stable/sequence_diagram_real/elk/board.exp.json
generated
vendored
|
|
@ -9,7 +9,7 @@
|
||||||
"y": 12
|
"y": 12
|
||||||
},
|
},
|
||||||
"width": 3633,
|
"width": 3633,
|
||||||
"height": 2055,
|
"height": 2311,
|
||||||
"opacity": 1,
|
"opacity": 1,
|
||||||
"strokeDash": 0,
|
"strokeDash": 0,
|
||||||
"strokeWidth": 2,
|
"strokeWidth": 2,
|
||||||
|
|
@ -357,7 +357,7 @@
|
||||||
"type": "rectangle",
|
"type": "rectangle",
|
||||||
"pos": {
|
"pos": {
|
||||||
"x": 1316,
|
"x": 1316,
|
||||||
"y": 881
|
"y": 1137
|
||||||
},
|
},
|
||||||
"width": 20,
|
"width": 20,
|
||||||
"height": 422,
|
"height": 422,
|
||||||
|
|
@ -473,7 +473,7 @@
|
||||||
"type": "rectangle",
|
"type": "rectangle",
|
||||||
"pos": {
|
"pos": {
|
||||||
"x": 1739,
|
"x": 1739,
|
||||||
"y": 1661
|
"y": 1917
|
||||||
},
|
},
|
||||||
"width": 20,
|
"width": 20,
|
||||||
"height": 292,
|
"height": 292,
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 479 KiB After Width: | Height: | Size: 479 KiB |
658
e2etests/testdata/stable/sequence_diagram_self_edges/dagre/board.exp.json
generated
vendored
Normal file
658
e2etests/testdata/stable/sequence_diagram_self_edges/dagre/board.exp.json
generated
vendored
Normal file
|
|
@ -0,0 +1,658 @@
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"shapes": [
|
||||||
|
{
|
||||||
|
"id": "a",
|
||||||
|
"type": "",
|
||||||
|
"pos": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 50
|
||||||
|
},
|
||||||
|
"width": 150,
|
||||||
|
"height": 169,
|
||||||
|
"opacity": 1,
|
||||||
|
"strokeDash": 0,
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"borderRadius": 0,
|
||||||
|
"fill": "#E3E9FD",
|
||||||
|
"stroke": "#0D32B2",
|
||||||
|
"shadow": false,
|
||||||
|
"3d": false,
|
||||||
|
"multiple": false,
|
||||||
|
"tooltip": "",
|
||||||
|
"link": "",
|
||||||
|
"icon": null,
|
||||||
|
"iconPosition": "",
|
||||||
|
"fields": null,
|
||||||
|
"methods": null,
|
||||||
|
"columns": null,
|
||||||
|
"label": "a",
|
||||||
|
"fontSize": 16,
|
||||||
|
"fontFamily": "DEFAULT",
|
||||||
|
"language": "",
|
||||||
|
"color": "#0A0F25",
|
||||||
|
"italic": false,
|
||||||
|
"bold": true,
|
||||||
|
"underline": false,
|
||||||
|
"labelWidth": 12,
|
||||||
|
"labelHeight": 26,
|
||||||
|
"labelPosition": "INSIDE_MIDDLE_CENTER",
|
||||||
|
"zIndex": 0,
|
||||||
|
"level": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "b",
|
||||||
|
"type": "",
|
||||||
|
"pos": {
|
||||||
|
"x": 400,
|
||||||
|
"y": 52
|
||||||
|
},
|
||||||
|
"width": 150,
|
||||||
|
"height": 167,
|
||||||
|
"opacity": 1,
|
||||||
|
"strokeDash": 0,
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"borderRadius": 0,
|
||||||
|
"fill": "#E3E9FD",
|
||||||
|
"stroke": "#0D32B2",
|
||||||
|
"shadow": false,
|
||||||
|
"3d": false,
|
||||||
|
"multiple": false,
|
||||||
|
"tooltip": "",
|
||||||
|
"link": "",
|
||||||
|
"icon": null,
|
||||||
|
"iconPosition": "",
|
||||||
|
"fields": null,
|
||||||
|
"methods": null,
|
||||||
|
"columns": null,
|
||||||
|
"label": "b",
|
||||||
|
"fontSize": 16,
|
||||||
|
"fontFamily": "DEFAULT",
|
||||||
|
"language": "",
|
||||||
|
"color": "#0A0F25",
|
||||||
|
"italic": false,
|
||||||
|
"bold": true,
|
||||||
|
"underline": false,
|
||||||
|
"labelWidth": 13,
|
||||||
|
"labelHeight": 26,
|
||||||
|
"labelPosition": "INSIDE_MIDDLE_CENTER",
|
||||||
|
"zIndex": 0,
|
||||||
|
"level": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "b.1",
|
||||||
|
"type": "rectangle",
|
||||||
|
"pos": {
|
||||||
|
"x": 469,
|
||||||
|
"y": 673
|
||||||
|
},
|
||||||
|
"width": 12,
|
||||||
|
"height": 228,
|
||||||
|
"opacity": 1,
|
||||||
|
"strokeDash": 0,
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"borderRadius": 0,
|
||||||
|
"fill": "#EDF0FD",
|
||||||
|
"stroke": "#0D32B2",
|
||||||
|
"shadow": false,
|
||||||
|
"3d": false,
|
||||||
|
"multiple": false,
|
||||||
|
"tooltip": "",
|
||||||
|
"link": "",
|
||||||
|
"icon": null,
|
||||||
|
"iconPosition": "",
|
||||||
|
"fields": null,
|
||||||
|
"methods": null,
|
||||||
|
"columns": null,
|
||||||
|
"label": "",
|
||||||
|
"fontSize": 24,
|
||||||
|
"fontFamily": "DEFAULT",
|
||||||
|
"language": "",
|
||||||
|
"color": "#0A0F25",
|
||||||
|
"italic": false,
|
||||||
|
"bold": true,
|
||||||
|
"underline": false,
|
||||||
|
"labelWidth": 15,
|
||||||
|
"labelHeight": 36,
|
||||||
|
"zIndex": 1,
|
||||||
|
"level": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "b.1.2",
|
||||||
|
"type": "rectangle",
|
||||||
|
"pos": {
|
||||||
|
"x": 465,
|
||||||
|
"y": 803
|
||||||
|
},
|
||||||
|
"width": 20,
|
||||||
|
"height": 82,
|
||||||
|
"opacity": 1,
|
||||||
|
"strokeDash": 0,
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"borderRadius": 0,
|
||||||
|
"fill": "#F7F8FE",
|
||||||
|
"stroke": "#0D32B2",
|
||||||
|
"shadow": false,
|
||||||
|
"3d": false,
|
||||||
|
"multiple": false,
|
||||||
|
"tooltip": "",
|
||||||
|
"link": "",
|
||||||
|
"icon": null,
|
||||||
|
"iconPosition": "",
|
||||||
|
"fields": null,
|
||||||
|
"methods": null,
|
||||||
|
"columns": null,
|
||||||
|
"label": "",
|
||||||
|
"fontSize": 16,
|
||||||
|
"fontFamily": "DEFAULT",
|
||||||
|
"language": "",
|
||||||
|
"color": "#0A0F25",
|
||||||
|
"italic": false,
|
||||||
|
"bold": true,
|
||||||
|
"underline": false,
|
||||||
|
"labelWidth": 13,
|
||||||
|
"labelHeight": 26,
|
||||||
|
"zIndex": 1,
|
||||||
|
"level": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "a.1",
|
||||||
|
"type": "rectangle",
|
||||||
|
"pos": {
|
||||||
|
"x": 69,
|
||||||
|
"y": 967
|
||||||
|
},
|
||||||
|
"width": 12,
|
||||||
|
"height": 178,
|
||||||
|
"opacity": 1,
|
||||||
|
"strokeDash": 0,
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"borderRadius": 0,
|
||||||
|
"fill": "#EDF0FD",
|
||||||
|
"stroke": "#0D32B2",
|
||||||
|
"shadow": false,
|
||||||
|
"3d": false,
|
||||||
|
"multiple": false,
|
||||||
|
"tooltip": "",
|
||||||
|
"link": "",
|
||||||
|
"icon": null,
|
||||||
|
"iconPosition": "",
|
||||||
|
"fields": null,
|
||||||
|
"methods": null,
|
||||||
|
"columns": null,
|
||||||
|
"label": "",
|
||||||
|
"fontSize": 24,
|
||||||
|
"fontFamily": "DEFAULT",
|
||||||
|
"language": "",
|
||||||
|
"color": "#0A0F25",
|
||||||
|
"italic": false,
|
||||||
|
"bold": true,
|
||||||
|
"underline": false,
|
||||||
|
"labelWidth": 15,
|
||||||
|
"labelHeight": 36,
|
||||||
|
"zIndex": 1,
|
||||||
|
"level": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "a.1.2",
|
||||||
|
"type": "rectangle",
|
||||||
|
"pos": {
|
||||||
|
"x": 65,
|
||||||
|
"y": 983
|
||||||
|
},
|
||||||
|
"width": 20,
|
||||||
|
"height": 80,
|
||||||
|
"opacity": 1,
|
||||||
|
"strokeDash": 0,
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"borderRadius": 0,
|
||||||
|
"fill": "#F7F8FE",
|
||||||
|
"stroke": "#0D32B2",
|
||||||
|
"shadow": false,
|
||||||
|
"3d": false,
|
||||||
|
"multiple": false,
|
||||||
|
"tooltip": "",
|
||||||
|
"link": "",
|
||||||
|
"icon": null,
|
||||||
|
"iconPosition": "",
|
||||||
|
"fields": null,
|
||||||
|
"methods": null,
|
||||||
|
"columns": null,
|
||||||
|
"label": "",
|
||||||
|
"fontSize": 16,
|
||||||
|
"fontFamily": "DEFAULT",
|
||||||
|
"language": "",
|
||||||
|
"color": "#0A0F25",
|
||||||
|
"italic": false,
|
||||||
|
"bold": true,
|
||||||
|
"underline": false,
|
||||||
|
"labelWidth": 13,
|
||||||
|
"labelHeight": 26,
|
||||||
|
"zIndex": 1,
|
||||||
|
"level": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "b.3",
|
||||||
|
"type": "rectangle",
|
||||||
|
"pos": {
|
||||||
|
"x": 469,
|
||||||
|
"y": 1113
|
||||||
|
},
|
||||||
|
"width": 12,
|
||||||
|
"height": 80,
|
||||||
|
"opacity": 1,
|
||||||
|
"strokeDash": 0,
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"borderRadius": 0,
|
||||||
|
"fill": "#EDF0FD",
|
||||||
|
"stroke": "#0D32B2",
|
||||||
|
"shadow": false,
|
||||||
|
"3d": false,
|
||||||
|
"multiple": false,
|
||||||
|
"tooltip": "",
|
||||||
|
"link": "",
|
||||||
|
"icon": null,
|
||||||
|
"iconPosition": "",
|
||||||
|
"fields": null,
|
||||||
|
"methods": null,
|
||||||
|
"columns": null,
|
||||||
|
"label": "",
|
||||||
|
"fontSize": 16,
|
||||||
|
"fontFamily": "DEFAULT",
|
||||||
|
"language": "",
|
||||||
|
"color": "#0A0F25",
|
||||||
|
"italic": false,
|
||||||
|
"bold": true,
|
||||||
|
"underline": false,
|
||||||
|
"labelWidth": 13,
|
||||||
|
"labelHeight": 26,
|
||||||
|
"zIndex": 1,
|
||||||
|
"level": 2
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"connections": [
|
||||||
|
{
|
||||||
|
"id": "(a -> a)[0]",
|
||||||
|
"src": "a",
|
||||||
|
"srcArrow": "none",
|
||||||
|
"srcLabel": "",
|
||||||
|
"dst": "a",
|
||||||
|
"dstArrow": "triangle",
|
||||||
|
"dstLabel": "",
|
||||||
|
"opacity": 1,
|
||||||
|
"strokeDash": 0,
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"stroke": "#0D32B2",
|
||||||
|
"label": "a self edge here",
|
||||||
|
"fontSize": 16,
|
||||||
|
"fontFamily": "DEFAULT",
|
||||||
|
"language": "",
|
||||||
|
"color": "#676C7E",
|
||||||
|
"italic": true,
|
||||||
|
"bold": false,
|
||||||
|
"underline": false,
|
||||||
|
"labelWidth": 103,
|
||||||
|
"labelHeight": 21,
|
||||||
|
"labelPosition": "INSIDE_MIDDLE_CENTER",
|
||||||
|
"labelPercentage": 0,
|
||||||
|
"route": [
|
||||||
|
{
|
||||||
|
"x": 75,
|
||||||
|
"y": 349
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"x": 155,
|
||||||
|
"y": 349
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"x": 155,
|
||||||
|
"y": 429
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"x": 75,
|
||||||
|
"y": 429
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"animated": false,
|
||||||
|
"tooltip": "",
|
||||||
|
"icon": null,
|
||||||
|
"zIndex": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "(a -> b)[0]",
|
||||||
|
"src": "a",
|
||||||
|
"srcArrow": "none",
|
||||||
|
"srcLabel": "",
|
||||||
|
"dst": "b",
|
||||||
|
"dstArrow": "triangle",
|
||||||
|
"dstLabel": "",
|
||||||
|
"opacity": 1,
|
||||||
|
"strokeDash": 0,
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"stroke": "#0D32B2",
|
||||||
|
"label": "between actors",
|
||||||
|
"fontSize": 16,
|
||||||
|
"fontFamily": "DEFAULT",
|
||||||
|
"language": "",
|
||||||
|
"color": "#676C7E",
|
||||||
|
"italic": true,
|
||||||
|
"bold": false,
|
||||||
|
"underline": false,
|
||||||
|
"labelWidth": 102,
|
||||||
|
"labelHeight": 21,
|
||||||
|
"labelPosition": "INSIDE_MIDDLE_CENTER",
|
||||||
|
"labelPercentage": 0,
|
||||||
|
"route": [
|
||||||
|
{
|
||||||
|
"x": 75,
|
||||||
|
"y": 479
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"x": 475,
|
||||||
|
"y": 479
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"animated": false,
|
||||||
|
"tooltip": "",
|
||||||
|
"icon": null,
|
||||||
|
"zIndex": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "(b -> b.1)[0]",
|
||||||
|
"src": "b",
|
||||||
|
"srcArrow": "none",
|
||||||
|
"srcLabel": "",
|
||||||
|
"dst": "b.1",
|
||||||
|
"dstArrow": "triangle",
|
||||||
|
"dstLabel": "",
|
||||||
|
"opacity": 1,
|
||||||
|
"strokeDash": 0,
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"stroke": "#0D32B2",
|
||||||
|
"label": "to descendant",
|
||||||
|
"fontSize": 16,
|
||||||
|
"fontFamily": "DEFAULT",
|
||||||
|
"language": "",
|
||||||
|
"color": "#676C7E",
|
||||||
|
"italic": true,
|
||||||
|
"bold": false,
|
||||||
|
"underline": false,
|
||||||
|
"labelWidth": 94,
|
||||||
|
"labelHeight": 21,
|
||||||
|
"labelPosition": "INSIDE_MIDDLE_CENTER",
|
||||||
|
"labelPercentage": 0,
|
||||||
|
"route": [
|
||||||
|
{
|
||||||
|
"x": 475,
|
||||||
|
"y": 609
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"x": 555,
|
||||||
|
"y": 609
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"x": 555,
|
||||||
|
"y": 689
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"x": 481,
|
||||||
|
"y": 689
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"animated": false,
|
||||||
|
"tooltip": "",
|
||||||
|
"icon": null,
|
||||||
|
"zIndex": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "b.(1 -> 1.2)[0]",
|
||||||
|
"src": "b.1",
|
||||||
|
"srcArrow": "none",
|
||||||
|
"srcLabel": "",
|
||||||
|
"dst": "b.1.2",
|
||||||
|
"dstArrow": "triangle",
|
||||||
|
"dstLabel": "",
|
||||||
|
"opacity": 1,
|
||||||
|
"strokeDash": 0,
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"stroke": "#0D32B2",
|
||||||
|
"label": "to deeper descendant",
|
||||||
|
"fontSize": 16,
|
||||||
|
"fontFamily": "DEFAULT",
|
||||||
|
"language": "",
|
||||||
|
"color": "#676C7E",
|
||||||
|
"italic": true,
|
||||||
|
"bold": false,
|
||||||
|
"underline": false,
|
||||||
|
"labelWidth": 143,
|
||||||
|
"labelHeight": 21,
|
||||||
|
"labelPosition": "INSIDE_MIDDLE_CENTER",
|
||||||
|
"labelPercentage": 0,
|
||||||
|
"route": [
|
||||||
|
{
|
||||||
|
"x": 481,
|
||||||
|
"y": 739
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"x": 555,
|
||||||
|
"y": 739
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"x": 555,
|
||||||
|
"y": 819
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"x": 485,
|
||||||
|
"y": 819
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"animated": false,
|
||||||
|
"tooltip": "",
|
||||||
|
"icon": null,
|
||||||
|
"zIndex": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "(b.1.2 -> b)[0]",
|
||||||
|
"src": "b.1.2",
|
||||||
|
"srcArrow": "none",
|
||||||
|
"srcLabel": "",
|
||||||
|
"dst": "b",
|
||||||
|
"dstArrow": "triangle",
|
||||||
|
"dstLabel": "",
|
||||||
|
"opacity": 1,
|
||||||
|
"strokeDash": 0,
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"stroke": "#0D32B2",
|
||||||
|
"label": "to parent",
|
||||||
|
"fontSize": 16,
|
||||||
|
"fontFamily": "DEFAULT",
|
||||||
|
"language": "",
|
||||||
|
"color": "#676C7E",
|
||||||
|
"italic": true,
|
||||||
|
"bold": false,
|
||||||
|
"underline": false,
|
||||||
|
"labelWidth": 62,
|
||||||
|
"labelHeight": 21,
|
||||||
|
"labelPosition": "INSIDE_MIDDLE_CENTER",
|
||||||
|
"labelPercentage": 0,
|
||||||
|
"route": [
|
||||||
|
{
|
||||||
|
"x": 485,
|
||||||
|
"y": 869
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"x": 555,
|
||||||
|
"y": 869
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"x": 555,
|
||||||
|
"y": 949
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"x": 475,
|
||||||
|
"y": 949
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"animated": false,
|
||||||
|
"tooltip": "",
|
||||||
|
"icon": null,
|
||||||
|
"zIndex": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "(b -> a.1.2)[0]",
|
||||||
|
"src": "b",
|
||||||
|
"srcArrow": "none",
|
||||||
|
"srcLabel": "",
|
||||||
|
"dst": "a.1.2",
|
||||||
|
"dstArrow": "triangle",
|
||||||
|
"dstLabel": "",
|
||||||
|
"opacity": 1,
|
||||||
|
"strokeDash": 0,
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"stroke": "#0D32B2",
|
||||||
|
"label": "actor",
|
||||||
|
"fontSize": 16,
|
||||||
|
"fontFamily": "DEFAULT",
|
||||||
|
"language": "",
|
||||||
|
"color": "#676C7E",
|
||||||
|
"italic": true,
|
||||||
|
"bold": false,
|
||||||
|
"underline": false,
|
||||||
|
"labelWidth": 36,
|
||||||
|
"labelHeight": 21,
|
||||||
|
"labelPosition": "INSIDE_MIDDLE_CENTER",
|
||||||
|
"labelPercentage": 0,
|
||||||
|
"route": [
|
||||||
|
{
|
||||||
|
"x": 475,
|
||||||
|
"y": 999
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"x": 85,
|
||||||
|
"y": 999
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"animated": false,
|
||||||
|
"tooltip": "",
|
||||||
|
"icon": null,
|
||||||
|
"zIndex": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "(a.1 -> b.3)[0]",
|
||||||
|
"src": "a.1",
|
||||||
|
"srcArrow": "none",
|
||||||
|
"srcLabel": "",
|
||||||
|
"dst": "b.3",
|
||||||
|
"dstArrow": "triangle",
|
||||||
|
"dstLabel": "",
|
||||||
|
"opacity": 1,
|
||||||
|
"strokeDash": 0,
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"stroke": "#0D32B2",
|
||||||
|
"label": "",
|
||||||
|
"fontSize": 16,
|
||||||
|
"fontFamily": "DEFAULT",
|
||||||
|
"language": "",
|
||||||
|
"color": "#676C7E",
|
||||||
|
"italic": true,
|
||||||
|
"bold": false,
|
||||||
|
"underline": false,
|
||||||
|
"labelWidth": 0,
|
||||||
|
"labelHeight": 0,
|
||||||
|
"labelPosition": "",
|
||||||
|
"labelPercentage": 0,
|
||||||
|
"route": [
|
||||||
|
{
|
||||||
|
"x": 81,
|
||||||
|
"y": 1129
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"x": 469,
|
||||||
|
"y": 1129
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"animated": false,
|
||||||
|
"tooltip": "",
|
||||||
|
"icon": null,
|
||||||
|
"zIndex": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "(a -- )[0]",
|
||||||
|
"src": "a",
|
||||||
|
"srcArrow": "none",
|
||||||
|
"srcLabel": "",
|
||||||
|
"dst": "a-lifeline-end-2251863791",
|
||||||
|
"dstArrow": "none",
|
||||||
|
"dstLabel": "",
|
||||||
|
"opacity": 1,
|
||||||
|
"strokeDash": 6,
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"stroke": "#0D32B2",
|
||||||
|
"label": "",
|
||||||
|
"fontSize": 16,
|
||||||
|
"fontFamily": "DEFAULT",
|
||||||
|
"language": "",
|
||||||
|
"color": "#676C7E",
|
||||||
|
"italic": true,
|
||||||
|
"bold": false,
|
||||||
|
"underline": false,
|
||||||
|
"labelWidth": 0,
|
||||||
|
"labelHeight": 0,
|
||||||
|
"labelPosition": "",
|
||||||
|
"labelPercentage": 0,
|
||||||
|
"route": [
|
||||||
|
{
|
||||||
|
"x": 75,
|
||||||
|
"y": 219
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"x": 75,
|
||||||
|
"y": 1259
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"animated": false,
|
||||||
|
"tooltip": "",
|
||||||
|
"icon": null,
|
||||||
|
"zIndex": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "(b -- )[0]",
|
||||||
|
"src": "b",
|
||||||
|
"srcArrow": "none",
|
||||||
|
"srcLabel": "",
|
||||||
|
"dst": "b-lifeline-end-668380428",
|
||||||
|
"dstArrow": "none",
|
||||||
|
"dstLabel": "",
|
||||||
|
"opacity": 1,
|
||||||
|
"strokeDash": 6,
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"stroke": "#0D32B2",
|
||||||
|
"label": "",
|
||||||
|
"fontSize": 16,
|
||||||
|
"fontFamily": "DEFAULT",
|
||||||
|
"language": "",
|
||||||
|
"color": "#676C7E",
|
||||||
|
"italic": true,
|
||||||
|
"bold": false,
|
||||||
|
"underline": false,
|
||||||
|
"labelWidth": 0,
|
||||||
|
"labelHeight": 0,
|
||||||
|
"labelPosition": "",
|
||||||
|
"labelPercentage": 0,
|
||||||
|
"route": [
|
||||||
|
{
|
||||||
|
"x": 475,
|
||||||
|
"y": 219
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"x": 475,
|
||||||
|
"y": 1259
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"animated": false,
|
||||||
|
"tooltip": "",
|
||||||
|
"icon": null,
|
||||||
|
"zIndex": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
39
e2etests/testdata/stable/sequence_diagram_self_edges/dagre/sketch.exp.svg
vendored
Normal file
39
e2etests/testdata/stable/sequence_diagram_self_edges/dagre/sketch.exp.svg
vendored
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 472 KiB |
658
e2etests/testdata/stable/sequence_diagram_self_edges/elk/board.exp.json
generated
vendored
Normal file
658
e2etests/testdata/stable/sequence_diagram_self_edges/elk/board.exp.json
generated
vendored
Normal file
|
|
@ -0,0 +1,658 @@
|
||||||
|
{
|
||||||
|
"name": "",
|
||||||
|
"shapes": [
|
||||||
|
{
|
||||||
|
"id": "a",
|
||||||
|
"type": "",
|
||||||
|
"pos": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 50
|
||||||
|
},
|
||||||
|
"width": 150,
|
||||||
|
"height": 169,
|
||||||
|
"opacity": 1,
|
||||||
|
"strokeDash": 0,
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"borderRadius": 0,
|
||||||
|
"fill": "#E3E9FD",
|
||||||
|
"stroke": "#0D32B2",
|
||||||
|
"shadow": false,
|
||||||
|
"3d": false,
|
||||||
|
"multiple": false,
|
||||||
|
"tooltip": "",
|
||||||
|
"link": "",
|
||||||
|
"icon": null,
|
||||||
|
"iconPosition": "",
|
||||||
|
"fields": null,
|
||||||
|
"methods": null,
|
||||||
|
"columns": null,
|
||||||
|
"label": "a",
|
||||||
|
"fontSize": 16,
|
||||||
|
"fontFamily": "DEFAULT",
|
||||||
|
"language": "",
|
||||||
|
"color": "#0A0F25",
|
||||||
|
"italic": false,
|
||||||
|
"bold": true,
|
||||||
|
"underline": false,
|
||||||
|
"labelWidth": 12,
|
||||||
|
"labelHeight": 26,
|
||||||
|
"labelPosition": "INSIDE_MIDDLE_CENTER",
|
||||||
|
"zIndex": 0,
|
||||||
|
"level": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "b",
|
||||||
|
"type": "",
|
||||||
|
"pos": {
|
||||||
|
"x": 400,
|
||||||
|
"y": 52
|
||||||
|
},
|
||||||
|
"width": 150,
|
||||||
|
"height": 167,
|
||||||
|
"opacity": 1,
|
||||||
|
"strokeDash": 0,
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"borderRadius": 0,
|
||||||
|
"fill": "#E3E9FD",
|
||||||
|
"stroke": "#0D32B2",
|
||||||
|
"shadow": false,
|
||||||
|
"3d": false,
|
||||||
|
"multiple": false,
|
||||||
|
"tooltip": "",
|
||||||
|
"link": "",
|
||||||
|
"icon": null,
|
||||||
|
"iconPosition": "",
|
||||||
|
"fields": null,
|
||||||
|
"methods": null,
|
||||||
|
"columns": null,
|
||||||
|
"label": "b",
|
||||||
|
"fontSize": 16,
|
||||||
|
"fontFamily": "DEFAULT",
|
||||||
|
"language": "",
|
||||||
|
"color": "#0A0F25",
|
||||||
|
"italic": false,
|
||||||
|
"bold": true,
|
||||||
|
"underline": false,
|
||||||
|
"labelWidth": 13,
|
||||||
|
"labelHeight": 26,
|
||||||
|
"labelPosition": "INSIDE_MIDDLE_CENTER",
|
||||||
|
"zIndex": 0,
|
||||||
|
"level": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "b.1",
|
||||||
|
"type": "rectangle",
|
||||||
|
"pos": {
|
||||||
|
"x": 469,
|
||||||
|
"y": 673
|
||||||
|
},
|
||||||
|
"width": 12,
|
||||||
|
"height": 228,
|
||||||
|
"opacity": 1,
|
||||||
|
"strokeDash": 0,
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"borderRadius": 0,
|
||||||
|
"fill": "#EDF0FD",
|
||||||
|
"stroke": "#0D32B2",
|
||||||
|
"shadow": false,
|
||||||
|
"3d": false,
|
||||||
|
"multiple": false,
|
||||||
|
"tooltip": "",
|
||||||
|
"link": "",
|
||||||
|
"icon": null,
|
||||||
|
"iconPosition": "",
|
||||||
|
"fields": null,
|
||||||
|
"methods": null,
|
||||||
|
"columns": null,
|
||||||
|
"label": "",
|
||||||
|
"fontSize": 24,
|
||||||
|
"fontFamily": "DEFAULT",
|
||||||
|
"language": "",
|
||||||
|
"color": "#0A0F25",
|
||||||
|
"italic": false,
|
||||||
|
"bold": true,
|
||||||
|
"underline": false,
|
||||||
|
"labelWidth": 15,
|
||||||
|
"labelHeight": 36,
|
||||||
|
"zIndex": 1,
|
||||||
|
"level": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "b.1.2",
|
||||||
|
"type": "rectangle",
|
||||||
|
"pos": {
|
||||||
|
"x": 465,
|
||||||
|
"y": 803
|
||||||
|
},
|
||||||
|
"width": 20,
|
||||||
|
"height": 82,
|
||||||
|
"opacity": 1,
|
||||||
|
"strokeDash": 0,
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"borderRadius": 0,
|
||||||
|
"fill": "#F7F8FE",
|
||||||
|
"stroke": "#0D32B2",
|
||||||
|
"shadow": false,
|
||||||
|
"3d": false,
|
||||||
|
"multiple": false,
|
||||||
|
"tooltip": "",
|
||||||
|
"link": "",
|
||||||
|
"icon": null,
|
||||||
|
"iconPosition": "",
|
||||||
|
"fields": null,
|
||||||
|
"methods": null,
|
||||||
|
"columns": null,
|
||||||
|
"label": "",
|
||||||
|
"fontSize": 16,
|
||||||
|
"fontFamily": "DEFAULT",
|
||||||
|
"language": "",
|
||||||
|
"color": "#0A0F25",
|
||||||
|
"italic": false,
|
||||||
|
"bold": true,
|
||||||
|
"underline": false,
|
||||||
|
"labelWidth": 13,
|
||||||
|
"labelHeight": 26,
|
||||||
|
"zIndex": 1,
|
||||||
|
"level": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "a.1",
|
||||||
|
"type": "rectangle",
|
||||||
|
"pos": {
|
||||||
|
"x": 69,
|
||||||
|
"y": 967
|
||||||
|
},
|
||||||
|
"width": 12,
|
||||||
|
"height": 178,
|
||||||
|
"opacity": 1,
|
||||||
|
"strokeDash": 0,
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"borderRadius": 0,
|
||||||
|
"fill": "#EDF0FD",
|
||||||
|
"stroke": "#0D32B2",
|
||||||
|
"shadow": false,
|
||||||
|
"3d": false,
|
||||||
|
"multiple": false,
|
||||||
|
"tooltip": "",
|
||||||
|
"link": "",
|
||||||
|
"icon": null,
|
||||||
|
"iconPosition": "",
|
||||||
|
"fields": null,
|
||||||
|
"methods": null,
|
||||||
|
"columns": null,
|
||||||
|
"label": "",
|
||||||
|
"fontSize": 24,
|
||||||
|
"fontFamily": "DEFAULT",
|
||||||
|
"language": "",
|
||||||
|
"color": "#0A0F25",
|
||||||
|
"italic": false,
|
||||||
|
"bold": true,
|
||||||
|
"underline": false,
|
||||||
|
"labelWidth": 15,
|
||||||
|
"labelHeight": 36,
|
||||||
|
"zIndex": 1,
|
||||||
|
"level": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "a.1.2",
|
||||||
|
"type": "rectangle",
|
||||||
|
"pos": {
|
||||||
|
"x": 65,
|
||||||
|
"y": 983
|
||||||
|
},
|
||||||
|
"width": 20,
|
||||||
|
"height": 80,
|
||||||
|
"opacity": 1,
|
||||||
|
"strokeDash": 0,
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"borderRadius": 0,
|
||||||
|
"fill": "#F7F8FE",
|
||||||
|
"stroke": "#0D32B2",
|
||||||
|
"shadow": false,
|
||||||
|
"3d": false,
|
||||||
|
"multiple": false,
|
||||||
|
"tooltip": "",
|
||||||
|
"link": "",
|
||||||
|
"icon": null,
|
||||||
|
"iconPosition": "",
|
||||||
|
"fields": null,
|
||||||
|
"methods": null,
|
||||||
|
"columns": null,
|
||||||
|
"label": "",
|
||||||
|
"fontSize": 16,
|
||||||
|
"fontFamily": "DEFAULT",
|
||||||
|
"language": "",
|
||||||
|
"color": "#0A0F25",
|
||||||
|
"italic": false,
|
||||||
|
"bold": true,
|
||||||
|
"underline": false,
|
||||||
|
"labelWidth": 13,
|
||||||
|
"labelHeight": 26,
|
||||||
|
"zIndex": 1,
|
||||||
|
"level": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "b.3",
|
||||||
|
"type": "rectangle",
|
||||||
|
"pos": {
|
||||||
|
"x": 469,
|
||||||
|
"y": 1113
|
||||||
|
},
|
||||||
|
"width": 12,
|
||||||
|
"height": 80,
|
||||||
|
"opacity": 1,
|
||||||
|
"strokeDash": 0,
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"borderRadius": 0,
|
||||||
|
"fill": "#EDF0FD",
|
||||||
|
"stroke": "#0D32B2",
|
||||||
|
"shadow": false,
|
||||||
|
"3d": false,
|
||||||
|
"multiple": false,
|
||||||
|
"tooltip": "",
|
||||||
|
"link": "",
|
||||||
|
"icon": null,
|
||||||
|
"iconPosition": "",
|
||||||
|
"fields": null,
|
||||||
|
"methods": null,
|
||||||
|
"columns": null,
|
||||||
|
"label": "",
|
||||||
|
"fontSize": 16,
|
||||||
|
"fontFamily": "DEFAULT",
|
||||||
|
"language": "",
|
||||||
|
"color": "#0A0F25",
|
||||||
|
"italic": false,
|
||||||
|
"bold": true,
|
||||||
|
"underline": false,
|
||||||
|
"labelWidth": 13,
|
||||||
|
"labelHeight": 26,
|
||||||
|
"zIndex": 1,
|
||||||
|
"level": 2
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"connections": [
|
||||||
|
{
|
||||||
|
"id": "(a -> a)[0]",
|
||||||
|
"src": "a",
|
||||||
|
"srcArrow": "none",
|
||||||
|
"srcLabel": "",
|
||||||
|
"dst": "a",
|
||||||
|
"dstArrow": "triangle",
|
||||||
|
"dstLabel": "",
|
||||||
|
"opacity": 1,
|
||||||
|
"strokeDash": 0,
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"stroke": "#0D32B2",
|
||||||
|
"label": "a self edge here",
|
||||||
|
"fontSize": 16,
|
||||||
|
"fontFamily": "DEFAULT",
|
||||||
|
"language": "",
|
||||||
|
"color": "#676C7E",
|
||||||
|
"italic": true,
|
||||||
|
"bold": false,
|
||||||
|
"underline": false,
|
||||||
|
"labelWidth": 103,
|
||||||
|
"labelHeight": 21,
|
||||||
|
"labelPosition": "INSIDE_MIDDLE_CENTER",
|
||||||
|
"labelPercentage": 0,
|
||||||
|
"route": [
|
||||||
|
{
|
||||||
|
"x": 75,
|
||||||
|
"y": 349
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"x": 155,
|
||||||
|
"y": 349
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"x": 155,
|
||||||
|
"y": 429
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"x": 75,
|
||||||
|
"y": 429
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"animated": false,
|
||||||
|
"tooltip": "",
|
||||||
|
"icon": null,
|
||||||
|
"zIndex": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "(a -> b)[0]",
|
||||||
|
"src": "a",
|
||||||
|
"srcArrow": "none",
|
||||||
|
"srcLabel": "",
|
||||||
|
"dst": "b",
|
||||||
|
"dstArrow": "triangle",
|
||||||
|
"dstLabel": "",
|
||||||
|
"opacity": 1,
|
||||||
|
"strokeDash": 0,
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"stroke": "#0D32B2",
|
||||||
|
"label": "between actors",
|
||||||
|
"fontSize": 16,
|
||||||
|
"fontFamily": "DEFAULT",
|
||||||
|
"language": "",
|
||||||
|
"color": "#676C7E",
|
||||||
|
"italic": true,
|
||||||
|
"bold": false,
|
||||||
|
"underline": false,
|
||||||
|
"labelWidth": 102,
|
||||||
|
"labelHeight": 21,
|
||||||
|
"labelPosition": "INSIDE_MIDDLE_CENTER",
|
||||||
|
"labelPercentage": 0,
|
||||||
|
"route": [
|
||||||
|
{
|
||||||
|
"x": 75,
|
||||||
|
"y": 479
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"x": 475,
|
||||||
|
"y": 479
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"animated": false,
|
||||||
|
"tooltip": "",
|
||||||
|
"icon": null,
|
||||||
|
"zIndex": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "(b -> b.1)[0]",
|
||||||
|
"src": "b",
|
||||||
|
"srcArrow": "none",
|
||||||
|
"srcLabel": "",
|
||||||
|
"dst": "b.1",
|
||||||
|
"dstArrow": "triangle",
|
||||||
|
"dstLabel": "",
|
||||||
|
"opacity": 1,
|
||||||
|
"strokeDash": 0,
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"stroke": "#0D32B2",
|
||||||
|
"label": "to descendant",
|
||||||
|
"fontSize": 16,
|
||||||
|
"fontFamily": "DEFAULT",
|
||||||
|
"language": "",
|
||||||
|
"color": "#676C7E",
|
||||||
|
"italic": true,
|
||||||
|
"bold": false,
|
||||||
|
"underline": false,
|
||||||
|
"labelWidth": 94,
|
||||||
|
"labelHeight": 21,
|
||||||
|
"labelPosition": "INSIDE_MIDDLE_CENTER",
|
||||||
|
"labelPercentage": 0,
|
||||||
|
"route": [
|
||||||
|
{
|
||||||
|
"x": 475,
|
||||||
|
"y": 609
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"x": 555,
|
||||||
|
"y": 609
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"x": 555,
|
||||||
|
"y": 689
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"x": 481,
|
||||||
|
"y": 689
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"animated": false,
|
||||||
|
"tooltip": "",
|
||||||
|
"icon": null,
|
||||||
|
"zIndex": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "b.(1 -> 1.2)[0]",
|
||||||
|
"src": "b.1",
|
||||||
|
"srcArrow": "none",
|
||||||
|
"srcLabel": "",
|
||||||
|
"dst": "b.1.2",
|
||||||
|
"dstArrow": "triangle",
|
||||||
|
"dstLabel": "",
|
||||||
|
"opacity": 1,
|
||||||
|
"strokeDash": 0,
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"stroke": "#0D32B2",
|
||||||
|
"label": "to deeper descendant",
|
||||||
|
"fontSize": 16,
|
||||||
|
"fontFamily": "DEFAULT",
|
||||||
|
"language": "",
|
||||||
|
"color": "#676C7E",
|
||||||
|
"italic": true,
|
||||||
|
"bold": false,
|
||||||
|
"underline": false,
|
||||||
|
"labelWidth": 143,
|
||||||
|
"labelHeight": 21,
|
||||||
|
"labelPosition": "INSIDE_MIDDLE_CENTER",
|
||||||
|
"labelPercentage": 0,
|
||||||
|
"route": [
|
||||||
|
{
|
||||||
|
"x": 481,
|
||||||
|
"y": 739
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"x": 555,
|
||||||
|
"y": 739
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"x": 555,
|
||||||
|
"y": 819
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"x": 485,
|
||||||
|
"y": 819
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"animated": false,
|
||||||
|
"tooltip": "",
|
||||||
|
"icon": null,
|
||||||
|
"zIndex": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "(b.1.2 -> b)[0]",
|
||||||
|
"src": "b.1.2",
|
||||||
|
"srcArrow": "none",
|
||||||
|
"srcLabel": "",
|
||||||
|
"dst": "b",
|
||||||
|
"dstArrow": "triangle",
|
||||||
|
"dstLabel": "",
|
||||||
|
"opacity": 1,
|
||||||
|
"strokeDash": 0,
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"stroke": "#0D32B2",
|
||||||
|
"label": "to parent",
|
||||||
|
"fontSize": 16,
|
||||||
|
"fontFamily": "DEFAULT",
|
||||||
|
"language": "",
|
||||||
|
"color": "#676C7E",
|
||||||
|
"italic": true,
|
||||||
|
"bold": false,
|
||||||
|
"underline": false,
|
||||||
|
"labelWidth": 62,
|
||||||
|
"labelHeight": 21,
|
||||||
|
"labelPosition": "INSIDE_MIDDLE_CENTER",
|
||||||
|
"labelPercentage": 0,
|
||||||
|
"route": [
|
||||||
|
{
|
||||||
|
"x": 485,
|
||||||
|
"y": 869
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"x": 555,
|
||||||
|
"y": 869
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"x": 555,
|
||||||
|
"y": 949
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"x": 475,
|
||||||
|
"y": 949
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"animated": false,
|
||||||
|
"tooltip": "",
|
||||||
|
"icon": null,
|
||||||
|
"zIndex": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "(b -> a.1.2)[0]",
|
||||||
|
"src": "b",
|
||||||
|
"srcArrow": "none",
|
||||||
|
"srcLabel": "",
|
||||||
|
"dst": "a.1.2",
|
||||||
|
"dstArrow": "triangle",
|
||||||
|
"dstLabel": "",
|
||||||
|
"opacity": 1,
|
||||||
|
"strokeDash": 0,
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"stroke": "#0D32B2",
|
||||||
|
"label": "actor",
|
||||||
|
"fontSize": 16,
|
||||||
|
"fontFamily": "DEFAULT",
|
||||||
|
"language": "",
|
||||||
|
"color": "#676C7E",
|
||||||
|
"italic": true,
|
||||||
|
"bold": false,
|
||||||
|
"underline": false,
|
||||||
|
"labelWidth": 36,
|
||||||
|
"labelHeight": 21,
|
||||||
|
"labelPosition": "INSIDE_MIDDLE_CENTER",
|
||||||
|
"labelPercentage": 0,
|
||||||
|
"route": [
|
||||||
|
{
|
||||||
|
"x": 475,
|
||||||
|
"y": 999
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"x": 85,
|
||||||
|
"y": 999
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"animated": false,
|
||||||
|
"tooltip": "",
|
||||||
|
"icon": null,
|
||||||
|
"zIndex": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "(a.1 -> b.3)[0]",
|
||||||
|
"src": "a.1",
|
||||||
|
"srcArrow": "none",
|
||||||
|
"srcLabel": "",
|
||||||
|
"dst": "b.3",
|
||||||
|
"dstArrow": "triangle",
|
||||||
|
"dstLabel": "",
|
||||||
|
"opacity": 1,
|
||||||
|
"strokeDash": 0,
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"stroke": "#0D32B2",
|
||||||
|
"label": "",
|
||||||
|
"fontSize": 16,
|
||||||
|
"fontFamily": "DEFAULT",
|
||||||
|
"language": "",
|
||||||
|
"color": "#676C7E",
|
||||||
|
"italic": true,
|
||||||
|
"bold": false,
|
||||||
|
"underline": false,
|
||||||
|
"labelWidth": 0,
|
||||||
|
"labelHeight": 0,
|
||||||
|
"labelPosition": "",
|
||||||
|
"labelPercentage": 0,
|
||||||
|
"route": [
|
||||||
|
{
|
||||||
|
"x": 81,
|
||||||
|
"y": 1129
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"x": 469,
|
||||||
|
"y": 1129
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"animated": false,
|
||||||
|
"tooltip": "",
|
||||||
|
"icon": null,
|
||||||
|
"zIndex": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "(a -- )[0]",
|
||||||
|
"src": "a",
|
||||||
|
"srcArrow": "none",
|
||||||
|
"srcLabel": "",
|
||||||
|
"dst": "a-lifeline-end-2251863791",
|
||||||
|
"dstArrow": "none",
|
||||||
|
"dstLabel": "",
|
||||||
|
"opacity": 1,
|
||||||
|
"strokeDash": 6,
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"stroke": "#0D32B2",
|
||||||
|
"label": "",
|
||||||
|
"fontSize": 16,
|
||||||
|
"fontFamily": "DEFAULT",
|
||||||
|
"language": "",
|
||||||
|
"color": "#676C7E",
|
||||||
|
"italic": true,
|
||||||
|
"bold": false,
|
||||||
|
"underline": false,
|
||||||
|
"labelWidth": 0,
|
||||||
|
"labelHeight": 0,
|
||||||
|
"labelPosition": "",
|
||||||
|
"labelPercentage": 0,
|
||||||
|
"route": [
|
||||||
|
{
|
||||||
|
"x": 75,
|
||||||
|
"y": 219
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"x": 75,
|
||||||
|
"y": 1259
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"animated": false,
|
||||||
|
"tooltip": "",
|
||||||
|
"icon": null,
|
||||||
|
"zIndex": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "(b -- )[0]",
|
||||||
|
"src": "b",
|
||||||
|
"srcArrow": "none",
|
||||||
|
"srcLabel": "",
|
||||||
|
"dst": "b-lifeline-end-668380428",
|
||||||
|
"dstArrow": "none",
|
||||||
|
"dstLabel": "",
|
||||||
|
"opacity": 1,
|
||||||
|
"strokeDash": 6,
|
||||||
|
"strokeWidth": 2,
|
||||||
|
"stroke": "#0D32B2",
|
||||||
|
"label": "",
|
||||||
|
"fontSize": 16,
|
||||||
|
"fontFamily": "DEFAULT",
|
||||||
|
"language": "",
|
||||||
|
"color": "#676C7E",
|
||||||
|
"italic": true,
|
||||||
|
"bold": false,
|
||||||
|
"underline": false,
|
||||||
|
"labelWidth": 0,
|
||||||
|
"labelHeight": 0,
|
||||||
|
"labelPosition": "",
|
||||||
|
"labelPercentage": 0,
|
||||||
|
"route": [
|
||||||
|
{
|
||||||
|
"x": 475,
|
||||||
|
"y": 219
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"x": 475,
|
||||||
|
"y": 1259
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"animated": false,
|
||||||
|
"tooltip": "",
|
||||||
|
"icon": null,
|
||||||
|
"zIndex": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
39
e2etests/testdata/stable/sequence_diagram_self_edges/elk/sketch.exp.svg
vendored
Normal file
39
e2etests/testdata/stable/sequence_diagram_self_edges/elk/sketch.exp.svg
vendored
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 472 KiB |
Loading…
Reference in a new issue