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

Update arrowhead label positioning and use label dimensions #1207

Merged
merged 14 commits into from
Apr 17, 2023
  •  
  •  
  •  
12 changes: 10 additions & 2 deletions d2exporter/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,11 @@ func toConnection(edge *d2graph.Edge, theme *d2themes.Theme) d2target.Connection
}
if edge.SrcArrowhead != nil {
if edge.SrcArrowhead.Label.Value != "" {
connection.SrcLabel = edge.SrcArrowhead.Label.Value
connection.SrcLabel = &d2target.Text{
Label: edge.SrcArrowhead.Label.Value,
LabelWidth: edge.SrcArrowhead.LabelDimensions.Width,
LabelHeight: edge.SrcArrowhead.LabelDimensions.Height,
}
}
}
if edge.DstArrow {
Expand All @@ -230,7 +234,11 @@ func toConnection(edge *d2graph.Edge, theme *d2themes.Theme) d2target.Connection
}
if edge.DstArrowhead != nil {
if edge.DstArrowhead.Label.Value != "" {
connection.DstLabel = edge.DstArrowhead.Label.Value
connection.DstLabel = &d2target.Text{
Label: edge.DstArrowhead.Label.Value,
LabelWidth: edge.DstArrowhead.LabelDimensions.Width,
LabelHeight: edge.DstArrowhead.LabelDimensions.Height,
}
}
}
if theme != nil && theme.SpecialRules.NoCornerRadius {
Expand Down
35 changes: 18 additions & 17 deletions d2graph/d2graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
)

const INNER_LABEL_PADDING int = 5
const EDGE_LABEL_PADDING int = 5
const DEFAULT_SHAPE_SIZE = 100.
const MIN_SHAPE_SIZE = 5

