Merge pull request #361 from ejulio-ts/mask-group-label

Mask group label
This commit is contained in:
ejulio-ts 2022-12-05 21:28:27 -08:00 committed by GitHub
commit 376e615f93
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 80 additions and 22 deletions

View file

@ -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)

View file

@ -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(`<rect x="%f" y="%f" width="%d" height="%d" fill="black"></rect>`,
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, `<g id="%s">`, 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, `</g></g>`)
return nil
return labelMask, nil
case d2target.ShapeSQLTable:
drawTable(writer, targetShape)
fmt.Fprintf(writer, `</g></g>`)
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, `<g transform="translate(%f %f)" style="opacity:%f">`, box.TopLeft.X, box.TopLeft.Y, targetShape.Opacity)
fmt.Fprintf(writer, render)
fmt.Fprint(writer, render)
fmt.Fprintf(writer, "</g>")
} else {
render, err := textmeasure.RenderMarkdown(targetShape.Label)
if err != nil {
return err
return labelMask, err
}
fmt.Fprintf(writer, `<g><foreignObject requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" x="%f" y="%f" width="%d" height="%d">`,
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, `<text class="%s" x="%f" y="%f" style="%s">%s</text>`,
@ -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, `</g>`)
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)

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 475 KiB

After

Width:  |  Height:  |  Size: 475 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 475 KiB

After

Width:  |  Height:  |  Size: 475 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 332 KiB

After

Width:  |  Height:  |  Size: 333 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 332 KiB

After

Width:  |  Height:  |  Size: 333 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 480 KiB

After

Width:  |  Height:  |  Size: 480 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 480 KiB

After

Width:  |  Height:  |  Size: 480 KiB

View file

