I'm trying to make an animation of a growing arrow. The path is drawn correctly, but the marker arrow is immediately at the end. Can you please tell me how can I attach a marker to the end of the path so that it moves with it?
<?xml version="1.0" encoding="UTF-8"?>
<svg width="291px" height="260px" viewBox="0 0 391 260" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Path</title>
<defs>
<marker id="Triangle" viewBox="0 0 10 10" refX="1" refY="5"
markerUnits="strokeWidth" markerWidth="4" markerHeight="3"
orient="auto">
<path d="M 0 0 L 10 5 L 0 10 z" fill="context-stroke"/>
</marker>
</defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<path marker-end="url(#Triangle)" d="M273.097656,120.507813 C201.899566,163.577543 130.777516,213.94793 50.8398438,240.160156 C36.9248074,244.723012 17.4914196,262.184399 8.2265625,250.84375 C-1.53762975,238.89189 20.198756,222.272258 24.0078125,207.316406 C27.3670238,194.126823 28.5689142,180.441602 29.6132812,166.871094 C30.9603726,149.366986 31.1766739,131.782428 31.171875,114.226563 C31.1623478,79.3735161 8.15793288,37.1795952 29.5703125,9.6796875 C43.1473611,-7.75730878 67.7544299,32.013528 87.5742187,41.7890625 C105.639606,50.6992894 124.365537,58.2317755 143.085938,65.6679688 C150.003672,68.4158594 157.202901,70.4330349 164.40625,72.3085938 C177.173796,75.6329203 190.335014,77.4306133 202.960938,81.2578125 C220.824973,86.6728004 237.747783,94.999359 255.734375,99.9921875 C266.927708,103.099302 278.679688,103.638021 290.152344,105.460938" id="Path" stroke="#979797" stroke-width="10"></path>
</g>
</svg>
html,
body {
display: grid;
place-items: center;
min-height: 100vh;
}
svg {
stroke-dasharray: 1000;
stroke-dashoffset: 1000;
pointer-events: none;
animation: animateDash 2s linear forwards infinite;
}
@keyframes animateDash {
to {
stroke-dashoffset: 0;
}
}
code https://codepen.io/rostislav_blatman/pen/JjBOWMB
UPD: Or perhaps there is another way how to achieve a similar result. Ideally, I want to bind the length of the arrow to the page scroll percentage
CodePudding user response:
<marker>
elements refer to the actual geometry of an element
Since you don't actually change/manipulate the <path>
while animating – all markers will stick to their initial position.
In other words: you can't animate/move markers unless you're changing the element's geometry.
Animate an element via <mpath>
- create a reusable
<path>
element for the motion path within a<defs>
element - add a marker/arrow element here as well
- add a svg SMIL animation via
<animateMotion>
:
<animateMotion dur="6s" repeatCount="indefinite" rotate="auto">
<mpath href="#motionPath" />
</animateMotion>
Alernative: Css offset-path
Spoiler: current browser support (2023) is unfortunately still a bit spotty.
body {
margin: 1em;
}
svg {
width: 20em;
border: 1px solid #ccc;
overflow: visible;
}
.strokeBG {
marker-start: url(#markerStart);
marker-mid: url(#markerRound);
stroke-width: 0.33%;
}
.strokeAni {
stroke-dasharray: 0 100;
animation: animateDash 6s linear forwards infinite;
}
@keyframes animateDash {
to {
stroke-dasharray: 100 100;
}
}
.strokeMarker2 {
offset-path: path( "M273.1 120.5c-71.2 43.1-142.3 93.4-222.3 119.7c-13.9 4.5-33.3 22-42.6 10.6c-9.7-11.9 12-28.5 15.8-43.5c3.4-13.2 4.6-26.9 5.6-40.4c1.4-17.5 1.6-35.1 1.6-52.7c0-34.8-23-77-1.6-104.5c13.5-17.5 38.2 22.3 58 32.1c18 8.9 36.8 16.4 55.5 23.9c6.9 2.7 14.1 4.7 21.3 6.6c12.8 3.3 25.9 5.1 38.6 9c17.8 5.4 34.7 13.7 52.7 18.7c11.2 3.1 23 3.6 34.5 5.5");
animation: followpath 6s linear infinite;
}
@keyframes followpath {
to {
motion-offset: 100%;
offset-distance: 100%;
}
}
<h3>Svg SMIL</h3>
<svg viewBox="0 0 391 260" xmlns="http://www.w3.org/2000/svg">
<defs>
<path id="motionPath" pathLength="100" d="M273.1 120.5c-71.2 43.1-142.3 93.4-222.3 119.7c-13.9 4.5-33.3 22-42.6 10.6c-9.7-11.9 12-28.5 15.8-43.5c3.4-13.2 4.6-26.9 5.6-40.4c1.4-17.5 1.6-35.1 1.6-52.7c0-34.8-23-77-1.6-104.5c13.5-17.5 38.2 22.3 58 32.1c18 8.9 36.8 16.4 55.5 23.9c6.9 2.7 14.1 4.7 21.3 6.6c12.8 3.3 25.9 5.1 38.6 9c17.8 5.4 34.7 13.7 52.7 18.7c11.2 3.1 23 3.6 34.5 5.5" />
<path id="marker" d="M -5 -5 l 10 5 l -10 5 z" />
</defs>
<g id="Page-1" stroke-width="1" fill="none">
<use href="#motionPath" stroke="#eee" stroke-width="10" />
<use href="#motionPath" stroke="#979797" stroke-width="10" />
<use href="#marker" stroke="#979797" stroke-width="10">
<animateMotion dur="6s" repeatCount="indefinite" rotate="auto">
<mpath href="#motionPath" />
</animateMotion>
</use>
<use href="#marker" fill="red" />
</g>
</svg>
<h3>Css offset path</h3>
<svg viewBox="0 0 391 260" xmlns="http://www.w3.org/2000/svg">
<defs>
<path id="motionPath2" pathLength="100" d="M273.1 120.5c-71.2 43.1-142.3 93.4-222.3 119.7c-13.9 4.5-33.3 22-42.6 10.6c-9.7-11.9 12-28.5 15.8-43.5c3.4-13.2 4.6-26.9 5.6-40.4c1.4-17.5 1.6-35.1 1.6-52.7c0-34.8-23-77-1.6-104.5c13.5-17.5 38.2 22.3 58 32.1c18 8.9 36.8 16.4 55.5 23.9c6.9 2.7 14.1 4.7 21.3 6.6c12.8 3.3 25.9 5.1 38.6 9c17.8 5.4 34.7 13.7 52.7 18.7c11.2 3.1 23 3.6 34.5 5.5" />
<path id="marker2" d="M -5 -5 l 10 5 l -10 5 z" />
</defs>
<g stroke-width="1" fill="none">
<use href="#motionPath2" stroke="#979797" stroke-width="10" />
<use href="#marker2" stroke="#979797" stroke-width="10">
</g>
</svg>
<!-- markers to show commands -->
<svg id="svgMarkers" style="width:0; height:0; position:absolute; z-index:-1;">
<defs>
<marker id="markerStart" overflow="visible" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="strokeWidth" markerWidth="10" markerHeight="10" orient="auto-start-reverse">
<circle cx="5" cy="5" r="5" fill="green"></circle>
<marker id="markerRound" overflow="visible" viewBox="0 0 10 10" refX="5" refY="5" markerUnits="strokeWidth" markerWidth="10" markerHeight="10" orient="auto-start-reverse">
<circle cx="5" cy="5" r="2.5" fill="red"></circle>
</marker>
</defs>
</svg>