Home > Mobile >  svg animation of drawing line with marker
svg animation of drawing line with marker

Time:01-19

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>

  • Related