diff --git a/d2graph/d2graph.go b/d2graph/d2graph.go index de5785ffa..838ffe6d7 100644 --- a/d2graph/d2graph.go +++ b/d2graph/d2graph.go @@ -20,6 +20,8 @@ import ( "oss.terrastruct.com/d2/lib/textmeasure" ) +const INNER_LABEL_PADDING int = 5 + // TODO: Refactor with a light abstract layer on top of AST implementing scenarios, // variables, imports, substitutions and then a final set of structures representing // a final graph. @@ -883,7 +885,7 @@ func (g *Graph) SetDimensions(mtexts []*d2target.MText, ruler *textmeasure.Ruler } var dims *d2target.TextDimensions - var innerLabelPadding = 5 + var innerLabelPadding = INNER_LABEL_PADDING if obj.Attributes.Shape.Value == d2target.ShapeText { if obj.Attributes.Language == "latex" { width, height, err := d2latex.Measure(obj.Text().Text) diff --git a/d2renderers/d2svg/d2svg.go b/d2renderers/d2svg/d2svg.go index 77214ce3f..2af505713 100644 --- a/d2renderers/d2svg/d2svg.go +++ b/d2renderers/d2svg/d2svg.go @@ -22,6 +22,7 @@ import ( "oss.terrastruct.com/util-go/go2" + "oss.terrastruct.com/d2/d2graph" "oss.terrastruct.com/d2/d2renderers/d2fonts" "oss.terrastruct.com/d2/d2renderers/d2latex" "oss.terrastruct.com/d2/d2target" @@ -337,11 +338,11 @@ func pathData(connection d2target.Connection, idToShape map[string]d2target.Shap return strings.Join(path, " ") } -func makeLabelMask(connection d2target.Connection, labelTL, tl, br *geo.Point) string { +func makeLabelMask(labelTL *geo.Point, width, height int) string { return fmt.Sprintf(``, labelTL.X, labelTL.Y, - connection.LabelWidth, - connection.LabelHeight, + width, + height, ) } @@ -408,7 +409,7 @@ func drawConnection(writer io.Writer, connection d2target.Connection, markers ma br.X = math.Max(br.X, labelTL.X+float64(connection.LabelWidth)) br.Y = math.Max(br.Y, labelTL.Y+float64(connection.LabelHeight)) - labelMask = makeLabelMask(connection, labelTL, tl, br) + labelMask = makeLabelMask(labelTL, connection.LabelWidth, connection.LabelHeight) } } @@ -582,7 +583,7 @@ func render3dRect(targetShape d2target.Shape) string { return borderMask + mainRect + renderedSides + renderedBorder } -func drawShape(writer io.Writer, targetShape d2target.Shape) error { +func drawShape(writer io.Writer, targetShape d2target.Shape) (labelMask string, err error) { fmt.Fprintf(writer, ``, escapeText(targetShape.ID)) tl := geo.NewPoint(float64(targetShape.Pos.X), float64(targetShape.Pos.Y)) width := float64(targetShape.Width) @@ -620,11 +621,11 @@ func drawShape(writer io.Writer, targetShape d2target.Shape) error { case d2target.ShapeClass: drawClass(writer, targetShape) fmt.Fprintf(writer, ``) - return nil + return labelMask, nil case d2target.ShapeSQLTable: drawTable(writer, targetShape) fmt.Fprintf(writer, ``) - return nil + return labelMask, nil case d2target.ShapeOval: if targetShape.Multiple { fmt.Fprint(writer, renderOval(multipleTL, width, height, style)) @@ -706,19 +707,19 @@ func drawShape(writer io.Writer, targetShape d2target.Shape) error { case d2target.ShapeCode: lexer := lexers.Get(targetShape.Language) if lexer == nil { - return fmt.Errorf("code snippet lexer for %s not found", targetShape.Language) + return labelMask, fmt.Errorf("code snippet lexer for %s not found", targetShape.Language) } style := styles.Get("github") if style == nil { - return errors.New(`code snippet style "github" not found`) + return labelMask, errors.New(`code snippet style "github" not found`) } formatter := formatters.Get("svg") if formatter == nil { - return errors.New(`code snippet formatter "svg" not found`) + return labelMask, errors.New(`code snippet formatter "svg" not found`) } iterator, err := lexer.Tokenise(nil, targetShape.Label) if err != nil { - return err + return labelMask, err } svgStyles := styleToSVG(style) @@ -748,15 +749,15 @@ func drawShape(writer io.Writer, targetShape d2target.Shape) error { if targetShape.Language == "latex" { render, err := d2latex.Render(targetShape.Label) if err != nil { - return err + return labelMask, err } fmt.Fprintf(writer, ``, box.TopLeft.X, box.TopLeft.Y, targetShape.Opacity) - fmt.Fprintf(writer, render) + fmt.Fprint(writer, render) fmt.Fprintf(writer, "") } else { render, err := textmeasure.RenderMarkdown(targetShape.Label) if err != nil { - return err + return labelMask, err } fmt.Fprintf(writer, ``, box.TopLeft.X, box.TopLeft.Y, targetShape.Width, targetShape.Height, @@ -772,7 +773,7 @@ func drawShape(writer io.Writer, targetShape d2target.Shape) error { fontColor = targetShape.Color } textStyle := fmt.Sprintf("text-anchor:%s;font-size:%vpx;fill:%s", "middle", targetShape.FontSize, fontColor) - x := labelTL.X + float64(targetShape.LabelWidth)/2 + x := labelTL.X + float64(targetShape.LabelWidth)/2. // text is vertically positioned at its baseline which is at labelTL+FontSize y := labelTL.Y + float64(targetShape.FontSize) fmt.Fprintf(writer, `%s`, @@ -781,10 +782,13 @@ func drawShape(writer io.Writer, targetShape d2target.Shape) error { textStyle, renderText(targetShape.Label, x, float64(targetShape.LabelHeight)), ) + if targetShape.Blend { + labelMask = makeLabelMask(labelTL, targetShape.LabelWidth, targetShape.LabelHeight-d2graph.INNER_LABEL_PADDING) + } } } fmt.Fprintf(writer, ``) - return nil + return labelMask, nil } func escapeText(text string) string { @@ -996,9 +1000,11 @@ func Render(diagram *d2target.Diagram) ([]byte, error) { labelMasks = append(labelMasks, labelMask) } } else if s, is := obj.(d2target.Shape); is { - err := drawShape(buf, s) + labelMask, err := drawShape(buf, s) if err != nil { return nil, err + } else if labelMask != "" { + labelMasks = append(labelMasks, labelMask) } } else { return nil, fmt.Errorf("unknow object of type %T", obj) diff --git a/e2etests/testdata/stable/sequence_diagram_groups/dagre/sketch.exp.svg b/e2etests/testdata/stable/sequence_diagram_groups/dagre/sketch.exp.svg index ec8e7b216..9c0b05ef8 100644 --- a/e2etests/testdata/stable/sequence_diagram_groups/dagre/sketch.exp.svg +++ b/e2etests/testdata/stable/sequence_diagram_groups/dagre/sketch.exp.svg @@ -20,6 +20,11 @@ width="1147" height="2268" viewBox="-76 -26 1147 2268">abcdggggroup 1group bchoonested guy lalaeyokayokaywhat would arnold saythis note + + + + + diff --git a/e2etests/testdata/stable/sequence_diagram_groups/elk/sketch.exp.svg b/e2etests/testdata/stable/sequence_diagram_groups/elk/sketch.exp.svg index ec8e7b216..9c0b05ef8 100644 --- a/e2etests/testdata/stable/sequence_diagram_groups/elk/sketch.exp.svg +++ b/e2etests/testdata/stable/sequence_diagram_groups/elk/sketch.exp.svg @@ -20,6 +20,11 @@ width="1147" height="2268" viewBox="-76 -26 1147 2268">abcdggggroup 1group bchoonested guy lalaeyokayokaywhat would arnold saythis note + + + + + diff --git a/e2etests/testdata/stable/sequence_diagram_nested_groups/dagre/sketch.exp.svg b/e2etests/testdata/stable/sequence_diagram_nested_groups/dagre/sketch.exp.svg index e97ce77dc..70e362bbd 100644 --- a/e2etests/testdata/stable/sequence_diagram_nested_groups/dagre/sketch.exp.svg +++ b/e2etests/testdata/stable/sequence_diagram_nested_groups/dagre/sketch.exp.svg @@ -18,7 +18,19 @@ width="1116" height="2458" viewBox="-197 -26 1116 2458">abjust 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 toojustalongnotehere + + + + + + + + + + + +abjust 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 toojustalongnotehere + + + + + + + + + + + +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 + diff --git a/e2etests/testdata/stable/sequence_diagram_real/elk/sketch.exp.svg b/e2etests/testdata/stable/sequence_diagram_real/elk/sketch.exp.svg index 9e6ceb66d..095df39cf 100644 --- a/e2etests/testdata/stable/sequence_diagram_real/elk/sketch.exp.svg +++ b/e2etests/testdata/stable/sequence_diagram_real/elk/sketch.exp.svg @@ -20,6 +20,7 @@ width="2447" height="2536" viewBox="-88 -88 2447 2536">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 + diff --git a/e2etests/testdata/todo/sequence_diagram_actor_padding_nested_groups/dagre/sketch.exp.svg b/e2etests/testdata/todo/sequence_diagram_actor_padding_nested_groups/dagre/sketch.exp.svg index 45f3f9430..9357326e5 100644 --- a/e2etests/testdata/todo/sequence_diagram_actor_padding_nested_groups/dagre/sketch.exp.svg +++ b/e2etests/testdata/todo/sequence_diagram_actor_padding_nested_groups/dagre/sketch.exp.svg @@ -18,7 +18,14 @@ width="921" height="1242" viewBox="-147 -26 921 1242">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 + + + + + + +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 + + + + + + +