diff --git a/ci/release/changelogs/next.md b/ci/release/changelogs/next.md index b3f8fa64d..031a3414a 100644 --- a/ci/release/changelogs/next.md +++ b/ci/release/changelogs/next.md @@ -10,4 +10,4 @@ For v0.0.99 we focused on X, Y and Z. Enjoy! #### Bugfixes 🔴 -- Fixes something or the other #9999 +- The svg renderer now displays arrowhead labels fixing #169 diff --git a/d2renderers/d2svg/d2svg.go b/d2renderers/d2svg/d2svg.go index ec8e33d55..e234c9df4 100644 --- a/d2renderers/d2svg/d2svg.go +++ b/d2renderers/d2svg/d2svg.go @@ -447,6 +447,39 @@ func drawConnection(writer io.Writer, connection d2target.Connection, markers ma renderText(connection.Label, x, float64(connection.LabelHeight)), ) } + + 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)) + } +} + +func renderArrowheadLabel(connection d2target.Connection, text string, position, width, height float64) string { + labelTL := label.UnlockedTop.GetPointOnRoute(connection.Route, float64(connection.StrokeWidth), position, width, height) + + textStyle := fmt.Sprintf("text-anchor:%s;font-size:%vpx;fill:%s", "middle", connection.FontSize, "black") + x := labelTL.X + width/2 + y := labelTL.Y + float64(connection.FontSize) + return fmt.Sprintf(`%s`, + x, y, + textStyle, + renderText(text, x, height), + ) } func renderOval(tl *geo.Point, width, height float64, style string) string { diff --git a/e2etests/report/main.go b/e2etests/report/main.go index 81ae168d3..c471991ca 100644 --- a/e2etests/report/main.go +++ b/e2etests/report/main.go @@ -85,13 +85,14 @@ func main() { } if testFile != nil { + testCaseRoot := filepath.Dir(path) matchTestCase := true if testCaseFlag != "" { - matchTestCase, _ = regexp.MatchString(testCaseFlag, filepath.Base(path)) + matchTestCase, _ = regexp.MatchString(testCaseFlag, filepath.Base(testCaseRoot)) } matchTestSet := true if testSetFlag != "" { - matchTestSet, _ = regexp.MatchString(testSetFlag, filepath.Base(filepath.Dir(path))) + matchTestSet, _ = regexp.MatchString(testSetFlag, filepath.Base(filepath.Dir(testCaseRoot))) } if matchTestSet && matchTestCase { @@ -101,17 +102,19 @@ func main() { if _, err := os.Stat(gotPath); err == nil { hasGot = true } + // e.g. arrowhead_adjustment/dagre + name := filepath.Join(filepath.Base(testCaseRoot), info.Name()) if deltaFlag { if hasGot { tests = append(tests, TestItem{ - Name: info.Name(), + Name: name, ExpSVG: &fullPath, GotSVG: gotPath, }) } } else { test := TestItem{ - Name: info.Name(), + Name: name, ExpSVG: nil, GotSVG: fullPath, } diff --git a/e2etests/stable_test.go b/e2etests/stable_test.go index b48e2b20e..6f03c9570 100644 --- a/e2etests/stable_test.go +++ b/e2etests/stable_test.go @@ -881,6 +881,17 @@ b: { icon: https://icons.terrastruct.com/essentials/004-picture.svg } a -> b +`, + }, + { + name: "arrowhead_labels", + script: ` +a -> b: To err is human, to moo bovine { + source-arrowhead: 1 + target-arrowhead: * { + shape: diamond + } +} `, }, } diff --git a/e2etests/testdata/stable/arrowhead_adjustment/dagre/sketch.exp.svg b/e2etests/testdata/stable/arrowhead_adjustment/dagre/sketch.exp.svg index 83d10d7a0..0009a91a5 100644 --- a/e2etests/testdata/stable/arrowhead_adjustment/dagre/sketch.exp.svg +++ b/e2etests/testdata/stable/arrowhead_adjustment/dagre/sketch.exp.svg @@ -14,11 +14,18 @@ width="480" height="778" viewBox="-100 -100 480 778">cba cba * \ No newline at end of file diff --git a/e2etests/testdata/stable/arrowhead_adjustment/elk/sketch.exp.svg b/e2etests/testdata/stable/arrowhead_adjustment/elk/sketch.exp.svg index e0d6183d7..d537b4b4b 100644 --- a/e2etests/testdata/stable/arrowhead_adjustment/elk/sketch.exp.svg +++ b/e2etests/testdata/stable/arrowhead_adjustment/elk/sketch.exp.svg @@ -14,11 +14,18 @@ width="749" height="446" viewBox="-88 -88 749 446">cba cba * \ No newline at end of file diff --git a/e2etests/testdata/stable/arrowhead_labels/dagre/board.exp.json b/e2etests/testdata/stable/arrowhead_labels/dagre/board.exp.json new file mode 100644 index 000000000..60b8d8edd --- /dev/null +++ b/e2etests/testdata/stable/arrowhead_labels/dagre/board.exp.json @@ -0,0 +1,130 @@ +{ + "name": "", + "shapes": [ + { + "id": "a", + "type": "", + "pos": { + "x": 0, + "y": 0 + }, + "width": 113, + "height": 126, + "level": 1, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "fields": null, + "methods": null, + "columns": null, + "label": "a", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 13, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER" + }, + { + "id": "b", + "type": "", + "pos": { + "x": 0, + "y": 226 + }, + "width": 113, + "height": 126, + "level": 1, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "fields": null, + "methods": null, + "columns": null, + "label": "b", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 13, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER" + } + ], + "connections": [ + { + "id": "(a -> b)[0]", + "src": "a", + "srcArrow": "none", + "srcLabel": "1", + "dst": "b", + "dstArrow": "diamond", + "dstLabel": "*", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "#0D32B2", + "label": "To err is human, to moo bovine", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 201, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPercentage": 0, + "route": [ + { + "x": 56.5, + "y": 126 + }, + { + "x": 56.5, + "y": 166 + }, + { + "x": 56.5, + "y": 186 + }, + { + "x": 56.5, + "y": 226 + } + ], + "isCurve": true, + "animated": false, + "tooltip": "", + "icon": null + } + ] +} diff --git a/e2etests/testdata/stable/arrowhead_labels/dagre/sketch.exp.svg b/e2etests/testdata/stable/arrowhead_labels/dagre/sketch.exp.svg new file mode 100644 index 000000000..65b651774 --- /dev/null +++ b/e2etests/testdata/stable/arrowhead_labels/dagre/sketch.exp.svg @@ -0,0 +1,34 @@ + +ab + + +To err is human, to moo bovine1* \ No newline at end of file diff --git a/e2etests/testdata/stable/arrowhead_labels/elk/board.exp.json b/e2etests/testdata/stable/arrowhead_labels/elk/board.exp.json new file mode 100644 index 000000000..a0458a9db --- /dev/null +++ b/e2etests/testdata/stable/arrowhead_labels/elk/board.exp.json @@ -0,0 +1,121 @@ +{ + "name": "", + "shapes": [ + { + "id": "a", + "type": "", + "pos": { + "x": 12, + "y": 12 + }, + "width": 113, + "height": 126, + "level": 1, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "fields": null, + "methods": null, + "columns": null, + "label": "a", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 13, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER" + }, + { + "id": "b", + "type": "", + "pos": { + "x": 526, + "y": 12 + }, + "width": 113, + "height": 126, + "level": 1, + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "borderRadius": 0, + "fill": "#F7F8FE", + "stroke": "#0D32B2", + "shadow": false, + "3d": false, + "multiple": false, + "tooltip": "", + "link": "", + "icon": null, + "iconPosition": "", + "fields": null, + "methods": null, + "columns": null, + "label": "b", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#0A0F25", + "italic": false, + "bold": true, + "underline": false, + "labelWidth": 13, + "labelHeight": 26, + "labelPosition": "INSIDE_MIDDLE_CENTER" + } + ], + "connections": [ + { + "id": "(a -> b)[0]", + "src": "a", + "srcArrow": "none", + "srcLabel": "1", + "dst": "b", + "dstArrow": "diamond", + "dstLabel": "*", + "opacity": 1, + "strokeDash": 0, + "strokeWidth": 2, + "stroke": "#0D32B2", + "label": "To err is human, to moo bovine", + "fontSize": 16, + "fontFamily": "DEFAULT", + "language": "", + "color": "#676C7E", + "italic": true, + "bold": false, + "underline": false, + "labelWidth": 201, + "labelHeight": 21, + "labelPosition": "INSIDE_MIDDLE_CENTER", + "labelPercentage": 0, + "route": [ + { + "x": 125, + "y": 75 + }, + { + "x": 526, + "y": 75 + } + ], + "animated": false, + "tooltip": "", + "icon": null + } + ] +} diff --git a/e2etests/testdata/stable/arrowhead_labels/elk/sketch.exp.svg b/e2etests/testdata/stable/arrowhead_labels/elk/sketch.exp.svg new file mode 100644 index 000000000..fc098f10b --- /dev/null +++ b/e2etests/testdata/stable/arrowhead_labels/elk/sketch.exp.svg @@ -0,0 +1,34 @@ + +ab + + +To err is human, to moo bovine1* \ No newline at end of file diff --git a/out/.gitignore b/out/.gitignore new file mode 100644 index 000000000..e69de29bb