Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add label masks over all connections #332

Merged
merged 2 commits into from
Dec 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions ci/release/changelogs/next.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@

- Local images can now be included, e.g. `icon: ./my_img.png`.
[#146](https://github.com/terrastruct/d2/issues/146)
- Connection labels no longer overlap other connections.
[#332](https://github.com/terrastruct/d2/pull/332)
- ELK layout engine now defaults to top-down to be consistent with dagre.
[#251](https://github.com/terrastruct/d2/pull/251)
- [install.sh](./install.sh) prints the dry run message more visibly.
Expand Down
7 changes: 1 addition & 6 deletions d2layouts/d2sequence/sequence_diagram.go
Original file line number Diff line number Diff line change
Expand Up @@ -267,12 +267,7 @@ func (sd *sequenceDiagram) routeMessages() {
}

if message.Attributes.Label.Value != "" {
if isLeftToRight {
message.LabelPosition = go2.Pointer(string(label.OutsideTopCenter))
} else {
// the label will be placed above the message because the orientation is based on the edge normal vector
message.LabelPosition = go2.Pointer(string(label.OutsideBottomCenter))
}
message.LabelPosition = go2.Pointer(string(label.InsideMiddleCenter))
}
}
}
Expand Down
56 changes: 30 additions & 26 deletions d2renderers/d2svg/d2svg.go
Original file line number Diff line number Diff line change
Expand Up @@ -337,26 +337,15 @@ func pathData(connection d2target.Connection, idToShape map[string]d2target.Shap
return strings.Join(path, " ")
}

func labelMask(id string, connection d2target.Connection, labelTL, tl, br *geo.Point) string {
width := br.X - tl.X
height := br.Y - tl.Y
return strings.Join([]string{
fmt.Sprintf(`<mask id="%s" maskUnits="userSpaceOnUse" x="%f" y="%f" width="%f" height="%f">`,
id, tl.X, tl.Y, width, height,
),
fmt.Sprintf(`<rect x="%f" y="%f" width="%f" height="%f" fill="white"></rect>`,
tl.X, tl.Y, width, height,
),
fmt.Sprintf(`<rect x="%f" y="%f" width="%d" height="%d" fill="black"></rect>`,
labelTL.X, labelTL.Y,
connection.LabelWidth,
connection.LabelHeight,
),
`</mask>`,
}, "\n")
func makeLabelMask(connection d2target.Connection, labelTL, tl, br *geo.Point) string {
return fmt.Sprintf(`<rect x="%f" y="%f" width="%d" height="%d" fill="black"></rect>`,
labelTL.X, labelTL.Y,
connection.LabelWidth,
connection.LabelHeight,
)
}

func drawConnection(writer io.Writer, connection d2target.Connection, markers map[string]struct{}, idToShape map[string]d2target.Shape) {
func drawConnection(writer io.Writer, connection d2target.Connection, markers map[string]struct{}, idToShape map[string]d2target.Shape) (labelMask string) {
fmt.Fprintf(writer, `<g id="%s">`, escapeText(connection.ID))
var markerStart string
if connection.SrcArrow != d2target.NoArrowhead {
Expand Down Expand Up @@ -387,7 +376,6 @@ func drawConnection(writer io.Writer, connection d2target.Connection, markers ma
}

var labelTL *geo.Point
var mask string
if connection.Label != "" {
labelTL = connection.GetLabelTopLeft()
labelTL.X = math.Round(labelTL.X)
Expand Down Expand Up @@ -420,18 +408,15 @@ 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))

maskID := fmt.Sprintf("mask-%s", hash(connection.ID))
fmt.Fprint(writer, labelMask(maskID, connection, labelTL, tl, br))
mask = fmt.Sprintf(`mask="url(#%s)" `, maskID)
labelMask = makeLabelMask(connection, labelTL, tl, br)
}
}

fmt.Fprintf(writer, `<path d="%s" class="connection" style="fill:none;%s" %s%s%s/>`,
fmt.Fprintf(writer, `<path d="%s" class="connection" style="fill:none;%s" %s%smask="url(#labels)"/>`,
pathData(connection, idToShape),
connectionStyle(connection),
markerStart,
markerEnd,
mask,
)

if connection.Label != "" {
Expand Down Expand Up @@ -476,6 +461,7 @@ func drawConnection(writer io.Writer, connection d2target.Connection, markers ma
fmt.Fprint(writer, renderArrowheadLabel(connection, connection.DstLabel, position, size, size))
}
fmt.Fprintf(writer, `</g>`)
return
}

func renderArrowheadLabel(connection d2target.Connection, text string, position, width, height float64) string {
Expand Down Expand Up @@ -955,7 +941,7 @@ func embedFonts(buf *bytes.Buffer) {
// TODO minify output at end
func Render(diagram *d2target.Diagram) ([]byte, error) {
buf := &bytes.Buffer{}
_, _ = setViewbox(buf, diagram)
w, h := setViewbox(buf, diagram)

buf.WriteString(fmt.Sprintf(`<style type="text/css">
<![CDATA[
Expand Down Expand Up @@ -996,10 +982,14 @@ func Render(diagram *d2target.Diagram) ([]byte, error) {

sortObjects(allObjects)

var labelMasks []string
markers := map[string]struct{}{}
for _, obj := range allObjects {
if c, is := obj.(d2target.Connection); is {
drawConnection(buf, c, markers, idToShape)
labelMask := drawConnection(buf, c, markers, idToShape)
if labelMask != "" {
labelMasks = append(labelMasks, labelMask)
}
} else if s, is := obj.(d2target.Shape); is {
err := drawShape(buf, s)
if err != nil {
Expand All @@ -1010,6 +1000,20 @@ func Render(diagram *d2target.Diagram) ([]byte, error) {
}
}

if len(labelMasks) > 0 {
fmt.Fprint(buf, strings.Join([]string{
fmt.Sprintf(`<mask id="labels" maskUnits="userSpaceOnUse" x="0" y="0" width="%d" height="%d">`,
w, h,
),
fmt.Sprintf(`<rect x="0" y="0" width="%d" height="%d" fill="white"></rect>`,
w,
h,
),
strings.Join(labelMasks, "\n"),
`</mask>`,
}, "\n"))
}

embedFonts(buf)

buf.WriteString(`</svg>`)
Expand Down
2 changes: 1 addition & 1 deletion e2etests/testdata/sanity/1_to_2/dagre/sketch.exp.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion e2etests/testdata/sanity/1_to_2/elk/sketch.exp.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion e2etests/testdata/sanity/basic/dagre/sketch.exp.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion e2etests/testdata/sanity/basic/elk/sketch.exp.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading