From 1b996043591caee8ac115f60c01cb17ccfbd47ba Mon Sep 17 00:00:00 2001 From: Alexander Wang Date: Mon, 5 Dec 2022 13:53:09 -0800 Subject: [PATCH] fix nested sequence diagram shape --- d2exporter/export.go | 5 + d2graph/d2graph.go | 16 +- d2layouts/d2sequence/layout.go | 20 +- d2renderers/d2svg/d2svg.go | 2 +- .../dagre/board.exp.json | 120 +-- .../dagre/sketch.exp.svg | 14 +- .../elk/board.exp.json | 120 +-- .../elk/sketch.exp.svg | 14 +- .../dagre/board.exp.json | 392 ++++----- .../dagre/sketch.exp.svg | 26 +- .../elk/board.exp.json | 392 ++++----- .../elk/sketch.exp.svg | 26 +- .../dagre/board.exp.json | 140 +-- .../dagre/sketch.exp.svg | 14 +- .../elk/board.exp.json | 140 +-- .../elk/sketch.exp.svg | 14 +- .../dagre/board.exp.json | 32 +- .../dagre/sketch.exp.svg | 4 +- .../elk/board.exp.json | 32 +- .../elk/sketch.exp.svg | 4 +- .../dagre/board.exp.json | 108 +-- .../dagre/sketch.exp.svg | 4 +- .../elk/board.exp.json | 108 +-- .../elk/sketch.exp.svg | 4 +- .../dagre/board.exp.json | 212 ++--- .../dagre/sketch.exp.svg | 4 +- .../elk/board.exp.json | 212 ++--- .../elk/sketch.exp.svg | 4 +- .../dagre/board.exp.json | 72 +- .../dagre/sketch.exp.svg | 6 +- .../sequence_diagram_note/elk/board.exp.json | 72 +- .../sequence_diagram_note/elk/sketch.exp.svg | 6 +- .../dagre/board.exp.json | 226 ++--- .../dagre/sketch.exp.svg | 32 +- .../sequence_diagram_real/elk/board.exp.json | 226 ++--- .../sequence_diagram_real/elk/sketch.exp.svg | 32 +- .../dagre/board.exp.json | 132 +-- .../dagre/sketch.exp.svg | 16 +- .../elk/board.exp.json | 132 +-- .../elk/sketch.exp.svg | 16 +- .../dagre/board.exp.json | 140 +-- .../dagre/sketch.exp.svg | 20 +- .../elk/board.exp.json | 140 +-- .../elk/sketch.exp.svg | 20 +- .../dagre/board.exp.json | 220 ++--- .../dagre/sketch.exp.svg | 28 +- .../sequence_diagram_span/elk/board.exp.json | 220 ++--- .../sequence_diagram_span/elk/sketch.exp.svg | 28 +- .../sequence_diagrams/dagre/board.exp.json | 800 +++++++++--------- .../sequence_diagrams/dagre/sketch.exp.svg | 54 +- .../sequence_diagrams/elk/board.exp.json | 734 ++++++++-------- .../sequence_diagrams/elk/sketch.exp.svg | 54 +- .../dagre/board.exp.json | 84 +- .../dagre/sketch.exp.svg | 4 +- .../elk/board.exp.json | 84 +- .../elk/sketch.exp.svg | 4 +- 56 files changed, 2897 insertions(+), 2888 deletions(-) diff --git a/d2exporter/export.go b/d2exporter/export.go index c65542362..d39831a2e 100644 --- a/d2exporter/export.go +++ b/d2exporter/export.go @@ -3,6 +3,7 @@ package d2exporter import ( "context" "strconv" + "strings" "oss.terrastruct.com/d2/d2graph" "oss.terrastruct.com/d2/d2target" @@ -99,6 +100,10 @@ func toShape(obj *d2graph.Object, theme *d2themes.Theme) d2target.Shape { shape.Italic = text.IsItalic shape.FontSize = text.FontSize + if strings.EqualFold(obj.Attributes.Shape.Value, d2target.ShapeSequenceDiagram) { + shape.StrokeWidth = 0 + } + if obj.IsSequenceDiagramGroup() { shape.StrokeWidth = 0 shape.Blend = true diff --git a/d2graph/d2graph.go b/d2graph/d2graph.go index 8b5f7003e..3da658f59 100644 --- a/d2graph/d2graph.go +++ b/d2graph/d2graph.go @@ -305,18 +305,6 @@ func (s *Style) Apply(key, value string) error { type ContainerLevel int -func (l ContainerLevel) Fill() string { - // Darkest (least nested) to lightest (most nested) - if l == 1 { - return "#E3E9FD" - } else if l == 2 { - return "#EDF0FD" - } else if l == 3 { - return "#F7F8FE" - } - return "#FFFFFF" -} - func (l ContainerLevel) LabelSize() int { // Largest to smallest if l == 1 { @@ -341,6 +329,10 @@ func (obj *Object) GetFill(theme *d2themes.Theme) string { shape := obj.Attributes.Shape.Value + if strings.EqualFold(shape, d2target.ShapeSequenceDiagram) { + return theme.Colors.Neutrals.N7 + } + if shape == "" || strings.EqualFold(shape, d2target.ShapeSquare) || strings.EqualFold(shape, d2target.ShapeCircle) || strings.EqualFold(shape, d2target.ShapeOval) || strings.EqualFold(shape, d2target.ShapeRectangle) { if level == 1 { if !obj.IsContainer() { diff --git a/d2layouts/d2sequence/layout.go b/d2layouts/d2sequence/layout.go index 33e82a0a4..77f3c6a7d 100644 --- a/d2layouts/d2sequence/layout.go +++ b/d2layouts/d2sequence/layout.go @@ -43,7 +43,7 @@ func Layout(ctx context.Context, g *d2graph.Graph, layout func(ctx context.Conte } obj.Children = make(map[string]*d2graph.Object) obj.ChildrenArray = nil - obj.Box = geo.NewBox(nil, sd.getWidth(), sd.getHeight()) + 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 @@ -141,14 +141,26 @@ func cleanup(g *d2graph.Graph, sequenceDiagrams map[string]*sequenceDiagram, obj obj.LabelPosition = go2.Pointer(string(label.InsideTopCenter)) sd := sequenceDiagrams[obj.AbsID()] - // shift the sequence diagrams as they are always placed at (0, 0) - sd.shift(obj.TopLeft) + // 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[child.ID] = child + obj.ChildrenArray = append(obj.ChildrenArray, child) + } + for _, child := range sd.groups { + if child.Parent == obj { + obj.Children[child.ID] = child + obj.ChildrenArray = append(obj.ChildrenArray, child) + } } - obj.ChildrenArray = sd.actors g.Edges = append(g.Edges, sequenceDiagrams[obj.AbsID()].messages...) g.Edges = append(g.Edges, sequenceDiagrams[obj.AbsID()].lifelines...) diff --git a/d2renderers/d2svg/d2svg.go b/d2renderers/d2svg/d2svg.go index 6bf9135a9..77214ce3f 100644 --- a/d2renderers/d2svg/d2svg.go +++ b/d2renderers/d2svg/d2svg.go @@ -637,7 +637,7 @@ func drawShape(writer io.Writer, targetShape d2target.Shape) error { targetShape.Pos.X, targetShape.Pos.Y, targetShape.Width, targetShape.Height, style) // TODO should standardize "" to rectangle - case d2target.ShapeRectangle, "": + case d2target.ShapeRectangle, d2target.ShapeSequenceDiagram, "": if targetShape.ThreeDee { fmt.Fprint(writer, render3dRect(targetShape)) } else { diff --git a/e2etests/testdata/stable/sequence_diagram_actor_distance/dagre/board.exp.json b/e2etests/testdata/stable/sequence_diagram_actor_distance/dagre/board.exp.json index 775f8b93e..2341f4127 100644 --- a/e2etests/testdata/stable/sequence_diagram_actor_distance/dagre/board.exp.json +++ b/e2etests/testdata/stable/sequence_diagram_actor_distance/dagre/board.exp.json @@ -5,8 +5,8 @@ "id": "a", "type": "", "pos": { - "x": 0, - "y": 210 + "x": 24, + "y": 234 }, "width": 487, "height": 126, @@ -45,8 +45,8 @@ "id": "c", "type": "", "pos": { - "x": 578, - "y": 50 + "x": 602, + "y": 74 }, "width": 177, "height": 286, @@ -85,8 +85,8 @@ "id": "d", "type": "", "pos": { - "x": 1014, - "y": 210 + "x": 1038, + "y": 234 }, "width": 150, "height": 126, @@ -125,8 +125,8 @@ "id": "e", "type": "", "pos": { - "x": 1460, - "y": 210 + "x": 1484, + "y": 234 }, "width": 180, "height": 126, @@ -165,8 +165,8 @@ "id": "b", "type": "", "pos": { - "x": 1718, - "y": 210 + "x": 1742, + "y": 234 }, "width": 163, "height": 126, @@ -205,8 +205,8 @@ "id": "f", "type": "", "pos": { - "x": 1931, - "y": 210 + "x": 1955, + "y": 234 }, "width": 561, "height": 126, @@ -269,12 +269,12 @@ "labelPercentage": 0, "route": [ { - "x": 243.5, - "y": 466 + "x": 267.5, + "y": 490 }, { - "x": 1799.5, - "y": 466 + "x": 1823.5, + "y": 490 } ], "animated": false, @@ -308,12 +308,12 @@ "labelPercentage": 0, "route": [ { - "x": 243.5, - "y": 596 + "x": 267.5, + "y": 620 }, { - "x": 1799.5, - "y": 596 + "x": 1823.5, + "y": 620 } ], "animated": false, @@ -347,12 +347,12 @@ "labelPercentage": 0, "route": [ { - "x": 666.5, - "y": 726 + "x": 690.5, + "y": 750 }, { - "x": 1089, - "y": 726 + "x": 1113, + "y": 750 } ], "animated": false, @@ -386,12 +386,12 @@ "labelPercentage": 0, "route": [ { - "x": 243.5, - "y": 856 + "x": 267.5, + "y": 880 }, { - "x": 1089, - "y": 856 + "x": 1113, + "y": 880 } ], "animated": false, @@ -425,12 +425,12 @@ "labelPercentage": 0, "route": [ { - "x": 1089, - "y": 986 + "x": 1113, + "y": 1010 }, { - "x": 1550, - "y": 986 + "x": 1574, + "y": 1010 } ], "animated": false, @@ -464,12 +464,12 @@ "labelPercentage": 0, "route": [ { - "x": 243.5, - "y": 1116 + "x": 267.5, + "y": 1140 }, { - "x": 2211.5, - "y": 1116 + "x": 2235.5, + "y": 1140 } ], "animated": false, @@ -503,12 +503,12 @@ "labelPercentage": 0, "route": [ { - "x": 243.5, - "y": 336 + "x": 267.5, + "y": 360 }, { - "x": 243.5, - "y": 1246 + "x": 267.5, + "y": 1270 } ], "animated": false, @@ -542,12 +542,12 @@ "labelPercentage": 0, "route": [ { - "x": 666.5, - "y": 336 + "x": 690.5, + "y": 360 }, { - "x": 666.5, - "y": 1246 + "x": 690.5, + "y": 1270 } ], "animated": false, @@ -581,12 +581,12 @@ "labelPercentage": 0, "route": [ { - "x": 1089, - "y": 336 + "x": 1113, + "y": 360 }, { - "x": 1089, - "y": 1246 + "x": 1113, + "y": 1270 } ], "animated": false, @@ -620,12 +620,12 @@ "labelPercentage": 0, "route": [ { - "x": 1550, - "y": 336 + "x": 1574, + "y": 360 }, { - "x": 1550, - "y": 1246 + "x": 1574, + "y": 1270 } ], "animated": false, @@ -659,12 +659,12 @@ "labelPercentage": 0, "route": [ { - "x": 1799.5, - "y": 336 + "x": 1823.5, + "y": 360 }, { - "x": 1799.5, - "y": 1246 + "x": 1823.5, + "y": 1270 } ], "animated": false, @@ -698,12 +698,12 @@ "labelPercentage": 0, "route": [ { - "x": 2211.5, - "y": 336 + "x": 2235.5, + "y": 360 }, { - "x": 2211.5, - "y": 1246 + "x": 2235.5, + "y": 1270 } ], "animated": false, diff --git a/e2etests/testdata/stable/sequence_diagram_actor_distance/dagre/sketch.exp.svg b/e2etests/testdata/stable/sequence_diagram_actor_distance/dagre/sketch.exp.svg index a2518e2ba..0e9876acc 100644 --- a/e2etests/testdata/stable/sequence_diagram_actor_distance/dagre/sketch.exp.svg +++ b/e2etests/testdata/stable/sequence_diagram_actor_distance/dagre/sketch.exp.svg @@ -2,7 +2,7 @@ an actor with a really long label that will break everythinganactorwithareallylonglabelthatwillbreakeverythingsimplea short onefar awaywhat if there were no labels between this actor and the previous one shortlong label for testing purposes and it must be really, really longshortthis should span many actors lifelines so we know how it will look like when redering a long label over many actorslong label for testing purposes and it must be really, really long - - - - - + + + + + an actor with a really long label that will break everythinganactorwithareallylonglabelthatwillbreakeverythingsimplea short onefar awaywhat if there were no labels between this actor and the previous one shortlong label for testing purposes and it must be really, really longshortthis should span many actors lifelines so we know how it will look like when redering a long label over many actorslong label for testing purposes and it must be really, really long +an actor with a really long label that will break everythinganactorwithareallylonglabelthatwillbreakeverythingsimplea short onefar awaywhat if there were no labels between this actor and the previous one shortlong label for testing purposes and it must be really, really longshortthis should span many actors lifelines so we know how it will look like when redering a long label over many actorslong label for testing purposes and it must be really, really long - - - - - + + + + + a labelblabelsa class+ -public() bool -void- -private() int -voidcloudyyyy:= 5 +a labelblabelsa class+ +public() bool +void- +private() int +voidcloudyyyy:= 5 := a + 7 -fmt.Printf("%d", b)cyldiadocssix cornersa random iconoverpackdocs pagetoohard o saysinglepersona queuea squarea step at a timedatausersid -int -name -varchar - result := callThisFunction(obj, 5) midthis sideother side +fmt.Printf("%d", b)cyldiadocssix cornersa random iconoverpackdocs pagetoohard o saysinglepersona queuea squarea step at a timedatausersid +int +name +varchar + result := callThisFunction(obj, 5) midthis sideother side - - + + a labelblabelsa class+ -public() bool -void- -private() int -voidcloudyyyy:= 5 +a labelblabelsa class+ +public() bool +void- +private() int +voidcloudyyyy:= 5 := a + 7 -fmt.Printf("%d", b)cyldiadocssix cornersa random iconoverpackdocs pagetoohard o saysinglepersona queuea squarea step at a timedatausersid -int -name -varchar - result := callThisFunction(obj, 5) midthis sideother side +fmt.Printf("%d", b)cyldiadocssix cornersa random iconoverpackdocs pagetoohard o saysinglepersona queuea squarea step at a timedatausersid +int +name +varchar + result := callThisFunction(obj, 5) midthis sideother side - - + + abcdggggroup 1group bchoonested guy lalaeyokayokaywhat would arnold saythis note - - - - - +abcdggggroup 1group bchoonested guy lalaeyokayokaywhat would arnold saythis note + + + + + abcdggggroup 1group bchoonested guy lalaeyokayokaywhat would arnold saythis note - - - - - +abcdggggroup 1group bchoonested guy lalaeyokayokaywhat would arnold saythis note + + + + + ba a note here to remember that padding must consider notes toojustalongnotehereba a note here to remember that padding must consider notes toojustalongnotehereabjust an actorthis is a message groupaltand this is a nested message groupcase 1case 2case 3case 4what about more nestingcrazy townwhoa a notea note here to remember that padding must consider notes toojustalongnotehereabjust an actorthis is a message groupaltand this is a nested message groupcase 1case 2case 3case 4what about more nestingcrazy townwhoa a notea note here to remember that padding must consider notes toojustalongnoteherescoreritemResponseitemessayRubricconceptitemOutcome scoreritemResponseitemessayRubricconceptitemOutcome abcd okayexplanationanother explanationSome one who believes imaginary things appear right before your i's.The earth is like a tiny grain of sand, only much, much heavier +abcd okayexplanationanother explanationSome one who believes imaginary things appear right before your i's.The earth is like a tiny grain of sand, only much, much heavier - + abcd okayexplanationanother explanationSome one who believes imaginary things appear right before your i's.The earth is like a tiny grain of sand, only much, much heavier +abcd okayexplanationanother explanationSome one who believes imaginary things appear right before your i's.The earth is like a tiny grain of sand, only much, much heavier - + How this is renderedCLId2astd2compilerd2layoutd2exporterd2themesd2rendererd2sequencelayoutd2dagrelayoutonly if root is not sequence 'How this is rendered: {...}'tokenized ASTcompile ASTobjects and edgesrun layout enginesrun engine on shape: sequence_diagram, temporarily removerun core engine on rest add back in sequence diagramsdiagram with correct positions and dimensionsexport diagram with chosen theme and rendererget theme stylesrender to SVGresulting SVGmeasurements also take place - - - - - - - - - - - - - - +How this is renderedCLId2astd2compilerd2layoutd2exporterd2themesd2rendererd2sequencelayoutd2dagrelayoutonly if root is not sequence 'How this is rendered: {...}'tokenized ASTcompile ASTobjects and edgesrun layout enginesrun engine on shape: sequence_diagram, temporarily removerun core engine on rest add back in sequence diagramsdiagram with correct positions and dimensionsexport diagram with chosen theme and rendererget theme stylesrender to SVGresulting SVGmeasurements also take place + + + + + + + + + + + + + + How this is renderedCLId2astd2compilerd2layoutd2exporterd2themesd2rendererd2sequencelayoutd2dagrelayoutonly if root is not sequence 'How this is rendered: {...}'tokenized ASTcompile ASTobjects and edgesrun layout enginesrun engine on shape: sequence_diagram, temporarily removerun core engine on rest add back in sequence diagramsdiagram with correct positions and dimensionsexport diagram with chosen theme and rendererget theme stylesrender to SVGresulting SVGmeasurements also take place - - - - - - - - - - - - - - +How this is renderedCLId2astd2compilerd2layoutd2exporterd2themesd2rendererd2sequencelayoutd2dagrelayoutonly if root is not sequence 'How this is rendered: {...}'tokenized ASTcompile ASTobjects and edgesrun layout enginesrun engine on shape: sequence_diagram, temporarily removerun core engine on rest add back in sequence diagramsdiagram with correct positions and dimensionsexport diagram with chosen theme and rendererget theme stylesrender to SVGresulting SVGmeasurements also take place + + + + + + + + + + + + + + ab a self edge herebetween actorsto descendantto deeper descendantto parentactor +ab a self edge herebetween actorsto descendantto deeper descendantto parentactor - - - - - - + + + + + + ab a self edge herebetween actorsto descendantto deeper descendantto parentactor +ab a self edge herebetween actorsto descendantto deeper descendantto parentactor - - - - - - + + + + + + AlicelinebreakerBobdbqueueanoddservicewithanameinmultiple lines Authentication Requestmake request for something that is quite far away and requires a really long label to take all the space between the objectsvalidate credentialsAuthentication ResponseAnother authentication Requestdo it later storedAnother authentication Response +AlicelinebreakerBobdbqueueanoddservicewithanameinmultiple lines Authentication Requestmake request for something that is quite far away and requires a really long label to take all the space between the objectsvalidate credentialsAuthentication ResponseAnother authentication Requestdo it later storedAnother authentication Response - - - - - - - - + + + + + + + + AlicelinebreakerBobdbqueueanoddservicewithanameinmultiple lines Authentication Requestmake request for something that is quite far away and requires a really long label to take all the space between the objectsvalidate credentialsAuthentication ResponseAnother authentication Requestdo it later storedAnother authentication Response +AlicelinebreakerBobdbqueueanoddservicewithanameinmultiple lines Authentication Requestmake request for something that is quite far away and requires a really long label to take all the space between the objectsvalidate credentialsAuthentication ResponseAnother authentication Requestdo it later storedAnother authentication Response - - - - - - - - + + + + + + + + scoreritemResponseitemessayRubricconceptitemOutcome getItem() itemgetRubric()rubricapplyTo(essayResp)match(essayResponse)scorenewgetNormalMinimum()getNormalMaximum()setScore(score)setFeedback(missingConcepts) +scoreritemResponseitemessayRubricconceptitemOutcome getItem() itemgetRubric()rubricapplyTo(essayResp)match(essayResponse)scorenewgetNormalMinimum()getNormalMaximum()setScore(score)setFeedback(missingConcepts) - - - - - - - - - - - - + + + + + + + + + + + + scoreritemResponseitemessayRubricconceptitemOutcome getItem() itemgetRubric()rubricapplyTo(essayResp)match(essayResponse)scorenewgetNormalMinimum()getNormalMaximum()setScore(score)setFeedback(missingConcepts) +scoreritemResponseitemessayRubricconceptitemOutcome getItem() itemgetRubric()rubricapplyTo(essayResp)match(essayResponse)scorenewgetNormalMinimum()getNormalMaximum()setScore(score)setFeedback(missingConcepts) - - - - - - - - - - - - + + + + + + + + + + + + a_shapea_sequenceanotherfinallysequencesequencesequencescoreritemResponseitemessayRubricconceptitemOutcomescorerconceptessayRubricitemitemOutcomeitemResponsescoreritemResponseitemessayRubricconceptitemOutcome getItem()itemgetRubric()rubricapplyTo(essayResp)match(essayResponse)scorenewgetNormalMinimum()getNormalMaximum()setScore(score)setFeedback(missingConcepts)getItem()itemgetRubric()rubricapplyTo(essayResp)match(essayResponse)scorenewgetNormalMinimum()getNormalMaximum()setScore(score)setFeedback(missingConcepts) - - - - - - - - - - - - - - - - - - - - - - - - - +a_shapea_sequenceanotherfinallysequencesequencesequencescoreritemResponseitemessayRubricconceptitemOutcomescorerconceptessayRubricitemitemOutcomeitemResponsescoreritemResponseitemessayRubricconceptitemOutcome getItem()itemgetRubric()rubricapplyTo(essayResp)match(essayResponse)scorenewgetNormalMinimum()getNormalMaximum()setScore(score)setFeedback(missingConcepts)getItem()itemgetRubric()rubricapplyTo(essayResp)match(essayResponse)scorenewgetNormalMinimum()getNormalMaximum()setScore(score)setFeedback(missingConcepts) + + + + + + + + + + + + + + + + + + + + + + + + + a_shapea_sequenceanotherfinallysequencesequencesequencescoreritemResponseitemessayRubricconceptitemOutcomescorerconceptessayRubricitemitemOutcomeitemResponsescoreritemResponseitemessayRubricconceptitemOutcome getItem()itemgetRubric()rubricapplyTo(essayResp)match(essayResponse)scorenewgetNormalMinimum()getNormalMaximum()setScore(score)setFeedback(missingConcepts)getItem()itemgetRubric()rubricapplyTo(essayResp)match(essayResponse)scorenewgetNormalMinimum()getNormalMaximum()setScore(score)setFeedback(missingConcepts) - - - - - - - - - - - - - - - - - - - - - - - - - +a_shapea_sequenceanotherfinallysequencesequencesequencescoreritemResponseitemessayRubricconceptitemOutcomescorerconceptessayRubricitemitemOutcomeitemResponsescoreritemResponseitemessayRubricconceptitemOutcome getItem()itemgetRubric()rubricapplyTo(essayResp)match(essayResponse)scorenewgetNormalMinimum()getNormalMaximum()setScore(score)setFeedback(missingConcepts)getItem()itemgetRubric()rubricapplyTo(essayResp)match(essayResponse)scorenewgetNormalMinimum()getNormalMaximum()setScore(score)setFeedback(missingConcepts) + + + + + + + + + + + + + + + + + + + + + + + + + bacthis is a message groupand this is a nested message groupwhat about more nestingyoyo bacthis is a message groupand this is a nested message groupwhat about more nestingyoyo