Merge pull request #1466 from gavin-ts/shape-specific-link-position

position tooltip/link icons on shape
This commit is contained in:
gavin-ts 2023-07-03 19:05:58 -07:00 committed by GitHub
commit 6a1bfaac4f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 10064 additions and 22 deletions

View file

@ -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 ⛑️

View file

@ -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
@ -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
@ -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
fmt.Fprintf(writer, `<g transform="translate(%d %d)" class="appendix-icon">%s</g>`,
shape.Pos.X+shape.Width-appendixIconRadius,
shape.Pos.Y-appendixIconRadius,
TooltipIcon,
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.,
)
fmt.Fprintf(writer, `<title>%s</title>`, svg.EscapeText(shape.Tooltip))
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 shape.Link != "" {
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-rightPadForTooltip,
shape.Pos.Y-appendixIconRadius,
x-appendixIconRadius,
y-appendixIconRadius,
TooltipIcon,
)
fmt.Fprintf(writer, `<title>%s</title>`, svg.EscapeText(targetShape.Tooltip))
}
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>`,
x-appendixIconRadius,
y-appendixIconRadius,
LinkIcon,
)
}
@ -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>")
}
@ -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

View file

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

View file

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

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 141 KiB

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 139 KiB