@ -18,7 +18,14 @@ width="921" height="1242" viewBox="-147 -26 921 1242"><style type="text/css">
}
]]>
</style><g id="b"><g class="shape" ><rect x="24" y="74" width="150" height="126" style="fill:#EDF0FD;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" /></g><text class="text" x="99.000000" y="140.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">b</text></g><g id="a"><g class="shape" ><rect x="274" y="74" width="150" height="126" style="fill:#EDF0FD;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" /></g><text class="text" x="349.000000" y="140.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">a</text></g><g id="c"><g class="shape" ><rect x="524" y="74" width="150" height="126" style="fill:#EDF0FD;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" /></g><text class="text" x="599.000000" y="140.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">c</text></g><g id="(b -- )[0]"><path d="M 99.000000 202.000000 L 99.000000 1109.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;stroke-dasharray:12.000000,11.838767;" mask="url(#labels)"/></g><g id="(a -- )[0]"><path d="M 349.000000 202.000000 L 349.000000 1109.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;stroke-dasharray:12.000000,11.838767;" mask="url(#labels)"/></g><g id="(c -- )[0]"><path d="M 599.000000 202.000000 L 599.000000 1109.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;stroke-dasharray:12.000000,11.838767;" mask="url(#labels)"/></g><g id="this is a message group"><g class="shape blend" ><rect x="-47" y="420" width="542" height="696" style="fill:#DEE1EB;stroke:#0D32B2;opacity:1.000000;stroke-width:0;" /></g><text class="text" x="33.000000" y="436.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">this is a message group</text></g><g id="this is a message group.and this is a nested message group"><g class="shape blend" ><rect x="-23" y="550" width="494" height="542" style="fill:#DEE1EB;stroke:#0D32B2;opacity:1.000000;stroke-width:0;" /></g><text class="text" x="96.000000" y="566.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">and this is a nested message group</text></g><g id="this is a message group.and this is a nested message group.what about more nesting"><g class="shape blend" ><rect x="1" y="680" width="446" height="388" style="fill:#DEE1EB;stroke:#0D32B2;opacity:1.000000;stroke-width:0;" /></g><text class="text" x="87.500000" y="696.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">what about more nesting</text></g><g id="this is a message group.and this is a nested message group.what about more nesting.yo"><g class="shape blend" ><rect x="25" y="810" width="398" height="234" style="fill:#DEE1EB;stroke:#0D32B2;opacity:1.000000;stroke-width:0;" /></g><text class="text" x="35.500000" y="826.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">yo</text></g><g id="this is a message group.and this is a nested message group.what about more nesting.yo.yo"><g class="shape blend" ><rect x="49" y="940" width="350" height="80" style="fill:#DEE1EB;stroke:#0D32B2;opacity:1.000000;stroke-width:0;" /></g><text class="text" x="59.500000" y="956.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">yo</text></g><g id="(b -&gt; c)[0]"><marker id="mk-3990223579" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" /> </marker><path d="M 101.000000 330.000000 L 595.000000 330.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#labels)"/></g><g id="(a -&gt; b)[0]"><path d="M 347.000000 460.000000 L 103.000000 460.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#labels)"/></g><g id="(a -&gt; b)[1]"><path d="M 347.000000 590.000000 L 103.000000 590.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#labels)"/></g><g id="(a -&gt; b)[2]"><path d="M 347.000000 720.000000 L 103.000000 720.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#labels)"/></g><g id="(a -&gt; b)[3]"><path d="M 347.000000 850.000000 L 103.000000 850.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#labels)"/></g><g id="(a -&gt; b)[4]"><path d="M 347.000000 980.000000 L 103.000000 980.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#labels)"/></g><style type="text/css"><![CDATA[
</style><g id="b"><g class="shape" ><rect x="24" y="74" width="150" height="126" style="fill:#EDF0FD;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" /></g><text class="text" x="99.000000" y="140.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">b</text></g><g id="a"><g class="shape" ><rect x="274" y="74" width="150" height="126" style="fill:#EDF0FD;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" /></g><text class="text" x="349.000000" y="140.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">a</text></g><g id="c"><g class="shape" ><rect x="524" y="74" width="150" height="126" style="fill:#EDF0FD;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" /></g><text class="text" x="599.000000" y="140.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">c</text></g><g id="(b -- )[0]"><path d="M 99.000000 202.000000 L 99.000000 1109.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;stroke-dasharray:12.000000,11.838767;" mask="url(#labels)"/></g><g id="(a -- )[0]"><path d="M 349.000000 202.000000 L 349.000000 1109.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;stroke-dasharray:12.000000,11.838767;" mask="url(#labels)"/></g><g id="(c -- )[0]"><path d="M 599.000000 202.000000 L 599.000000 1109.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;stroke-dasharray:12.000000,11.838767;" mask="url(#labels)"/></g><g id="this is a message group"><g class="shape blend" ><rect x="-47" y="420" width="542" height="696" style="fill:#DEE1EB;stroke:#0D32B2;opacity:1.000000;stroke-width:0;" /></g><text class="text" x="33.000000" y="436.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">this is a message group</text></g><g id="this is a message group.and this is a nested message group"><g class="shape blend" ><rect x="-23" y="550" width="494" height="542" style="fill:#DEE1EB;stroke:#0D32B2;opacity:1.000000;stroke-width:0;" /></g><text class="text" x="96.000000" y="566.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">and this is a nested message group</text></g><g id="this is a message group.and this is a nested message group.what about more nesting"><g class="shape blend" ><rect x="1" y="680" width="446" height="388" style="fill:#DEE1EB;stroke:#0D32B2;opacity:1.000000;stroke-width:0;" /></g><text class="text" x="87.500000" y="696.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">what about more nesting</text></g><g id="this is a message group.and this is a nested message group.what about more nesting.yo"><g class="shape blend" ><rect x="25" y="810" width="398" height="234" style="fill:#DEE1EB;stroke:#0D32B2;opacity:1.000000;stroke-width:0;" /></g><text class="text" x="35.500000" y="826.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">yo</text></g><g id="this is a message group.and this is a nested message group.what about more nesting.yo.yo"><g class="shape blend" ><rect x="49" y="940" width="350" height="80" style="fill:#DEE1EB;stroke:#0D32B2;opacity:1.000000;stroke-width:0;" /></g><text class="text" x="59.500000" y="956.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">yo</text></g><g id="(b -&gt; c)[0]"><marker id="mk-3990223579" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" /> </marker><path d="M 101.000000 330.000000 L 595.000000 330.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#labels)"/></g><g id="(a -&gt; b)[0]"><path d="M 347.000000 460.000000 L 103.000000 460.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#labels)"/></g><g id="(a -&gt; b)[1]"><path d="M 347.000000 590.000000 L 103.000000 590.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#labels)"/></g><g id="(a -&gt; b)[2]"><path d="M 347.000000 720.000000 L 103.000000 720.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#labels)"/></g><g id="(a -&gt; b)[3]"><path d="M 347.000000 850.000000 L 103.000000 850.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#labels)"/></g><g id="(a -&gt; b)[4]"><path d="M 347.000000 980.000000 L 103.000000 980.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#labels)"/></g><mask id="labels" maskUnits="userSpaceOnUse" x="0" y="0" width="921" height="1242">
<rect x="0" y="0" width="921" height="1242" fill="white"></rect>
<rect x="-47.000000" y="420.000000" width="160" height="21" fill="black"></rect>
<rect x="-23.000000" y="550.000000" width="238" height="21" fill="black"></rect>
<rect x="1.000000" y="680.000000" width="173" height="21" fill="black"></rect>
<rect x="25.000000" y="810.000000" width="21" height="21" fill="black"></rect>
<rect x="49.000000" y="940.000000" width="21" height="21" fill="black"></rect>
</mask><style type="text/css"><![CDATA[
.text {
font-family: "font-regular";
}

Before

Width:  |  Height:  |  Size: 329 KiB

After

Width:  |  Height:  |  Size: 330 KiB

View file

@ -18,7 +18,14 @@ width="921" height="1242" viewBox="-147 -26 921 1242"><style type="text/css">
}
]]>
</style><g id="b"><g class="shape" ><rect x="24" y="74" width="150" height="126" style="fill:#EDF0FD;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" /></g><text class="text" x="99.000000" y="140.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">b</text></g><g id="a"><g class="shape" ><rect x="274" y="74" width="150" height="126" style="fill:#EDF0FD;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" /></g><text class="text" x="349.000000" y="140.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">a</text></g><g id="c"><g class="shape" ><rect x="524" y="74" width="150" height="126" style="fill:#EDF0FD;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" /></g><text class="text" x="599.000000" y="140.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">c</text></g><g id="(b -- )[0]"><path d="M 99.000000 202.000000 L 99.000000 1109.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;stroke-dasharray:12.000000,11.838767;" mask="url(#labels)"/></g><g id="(a -- )[0]"><path d="M 349.000000 202.000000 L 349.000000 1109.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;stroke-dasharray:12.000000,11.838767;" mask="url(#labels)"/></g><g id="(c -- )[0]"><path d="M 599.000000 202.000000 L 599.000000 1109.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;stroke-dasharray:12.000000,11.838767;" mask="url(#labels)"/></g><g id="this is a message group"><g class="shape blend" ><rect x="-47" y="420" width="542" height="696" style="fill:#DEE1EB;stroke:#0D32B2;opacity:1.000000;stroke-width:0;" /></g><text class="text" x="33.000000" y="436.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">this is a message group</text></g><g id="this is a message group.and this is a nested message group"><g class="shape blend" ><rect x="-23" y="550" width="494" height="542" style="fill:#DEE1EB;stroke:#0D32B2;opacity:1.000000;stroke-width:0;" /></g><text class="text" x="96.000000" y="566.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">and this is a nested message group</text></g><g id="this is a message group.and this is a nested message group.what about more nesting"><g class="shape blend" ><rect x="1" y="680" width="446" height="388" style="fill:#DEE1EB;stroke:#0D32B2;opacity:1.000000;stroke-width:0;" /></g><text class="text" x="87.500000" y="696.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">what about more nesting</text></g><g id="this is a message group.and this is a nested message group.what about more nesting.yo"><g class="shape blend" ><rect x="25" y="810" width="398" height="234" style="fill:#DEE1EB;stroke:#0D32B2;opacity:1.000000;stroke-width:0;" /></g><text class="text" x="35.500000" y="826.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">yo</text></g><g id="this is a message group.and this is a nested message group.what about more nesting.yo.yo"><g class="shape blend" ><rect x="49" y="940" width="350" height="80" style="fill:#DEE1EB;stroke:#0D32B2;opacity:1.000000;stroke-width:0;" /></g><text class="text" x="59.500000" y="956.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">yo</text></g><g id="(b -&gt; c)[0]"><marker id="mk-3990223579" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" /> </marker><path d="M 101.000000 330.000000 L 595.000000 330.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#labels)"/></g><g id="(a -&gt; b)[0]"><path d="M 347.000000 460.000000 L 103.000000 460.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#labels)"/></g><g id="(a -&gt; b)[1]"><path d="M 347.000000 590.000000 L 103.000000 590.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#labels)"/></g><g id="(a -&gt; b)[2]"><path d="M 347.000000 720.000000 L 103.000000 720.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#labels)"/></g><g id="(a -&gt; b)[3]"><path d="M 347.000000 850.000000 L 103.000000 850.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#labels)"/></g><g id="(a -&gt; b)[4]"><path d="M 347.000000 980.000000 L 103.000000 980.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#labels)"/></g><style type="text/css"><![CDATA[
</style><g id="b"><g class="shape" ><rect x="24" y="74" width="150" height="126" style="fill:#EDF0FD;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" /></g><text class="text" x="99.000000" y="140.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">b</text></g><g id="a"><g class="shape" ><rect x="274" y="74" width="150" height="126" style="fill:#EDF0FD;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" /></g><text class="text" x="349.000000" y="140.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">a</text></g><g id="c"><g class="shape" ><rect x="524" y="74" width="150" height="126" style="fill:#EDF0FD;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" /></g><text class="text" x="599.000000" y="140.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">c</text></g><g id="(b -- )[0]"><path d="M 99.000000 202.000000 L 99.000000 1109.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;stroke-dasharray:12.000000,11.838767;" mask="url(#labels)"/></g><g id="(a -- )[0]"><path d="M 349.000000 202.000000 L 349.000000 1109.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;stroke-dasharray:12.000000,11.838767;" mask="url(#labels)"/></g><g id="(c -- )[0]"><path d="M 599.000000 202.000000 L 599.000000 1109.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;stroke-dasharray:12.000000,11.838767;" mask="url(#labels)"/></g><g id="this is a message group"><g class="shape blend" ><rect x="-47" y="420" width="542" height="696" style="fill:#DEE1EB;stroke:#0D32B2;opacity:1.000000;stroke-width:0;" /></g><text class="text" x="33.000000" y="436.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">this is a message group</text></g><g id="this is a message group.and this is a nested message group"><g class="shape blend" ><rect x="-23" y="550" width="494" height="542" style="fill:#DEE1EB;stroke:#0D32B2;opacity:1.000000;stroke-width:0;" /></g><text class="text" x="96.000000" y="566.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">and this is a nested message group</text></g><g id="this is a message group.and this is a nested message group.what about more nesting"><g class="shape blend" ><rect x="1" y="680" width="446" height="388" style="fill:#DEE1EB;stroke:#0D32B2;opacity:1.000000;stroke-width:0;" /></g><text class="text" x="87.500000" y="696.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">what about more nesting</text></g><g id="this is a message group.and this is a nested message group.what about more nesting.yo"><g class="shape blend" ><rect x="25" y="810" width="398" height="234" style="fill:#DEE1EB;stroke:#0D32B2;opacity:1.000000;stroke-width:0;" /></g><text class="text" x="35.500000" y="826.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">yo</text></g><g id="this is a message group.and this is a nested message group.what about more nesting.yo.yo"><g class="shape blend" ><rect x="49" y="940" width="350" height="80" style="fill:#DEE1EB;stroke:#0D32B2;opacity:1.000000;stroke-width:0;" /></g><text class="text" x="59.500000" y="956.000000" style="text-anchor:middle;font-size:16px;fill:#0A0F25">yo</text></g><g id="(b -&gt; c)[0]"><marker id="mk-3990223579" markerWidth="10.000000" markerHeight="12.000000" refX="7.000000" refY="6.000000" viewBox="0.000000 0.000000 10.000000 12.000000" orient="auto" markerUnits="userSpaceOnUse"> <polygon class="connection" fill="#0D32B2" stroke-width="2" points="0.000000,0.000000 10.000000,6.000000 0.000000,12.000000" /> </marker><path d="M 101.000000 330.000000 L 595.000000 330.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#labels)"/></g><g id="(a -&gt; b)[0]"><path d="M 347.000000 460.000000 L 103.000000 460.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#labels)"/></g><g id="(a -&gt; b)[1]"><path d="M 347.000000 590.000000 L 103.000000 590.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#labels)"/></g><g id="(a -&gt; b)[2]"><path d="M 347.000000 720.000000 L 103.000000 720.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#labels)"/></g><g id="(a -&gt; b)[3]"><path d="M 347.000000 850.000000 L 103.000000 850.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#labels)"/></g><g id="(a -&gt; b)[4]"><path d="M 347.000000 980.000000 L 103.000000 980.000000" class="connection" style="fill:none;stroke:#0D32B2;opacity:1.000000;stroke-width:2;" marker-end="url(#mk-3990223579)" mask="url(#labels)"/></g><mask id="labels" maskUnits="userSpaceOnUse" x="0" y="0" width="921" height="1242">
<rect x="0" y="0" width="921" height="1242" fill="white"></rect>
<rect x="-47.000000" y="420.000000" width="160" height="21" fill="black"></rect>
<rect x="-23.000000" y="550.000000" width="238" height="21" fill="black"></rect>
<rect x="1.000000" y="680.000000" width="173" height="21" fill="black"></rect>
<rect x="25.000000" y="810.000000" width="21" height="21" fill="black"></rect>
<rect x="49.000000" y="940.000000" width="21" height="21" fill="black"></rect>
</mask><style type="text/css"><![CDATA[
.text {
font-family: "font-regular";
}

Before

Width:  |  Height:  |  Size: 329 KiB

After

Width:  |  Height:  |  Size: 330 KiB