Expand Down Expand Up @@ -1471,21 +1472,27 @@ func (g *Graph) SetDimensions(mtexts []*d2target.MText, ruler *textmeasure.Ruler
}
}
for _, edge := range g.Edges {
endpointLabels := []string{}
usedFont := fontFamily
if edge.Style.Font != nil {
f := d2fonts.D2_FONT_TO_FAMILY[edge.Style.Font.Value]
usedFont = &f
}

if edge.SrcArrowhead != nil && edge.SrcArrowhead.Label.Value != "" {
endpointLabels = append(endpointLabels, edge.SrcArrowhead.Label.Value)
t := edge.Text()
t.Text = edge.SrcArrowhead.Label.Value
dims := GetTextDimensions(mtexts, ruler, t, usedFont)
edge.MinWidth += dims.Width + EDGE_LABEL_PADDING
edge.MinHeight += dims.Height + EDGE_LABEL_PADDING
edge.SrcArrowhead.LabelDimensions = *dims
}
if edge.DstArrowhead != nil && edge.DstArrowhead.Label.Value != "" {
endpointLabels = append(endpointLabels, edge.DstArrowhead.Label.Value)
}

for _, label := range endpointLabels {
t := edge.Text()
t.Text = label
dims := GetTextDimensions(mtexts, ruler, t, fontFamily)
edge.MinWidth += dims.Width
// Some padding as it's not totally near the end
edge.MinHeight += dims.Height + 5
t.Text = edge.DstArrowhead.Label.Value
dims := GetTextDimensions(mtexts, ruler, t, usedFont)
edge.MinWidth += dims.Width + EDGE_LABEL_PADDING
edge.MinHeight += dims.Height + EDGE_LABEL_PADDING
edge.DstArrowhead.LabelDimensions = *dims
}

if edge.Label.Value == "" {
Expand All @@ -1497,12 +1504,6 @@ func (g *Graph) SetDimensions(mtexts []*d2target.MText, ruler *textmeasure.Ruler
}
edge.ApplyTextTransform()

usedFont := fontFamily
if edge.Style.Font != nil {
f := d2fonts.D2_FONT_TO_FAMILY[edge.Style.Font.Value]
usedFont = &f
}

dims := GetTextDimensions(mtexts, ruler, edge.Text(), usedFont)
if dims == nil {
return fmt.Errorf("dimensions for edge label %#v not found", edge.Text())
Expand Down
154 changes: 77 additions & 77 deletions d2renderers/d2sketch/testdata/all_shapes/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.
154 changes: 77 additions & 77 deletions d2renderers/d2sketch/testdata/all_shapes_dark/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.
160 changes: 80 additions & 80 deletions d2renderers/d2sketch/testdata/animated/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.
160 changes: 80 additions & 80 deletions d2renderers/d2sketch/testdata/animated_dark/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.
160 changes: 80 additions & 80 deletions d2renderers/d2sketch/testdata/arrowheads/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.
160 changes: 80 additions & 80 deletions d2renderers/d2sketch/testdata/arrowheads_dark/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.
154 changes: 77 additions & 77 deletions d2renderers/d2sketch/testdata/basic/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.
154 changes: 77 additions & 77 deletions d2renderers/d2sketch/testdata/basic_dark/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.
160 changes: 80 additions & 80 deletions d2renderers/d2sketch/testdata/child_to_child/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.
160 changes: 80 additions & 80 deletions d2renderers/d2sketch/testdata/child_to_child_dark/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.
160 changes: 80 additions & 80 deletions d2renderers/d2sketch/testdata/connection_label/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.
160 changes: 80 additions & 80 deletions d2renderers/d2sketch/testdata/connection_label_dark/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.
154 changes: 77 additions & 77 deletions d2renderers/d2sketch/testdata/crows_feet/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.
154 changes: 77 additions & 77 deletions d2renderers/d2sketch/testdata/crows_feet_dark/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.
154 changes: 77 additions & 77 deletions d2renderers/d2sketch/testdata/dots-all/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.
154 changes: 77 additions & 77 deletions d2renderers/d2sketch/testdata/dots-multiple/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.
160 changes: 80 additions & 80 deletions d2renderers/d2sketch/testdata/dots-real/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.
154 changes: 77 additions & 77 deletions d2renderers/d2sketch/testdata/elk_corners/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.
568 changes: 284 additions & 284 deletions d2renderers/d2sketch/testdata/opacity/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.
568 changes: 284 additions & 284 deletions d2renderers/d2sketch/testdata/opacity_dark/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.
160 changes: 80 additions & 80 deletions d2renderers/d2sketch/testdata/paper-real/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.
562 changes: 281 additions & 281 deletions d2renderers/d2sketch/testdata/root-fill/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.
154 changes: 77 additions & 77 deletions d2renderers/d2sketch/testdata/sql_tables/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.
154 changes: 77 additions & 77 deletions d2renderers/d2sketch/testdata/sql_tables_dark/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.
160 changes: 80 additions & 80 deletions d2renderers/d2sketch/testdata/terminal/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.
568 changes: 284 additions & 284 deletions d2renderers/d2sketch/testdata/twitter/sketch.exp.svg

Large diffs are not rendered by default.

568 changes: 284 additions & 284 deletions d2renderers/d2sketch/testdata/twitter_dark/sketch.exp.svg

Large diffs are not rendered by default.

Large diffs are not rendered by default.

152 changes: 76 additions & 76 deletions d2renderers/d2svg/appendix/testdata/links/sketch.exp.svg

Large diffs are not rendered by default.

152 changes: 76 additions & 76 deletions d2renderers/d2svg/appendix/testdata/links_dark/sketch.exp.svg

Large diffs are not rendered by default.

152 changes: 76 additions & 76 deletions d2renderers/d2svg/appendix/testdata/tooltip_fill/sketch.exp.svg

Large diffs are not rendered by default.

Large diffs are not rendered by default.

98 changes: 27 additions & 71 deletions d2renderers/d2svg/d2svg.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ import (
"github.com/alecthomas/chroma/v2/lexers"
"github.com/alecthomas/chroma/v2/styles"

"oss.terrastruct.com/util-go/go2"

"oss.terrastruct.com/d2/d2graph"
"oss.terrastruct.com/d2/d2renderers/d2fonts"
"oss.terrastruct.com/d2/d2renderers/d2latex"
Expand All @@ -39,8 +37,7 @@ import (
)

const (
DEFAULT_PADDING = 100
MIN_ARROWHEAD_STROKE_WIDTH = 2
DEFAULT_PADDING = 100

appendixIconRadius = 16
)
Expand Down Expand Up @@ -109,56 +106,13 @@ func arrowheadMarkerID(isTarget bool, connection d2target.Connection) string {
)))
}

func arrowheadDimensions(arrowhead d2target.Arrowhead, strokeWidth float64) (width, height float64) {
var baseWidth, baseHeight float64
var widthMultiplier, heightMultiplier float64
switch arrowhead {
case d2target.ArrowArrowhead:
baseWidth = 4
baseHeight = 4
widthMultiplier = 4
heightMultiplier = 4
case d2target.TriangleArrowhead:
baseWidth = 4
baseHeight = 4
widthMultiplier = 3
heightMultiplier = 4
case d2target.LineArrowhead:
widthMultiplier = 5
heightMultiplier = 8
case d2target.FilledDiamondArrowhead:
baseWidth = 11
baseHeight = 7
widthMultiplier = 5.5
heightMultiplier = 3.5
case d2target.DiamondArrowhead:
baseWidth = 11
baseHeight = 9
widthMultiplier = 5.5
heightMultiplier = 4.5
case d2target.FilledCircleArrowhead, d2target.CircleArrowhead:
baseWidth = 8
baseHeight = 8
widthMultiplier = 5
heightMultiplier = 5
case d2target.CfOne, d2target.CfMany, d2target.CfOneRequired, d2target.CfManyRequired:
baseWidth = 9
baseHeight = 9
widthMultiplier = 4.5
heightMultiplier = 4.5
}

clippedStrokeWidth := go2.Max(MIN_ARROWHEAD_STROKE_WIDTH, strokeWidth)
return baseWidth + clippedStrokeWidth*widthMultiplier, baseHeight + clippedStrokeWidth*heightMultiplier
}

func arrowheadMarker(isTarget bool, id string, connection d2target.Connection) string {
arrowhead := connection.DstArrow
if !isTarget {
arrowhead = connection.SrcArrow
}
strokeWidth := float64(connection.StrokeWidth)
width, height := arrowheadDimensions(arrowhead, strokeWidth)
width, height := arrowhead.Dimensions(strokeWidth)

var path string
switch arrowhead {
Expand Down Expand Up @@ -620,38 +574,40 @@ func drawConnection(writer io.Writer, labelMaskID string, connection d2target.Co
fmt.Fprint(writer, textEl.Render())
}

length := geo.Route(connection.Route).Length()
if connection.SrcLabel != "" {
// TODO use arrowhead label dimensions https://github.com/terrastruct/d2/issues/183
size := float64(connection.FontSize)
position := 0.
if length > 0 {
position = size / length
}
fmt.Fprint(writer, renderArrowheadLabel(connection, connection.SrcLabel, position, size, size))
}
if connection.DstLabel != "" {
// TODO use arrowhead label dimensions https://github.com/terrastruct/d2/issues/183
size := float64(connection.FontSize)
position := 1.
if length > 0 {
position -= size / length
}
fmt.Fprint(writer, renderArrowheadLabel(connection, connection.DstLabel, position, size, size))
if connection.SrcLabel != nil && connection.SrcLabel.Label != "" {
fmt.Fprint(writer, renderArrowheadLabel(connection, connection.SrcLabel.Label, false))
}
if connection.DstLabel != nil && connection.DstLabel.Label != "" {
fmt.Fprint(writer, renderArrowheadLabel(connection, connection.DstLabel.Label, true))
}
fmt.Fprintf(writer, `</g>`)
return
}

func renderArrowheadLabel(connection d2target.Connection, text string, position, width, height float64) string {
labelTL := label.UnlockedTop.GetPointOnRoute(connection.Route, float64(connection.StrokeWidth), position, width, height)
func renderArrowheadLabel(connection d2target.Connection, text string, isDst bool) string {
var width, height float64
if isDst {
width = float64(connection.DstLabel.LabelWidth)
height = float64(connection.DstLabel.LabelHeight)
} else {
width = float64(connection.SrcLabel.LabelWidth)
height = float64(connection.SrcLabel.LabelHeight)
}

labelTL := connection.GetArrowheadLabelPosition(isDst)

// svg text is positioned with the center of its baseline
baselineCenter := geo.Point{
X: labelTL.X + width/2.,
Y: labelTL.Y + float64(connection.FontSize),
}

textEl := d2themes.NewThemableElement("text")
textEl.X = labelTL.X + width/2
textEl.Y = labelTL.Y + float64(connection.FontSize)
textEl.X = baselineCenter.X
textEl.Y = baselineCenter.Y
textEl.Fill = d2target.FG_COLOR
textEl.ClassName = "text-italic"
textEl.Style = fmt.Sprintf("text-anchor:%s;font-size:%vpx", "middle", connection.FontSize)
textEl.Style = fmt.Sprintf("text-anchor:middle;font-size:%vpx", connection.FontSize)
textEl.Content = RenderText(text, textEl.X, height)
return textEl.Render()
}
Expand Down
Loading