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

position tooltip/link icons on shape #1466

Merged
merged 9 commits into from
Jul 4, 2023
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
1 change: 1 addition & 0 deletions ci/release/changelogs/next.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
- Improved rendering and text measurement for code shapes [#1425](https://github.com/terrastruct/d2/pull/1425)
- The autoformatter moves board declarations to the bottom of its scope [#1424](https://github.com/terrastruct/d2/pull/1424)
- All font styles in sketch mode use a consistent font-family [#1463](https://github.com/terrastruct/d2/pull/1463)
- Tooltip and link icons are now positioned on shape border [#1466](https://github.com/terrastruct/d2/pull/1466)

#### Bugfixes ⛑️

Expand Down
84 changes: 63 additions & 21 deletions d2renderers/d2svg/d2svg.go
Original file line number Diff line number Diff line change
Expand Up @@ -936,7 +936,7 @@ func drawShape(writer io.Writer, diagramHash string, targetShape d2target.Shape,
} else {
drawClass(writer, diagramHash, targetShape)
}
addAppendixItems(writer, targetShape)
addAppendixItems(writer, targetShape, s)
fmt.Fprint(writer, `</g>`)
fmt.Fprint(writer, closingTag)
return labelMask, nil
Expand All @@ -950,7 +950,7 @@ func drawShape(writer io.Writer, diagramHash string, targetShape d2target.Shape,
} else {
drawTable(writer, diagramHash, targetShape)
}
addAppendixItems(writer, targetShape)
addAppendixItems(writer, targetShape, s)
fmt.Fprint(writer, `</g>`)
fmt.Fprint(writer, closingTag)
return labelMask, nil
Expand Down Expand Up @@ -1341,28 +1341,70 @@ func drawShape(writer io.Writer, diagramHash string, targetShape d2target.Shape,
}
}

addAppendixItems(writer, targetShape)
addAppendixItems(writer, targetShape, s)

fmt.Fprint(writer, closingTag)
return labelMask, nil
}

func addAppendixItems(writer io.Writer, shape d2target.Shape) {
rightPadForTooltip := 0
if shape.Tooltip != "" {
rightPadForTooltip = 2 * appendixIconRadius
func addAppendixItems(writer io.Writer, targetShape d2target.Shape, s shape.Shape) {
var p1, p2 *geo.Point
if targetShape.Tooltip != "" || targetShape.Link != "" {
bothIcons := targetShape.Tooltip != "" && targetShape.Link != ""
corner := geo.NewPoint(float64(targetShape.Pos.X+targetShape.Width), float64(targetShape.Pos.Y))
center := geo.NewPoint(
float64(targetShape.Pos.X)+float64(targetShape.Width)/2.,
float64(targetShape.Pos.Y)+float64(targetShape.Height)/2.,
)
offset := geo.Vector{-2 * appendixIconRadius, 0}
var leftOnShape bool
switch s.GetType() {
case shape.STEP_TYPE, shape.HEXAGON_TYPE, shape.QUEUE_TYPE, shape.PAGE_TYPE:
// trace straight left for these
center.Y = float64(targetShape.Pos.Y)
case shape.PACKAGE_TYPE:
// trace straight down
center.X = float64(targetShape.Pos.X + targetShape.Width)
case shape.CIRCLE_TYPE, shape.OVAL_TYPE, shape.DIAMOND_TYPE,
shape.PERSON_TYPE, shape.CLOUD_TYPE, shape.CYLINDER_TYPE:
if bothIcons {
leftOnShape = true
corner = corner.AddVector(offset)
}
}
v1 := center.VectorTo(corner)
p1 = shape.TraceToShapeBorder(s, corner, corner.AddVector(v1))
if bothIcons {
if leftOnShape {
// these shapes should have p1 on shape border
p2 = p1.AddVector(offset.Reverse())
p1, p2 = p2, p1
} else {
p2 = p1.AddVector(offset)
}
}
}

if targetShape.Tooltip != "" {
x := int(math.Ceil(p1.X))
y := int(math.Ceil(p1.Y))

fmt.Fprintf(writer, `<g transform="translate(%d %d)" class="appendix-icon">%s</g>`,
shape.Pos.X+shape.Width-appendixIconRadius,
shape.Pos.Y-appendixIconRadius,
x-appendixIconRadius,
y-appendixIconRadius,
TooltipIcon,
)
fmt.Fprintf(writer, `<title>%s</title>`, svg.EscapeText(shape.Tooltip))
fmt.Fprintf(writer, `<title>%s</title>`, svg.EscapeText(targetShape.Tooltip))
}

if shape.Link != "" {
if targetShape.Link != "" {
if p2 == nil {
p2 = p1
}
x := int(math.Ceil(p2.X))
y := int(math.Ceil(p2.Y))
fmt.Fprintf(writer, `<g transform="translate(%d %d)" class="appendix-icon">%s</g>`,
shape.Pos.X+shape.Width-appendixIconRadius-rightPadForTooltip,
shape.Pos.Y-appendixIconRadius,
x-appendixIconRadius,
y-appendixIconRadius,
LinkIcon,
)
}
Expand Down Expand Up @@ -1842,17 +1884,17 @@ func Render(diagram *d2target.Diagram, opts *RenderOpts) ([]byte, error) {
case "paper":
patternDefs += paper
}
fmt.Fprint(upperBuf, fmt.Sprintf(`
fmt.Fprintf(upperBuf, `
.%s-overlay {
fill: url(#%s);
mix-blend-mode: multiply;
}`, pattern, pattern))
}`, pattern, pattern)
}
}
if patternDefs != "" {
fmt.Fprint(upperBuf, `]]></style>`)
fmt.Fprint(upperBuf, "<defs>")
fmt.Fprintf(upperBuf, patternDefs)
fmt.Fprint(upperBuf, patternDefs)
fmt.Fprint(upperBuf, "</defs>")
}

Expand Down Expand Up @@ -2101,11 +2143,11 @@ func singleThemeRulesets(diagramHash string, themeID int64) (rulesets string, er
out += fmt.Sprintf(".sketch-overlay-%s{fill:url(#streaks-%s);mix-blend-mode:%s}", color.N7, lc, blendMode(lc))

if theme.IsDark() {
out += fmt.Sprintf(".light-code{display: none}")
out += fmt.Sprintf(".dark-code{display: block}")
out += ".light-code{display: none}"
out += ".dark-code{display: block}"
} else {
out += fmt.Sprintf(".light-code{display: block}")
out += fmt.Sprintf(".dark-code{display: none}")
out += ".light-code{display: block}"
out += ".dark-code{display: none}"
}

return out, nil
Expand Down
1 change: 1 addition & 0 deletions e2etests/stable_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2781,6 +2781,7 @@ scenarios: {
loadFromFile(t, "outside_bottom_labels"),
loadFromFile(t, "label_positions"),
loadFromFile(t, "icon_positions"),
loadFromFile(t, "all_shapes_link"),
}

runa(t, tcs)
Expand Down
141 changes: 141 additions & 0 deletions e2etests/testdata/files/all_shapes_link.d2
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
linked: {
rectangle.shape: rectangle
square.shape: square
page.shape: page
parallelogram.shape: parallelogram
document.shape: document
cylinder.shape: cylinder
queue.shape: queue
package.shape: package
step.shape: step
callout.shape: callout
stored_data.shape: stored_data
person.shape: person
diamond.shape: diamond
oval.shape: oval
circle.shape: circle
hexagon.shape: hexagon
cloud.shape: cloud

rectangle -> square -> page
parallelogram -> document -> cylinder
queue -> package -> step
callout -> stored_data -> person
diamond -> oval -> circle
hexagon -> cloud

rectangle.class: linked
square.class: linked
page.class: linked
parallelogram.class: linked
document.class: linked
cylinder.class: linked
queue.class: linked
package.class: linked
step.class: linked
callout.class: linked
stored_data.class: linked
person.class: linked
diamond.class: linked
oval.class: linked
circle.class: linked
hexagon.class: linked
cloud.class: linked
}

tooltipped: {
rectangle.shape: rectangle
square.shape: square
page.shape: page
parallelogram.shape: parallelogram
document.shape: document
cylinder.shape: cylinder
queue.shape: queue
package.shape: package
step.shape: step
callout.shape: callout
stored_data.shape: stored_data
person.shape: person
diamond.shape: diamond
oval.shape: oval
circle.shape: circle
hexagon.shape: hexagon
cloud.shape: cloud

rectangle -> square -> page
parallelogram -> document -> cylinder
queue -> package -> step
callout -> stored_data -> person
diamond -> oval -> circle
hexagon -> cloud

rectangle.class: tooltipped
square.class: tooltipped
page.class: tooltipped
parallelogram.class: tooltipped
document.class: tooltipped
cylinder.class: tooltipped
queue.class: tooltipped
package.class: tooltipped
step.class: tooltipped
callout.class: tooltipped
stored_data.class: tooltipped
person.class: tooltipped
diamond.class: tooltipped
oval.class: tooltipped
circle.class: tooltipped
hexagon.class: tooltipped
cloud.class: tooltipped
}

both: {
rectangle.shape: rectangle
square.shape: square
page.shape: page
parallelogram.shape: parallelogram
document.shape: document
cylinder.shape: cylinder
queue.shape: queue
package.shape: package
step.shape: step
callout.shape: callout
stored_data.shape: stored_data
person.shape: person
diamond.shape: diamond
oval.shape: oval
circle.shape: circle
hexagon.shape: hexagon
cloud.shape: cloud

rectangle -> square -> page
parallelogram -> document -> cylinder
queue -> package -> step
callout -> stored_data -> person
diamond -> oval -> circle
hexagon -> cloud

rectangle.class: [linked; tooltipped]
square.class: [linked; tooltipped]
page.class: [linked; tooltipped]
parallelogram.class: [linked; tooltipped]
document.class: [linked; tooltipped]
cylinder.class: [linked; tooltipped]
queue.class: [linked; tooltipped]
package.class: [linked; tooltipped]
step.class: [linked; tooltipped]
callout.class: [linked; tooltipped]
stored_data.class: [linked; tooltipped]
person.class: [linked; tooltipped]
diamond.class: [linked; tooltipped]
oval.class: [linked; tooltipped]
circle.class: [linked; tooltipped]
hexagon.class: [linked; tooltipped]
cloud.class: [linked; tooltipped]
}

linked -> tooltipped -> both

classes: {
linked.link: example.com
tooltipped.tooltip: example
}
Loading