diff --git a/d2renderers/d2svg/d2svg.go b/d2renderers/d2svg/d2svg.go
index 2ff96d2eb..2b48d70ef 100644
--- a/d2renderers/d2svg/d2svg.go
+++ b/d2renderers/d2svg/d2svg.go
@@ -461,8 +461,12 @@ func drawConnection(writer io.Writer, labelMaskID string, connection d2target.Co
}
fmt.Fprintf(writer, out)
} else {
- fmt.Fprintf(writer, ``,
- path, connectionStyle(connection), attrs)
+ animatedClass := ""
+ if connection.Animated {
+ animatedClass = " animated-connection"
+ }
+ fmt.Fprintf(writer, ``,
+ path, animatedClass, connectionStyle(connection), attrs)
}
if connection.Label != "" {
@@ -968,11 +972,14 @@ func connectionStyle(connection d2target.Connection) string {
out += fmt.Sprintf(`stroke:%s;`, connection.Stroke)
out += fmt.Sprintf(`opacity:%f;`, connection.Opacity)
out += fmt.Sprintf(`stroke-width:%d;`, connection.StrokeWidth)
- if connection.StrokeDash != 0 {
- dashSize, gapSize := svg.GetStrokeDashAttributes(float64(connection.StrokeWidth), connection.StrokeDash)
+ strokeDash := connection.StrokeDash
+ if strokeDash == 0 && connection.Animated {
+ strokeDash = 5
+ }
+ if strokeDash != 0 {
+ dashSize, gapSize := svg.GetStrokeDashAttributes(float64(connection.StrokeWidth), strokeDash)
out += fmt.Sprintf(`stroke-dasharray:%f,%f;`, dashSize, gapSize)
}
-
return out
}
@@ -1015,6 +1022,27 @@ func embedFonts(buf *bytes.Buffer, fontFamily *d2fonts.FontFamily) {
}
}
+ triggers = []string{
+ `animated-connection`,
+ }
+
+ for _, t := range triggers {
+ if strings.Contains(content, t) {
+ buf.WriteString(`
+@keyframes dashdraw {
+ from {
+ stroke-dashoffset: 30;
+ }
+}
+
+.animated-connection {
+ stroke-dasharray: 15 15;
+ animation: dashdraw 0.5s linear infinite;
+}`)
+ break
+ }
+ }
+
triggers = []string{
`appendix-icon`,
}
diff --git a/d2renderers/d2svg/style.css b/d2renderers/d2svg/style.css
index 5a7bc3b10..2476c6ae7 100644
--- a/d2renderers/d2svg/style.css
+++ b/d2renderers/d2svg/style.css
@@ -10,15 +10,3 @@
mix-blend-mode: multiply;
opacity: 0.5;
}
-
-
-@keyframes dashdraw {
- from {
- stroke-dashoffset: 30;
- }
-}
-
-path[stroke-dasharray] {
- stroke-dasharray: 15 15;
- animation: dashdraw 0.5s linear infinite;
-}
diff --git a/e2etests/stable_test.go b/e2etests/stable_test.go
index a8acc138a..f9b064710 100644
--- a/e2etests/stable_test.go
+++ b/e2etests/stable_test.go
@@ -1764,6 +1764,13 @@ e <--> f: {
}
}`,
},
+ {
+ name: "animated",
+ script: `
+your love life will be -> happy: { style.animated: true }
+your love life will be -> harmonious: { style.animated: true }
+`,
+ },
}
runa(t, tcs)
diff --git a/e2etests/testdata/regression/dagre_edge_label_spacing/dagre/sketch.exp.svg b/e2etests/testdata/regression/dagre_edge_label_spacing/dagre/sketch.exp.svg
index 24918268a..1e7b73085 100644
--- a/e2etests/testdata/regression/dagre_edge_label_spacing/dagre/sketch.exp.svg
+++ b/e2etests/testdata/regression/dagre_edge_label_spacing/dagre/sketch.exp.svg
@@ -18,18 +18,6 @@ width="2832" height="441" viewBox="-102 -102 2832 441">your love life will behappyharmonious
+
+
+
\ No newline at end of file
diff --git a/e2etests/testdata/stable/animated/elk/board.exp.json b/e2etests/testdata/stable/animated/elk/board.exp.json
new file mode 100644
index 000000000..89d3c0453
--- /dev/null
+++ b/e2etests/testdata/stable/animated/elk/board.exp.json
@@ -0,0 +1,214 @@
+{
+ "name": "",
+ "fontFamily": "SourceSansPro",
+ "shapes": [
+ {
+ "id": "your love life will be",
+ "type": "",
+ "pos": {
+ "x": 111,
+ "y": 12
+ },
+ "width": 247,
+ "height": 126,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "#F7F8FE",
+ "stroke": "#0D32B2",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "your love life will be",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#0A0F25",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 147,
+ "labelHeight": 26,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 1
+ },
+ {
+ "id": "happy",
+ "type": "",
+ "pos": {
+ "x": 12,
+ "y": 238
+ },
+ "width": 149,
+ "height": 126,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "#F7F8FE",
+ "stroke": "#0D32B2",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "happy",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#0A0F25",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 49,
+ "labelHeight": 26,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 1
+ },
+ {
+ "id": "harmonious",
+ "type": "",
+ "pos": {
+ "x": 181,
+ "y": 238
+ },
+ "width": 190,
+ "height": 126,
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "borderRadius": 0,
+ "fill": "#F7F8FE",
+ "stroke": "#0D32B2",
+ "shadow": false,
+ "3d": false,
+ "multiple": false,
+ "tooltip": "",
+ "link": "",
+ "icon": null,
+ "iconPosition": "",
+ "blend": false,
+ "fields": null,
+ "methods": null,
+ "columns": null,
+ "label": "harmonious",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#0A0F25",
+ "italic": false,
+ "bold": true,
+ "underline": false,
+ "labelWidth": 90,
+ "labelHeight": 26,
+ "labelPosition": "INSIDE_MIDDLE_CENTER",
+ "zIndex": 0,
+ "level": 1
+ }
+ ],
+ "connections": [
+ {
+ "id": "(your love life will be -> happy)[0]",
+ "src": "your love life will be",
+ "srcArrow": "none",
+ "srcLabel": "",
+ "dst": "happy",
+ "dstArrow": "triangle",
+ "dstLabel": "",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "stroke": "#0D32B2",
+ "label": "",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#676C7E",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 0,
+ "labelHeight": 0,
+ "labelPosition": "",
+ "labelPercentage": 0,
+ "route": [
+ {
+ "x": 193.66666666666669,
+ "y": 138
+ },
+ {
+ "x": 193.66666666666669,
+ "y": 188
+ },
+ {
+ "x": 86.5,
+ "y": 188
+ },
+ {
+ "x": 86.5,
+ "y": 238
+ }
+ ],
+ "animated": true,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 0
+ },
+ {
+ "id": "(your love life will be -> harmonious)[0]",
+ "src": "your love life will be",
+ "srcArrow": "none",
+ "srcLabel": "",
+ "dst": "harmonious",
+ "dstArrow": "triangle",
+ "dstLabel": "",
+ "opacity": 1,
+ "strokeDash": 0,
+ "strokeWidth": 2,
+ "stroke": "#0D32B2",
+ "label": "",
+ "fontSize": 16,
+ "fontFamily": "DEFAULT",
+ "language": "",
+ "color": "#676C7E",
+ "italic": true,
+ "bold": false,
+ "underline": false,
+ "labelWidth": 0,
+ "labelHeight": 0,
+ "labelPosition": "",
+ "labelPercentage": 0,
+ "route": [
+ {
+ "x": 276,
+ "y": 138
+ },
+ {
+ "x": 276,
+ "y": 238
+ }
+ ],
+ "animated": true,
+ "tooltip": "",
+ "icon": null,
+ "zIndex": 0
+ }
+ ]
+}
diff --git a/e2etests/testdata/stable/animated/elk/sketch.exp.svg b/e2etests/testdata/stable/animated/elk/sketch.exp.svg
new file mode 100644
index 000000000..6adb4db90
--- /dev/null
+++ b/e2etests/testdata/stable/animated/elk/sketch.exp.svg
@@ -0,0 +1,62 @@
+
+
\ No newline at end of file
diff --git a/e2etests/testdata/stable/arrowhead_adjustment/dagre/sketch.exp.svg b/e2etests/testdata/stable/arrowhead_adjustment/dagre/sketch.exp.svg
index 048039058..90796e221 100644
--- a/e2etests/testdata/stable/arrowhead_adjustment/dagre/sketch.exp.svg
+++ b/e2etests/testdata/stable/arrowhead_adjustment/dagre/sketch.exp.svg
@@ -18,18 +18,6 @@ width="494" height="793" viewBox="-108 -107 494 793">