diff --git a/d2renderers/d2svg/d2svg.go b/d2renderers/d2svg/d2svg.go
index 37cfd7529..4409e6045 100644
--- a/d2renderers/d2svg/d2svg.go
+++ b/d2renderers/d2svg/d2svg.go
@@ -207,9 +207,9 @@ func arrowheadMarker(isTarget bool, id string, connection d2target.Connection) s
width *= 1.1
default:
if isTarget {
- refX = width - 3/2*strokeWidth
+ refX = width - 1.5*strokeWidth
} else {
- refX = 3 / 2 * strokeWidth
+ refX = 1.5 * strokeWidth
}
}
@@ -225,10 +225,10 @@ func arrowheadMarker(isTarget bool, id string, connection d2target.Connection) s
}
// compute the (dx, dy) adjustment to apply to get the arrowhead-adjusted end point
-func arrowheadAdjustment(start, end *geo.Point, arrowhead d2target.Arrowhead, strokeWidth int) *geo.Point {
- distance := float64(strokeWidth) / 2.0
+func arrowheadAdjustment(start, end *geo.Point, arrowhead d2target.Arrowhead, edgeStrokeWidth, shapeStrokeWidth int) *geo.Point {
+ distance := (float64(edgeStrokeWidth) + float64(shapeStrokeWidth)) / 2.0
if arrowhead != d2target.NoArrowhead {
- distance += float64(strokeWidth)
+ distance += float64(edgeStrokeWidth)
}
v := geo.NewVector(end.X-start.X, end.Y-start.Y)
@@ -236,11 +236,13 @@ func arrowheadAdjustment(start, end *geo.Point, arrowhead d2target.Arrowhead, st
}
// returns the path's d attribute for the given connection
-func pathData(connection d2target.Connection) string {
+func pathData(connection d2target.Connection, idToShape map[string]d2target.Shape) string {
var path []string
route := connection.Route
+ srcShape := idToShape[connection.Src]
+ dstShape := idToShape[connection.Dst]
- sourceAdjustment := arrowheadAdjustment(route[0], route[1], connection.SrcArrow, connection.StrokeWidth)
+ sourceAdjustment := arrowheadAdjustment(route[0], route[1], connection.SrcArrow, connection.StrokeWidth, srcShape.StrokeWidth)
path = append(path, fmt.Sprintf("M %f %f",
route[0].X-sourceAdjustment.X,
route[0].Y-sourceAdjustment.Y,
@@ -256,7 +258,7 @@ func pathData(connection d2target.Connection) string {
))
}
// final curve target adjustment
- targetAdjustment := arrowheadAdjustment(route[i+1], route[i+2], connection.DstArrow, connection.StrokeWidth)
+ targetAdjustment := arrowheadAdjustment(route[i+1], route[i+2], connection.DstArrow, connection.StrokeWidth, dstShape.StrokeWidth)
path = append(path, fmt.Sprintf("C %f %f %f %f %f %f",
route[i].X, route[i].Y,
route[i+1].X, route[i+1].Y,
@@ -315,7 +317,7 @@ func pathData(connection d2target.Connection) string {
lastPoint := route[len(route)-1]
secondToLastPoint := route[len(route)-2]
- targetAdjustment := arrowheadAdjustment(secondToLastPoint, lastPoint, connection.DstArrow, connection.StrokeWidth)
+ targetAdjustment := arrowheadAdjustment(secondToLastPoint, lastPoint, connection.DstArrow, connection.StrokeWidth, dstShape.StrokeWidth)
path = append(path, fmt.Sprintf("L %f %f",
lastPoint.X+targetAdjustment.X,
lastPoint.Y+targetAdjustment.Y,
@@ -344,7 +346,7 @@ func labelMask(id string, connection d2target.Connection, labelTL, tl, br *geo.P
}, "\n")
}
-func drawConnection(writer io.Writer, connection d2target.Connection, markers map[string]struct{}) {
+func drawConnection(writer io.Writer, connection d2target.Connection, markers map[string]struct{}, idToShape map[string]d2target.Shape) {
var markerStart string
if connection.SrcArrow != d2target.NoArrowhead {
id := arrowheadMarkerID(false, connection)
@@ -414,7 +416,7 @@ func drawConnection(writer io.Writer, connection d2target.Connection, markers ma
}
fmt.Fprintf(writer, ``,
- pathData(connection),
+ pathData(connection, idToShape),
connectionStyle(connection),
markerStart,
markerEnd,
@@ -772,9 +774,11 @@ func Render(diagram *d2target.Diagram) ([]byte, error) {
// SVG has no notion of z-index. The z-index is effectively the order it's drawn.
// So draw from the least nested to most nested
+ idToShape := make(map[string]d2target.Shape)
highest := 1
for _, s := range diagram.Shapes {
highest = go2.Max(highest, s.Level)
+ idToShape[s.ID] = s
}
for i := 1; i <= highest; i++ {
for _, s := range diagram.Shapes {
@@ -789,7 +793,7 @@ func Render(diagram *d2target.Diagram) ([]byte, error) {
markers := map[string]struct{}{}
for _, c := range diagram.Connections {
- drawConnection(buf, c, markers)
+ drawConnection(buf, c, markers, idToShape)
}
embedFonts(buf)
diff --git a/e2etests/stable_test.go b/e2etests/stable_test.go
index 5a5fc0e77..3aafba44d 100644
--- a/e2etests/stable_test.go
+++ b/e2etests/stable_test.go
@@ -637,6 +637,45 @@ func RegisterHash(h Hash, f func() hash.Hash) {
}
|
x -> hey -> y`,
+ }, {
+ name: "arrowhead_adjustment",
+ script: `a <-> b: {
+ style.stroke-width: 6
+ style.stroke-dash: 4
+ source-arrowhead: {
+ shape: arrow
+ }
+ }
+
+ c -> b: {
+ style.stroke-width: 7
+ style.stroke: "#20222a"
+ }
+ c.style.stroke-width: 7
+ c.style.stroke: "#b2350d"
+ c.shape: document
+ b.style.stroke-width: 8
+ b.style.stroke: "#0db254"
+ a.style.border-radius: 10
+ a.style.stroke-width: 8
+ a.style.stroke: "#2bc3d8"
+ Oval: "" {
+ shape: oval
+ style.stroke-width: 6
+ style.stroke: "#a1a4af"
+ }
+ a <-> Oval: {
+ style.stroke-width: 6
+ source-arrowhead: {
+ shape: diamond
+ }
+ target-arrowhead: * {
+ shape: diamond
+ style.filled: true
+ }
+ }
+ c -- a: {style.stroke-width: 7}
+ Oval <-> c`,
},
{
name: "md_code_inline",
diff --git a/e2etests/testdata/stable/all_shapes/sketch.exp.svg b/e2etests/testdata/stable/all_shapes/sketch.exp.svg
index fcf7d2fdb..3c83a55c5 100644
--- a/e2etests/testdata/stable/all_shapes/sketch.exp.svg
+++ b/e2etests/testdata/stable/all_shapes/sketch.exp.svg
@@ -12,7 +12,7 @@ width="1539" height="824" viewBox="-100 -100 1539 824">rectanglesquarepageparallelogramdocumentcylinderqueuepackagestepcalloutstored_datapersondiamondovalcirclehexagoncloud rectanglesquarepageparallelogramdocumentcylinderqueuepackagestepcalloutstored_datapersondiamondovalcirclehexagoncloud cba
\ No newline at end of file
diff --git a/e2etests/testdata/stable/binary_tree/sketch.exp.svg b/e2etests/testdata/stable/binary_tree/sketch.exp.svg
index e627cc671..c7029d6f7 100644
--- a/e2etests/testdata/stable/binary_tree/sketch.exp.svg
+++ b/e2etests/testdata/stable/binary_tree/sketch.exp.svg
@@ -12,7 +12,7 @@ width="1518" height="1004" viewBox="-100 -100 1518 1004">abcdefghijklmno abcdefghijklmno aaadddeeebbbccc
-111
+111
-222abcd abcd abc abc acfbdhg acfbdhg agdfbhec agdfbhec abcdefghijklmnopq abcdefghijklmnopq finallyatreeandnodessomemoremanythenhereyouhavehierarchyanotherofnestingtreesatreeinsidehierarchyroot finallyatreeandnodessomemoremanythenhereyouhavehierarchyanotherofnestingtreesatreeinsidehierarchyroot aabbccddllffwwyyadnniijjkkssuurmeemmmmgghhzzooppqqrrttvvxxabac
+aabbccddllffwwyyadnniijjkkssuurmeemmmmgghhzzooppqqrrttvvxxabac
-1
+1
-2
+2
-3
+3
-4
+4
-5
+5
-6abcdefghiqrjmnoszaabbeeffggklptuwxyccddv abcdefghiqrjmnoszaabbeeffggklptuwxyccddv Markdown: Syntax
-
ab ab abcdefghijklmnopqrstuvw abcdefghijklmnopqrstuvw abcdefghijklmnopqrstu abcdefghijklmnopqrstu acdefgbh acdefgbh topabcbottomstartend topabcbottomstartend acbl1l2c1l2c3l2c2l3c1l3c2l4bacacbabcc1c2c3abc acbl1l2c1l2c3l2c2l3c1l3c2l4bacacbabcc1c2c3abc AKHIALFLGAMSTNAZCANVNMUTARLAMOOKTXORCOKSNEWYCTMANYRIDEMDNJPANCSCIDMTWAILINIAMIKYWIOHMNSDVAWVMENHVTNDAKHIALFLGAMSTNAZCANVNMUTARLAMOOKTXORCOKSNEWYCTMANYRIDEMDNJPANCSCIDMTWAILINIAMIKYWIOHMNSDVAWVMENHVTND