cssanimationsvggraphsmil

Why is my SVG animation loop skipping some parts?


I am working on a little svg component that produces graphs as in the snippet below.

I want to animate it. Right now, I just try to make a breathing-like effect but the line animation doesn't loop correctly. I split it into 2 parts and use an animateTransform trick to pause one while the other is executing. It works on the first iteration but not on the second and the rest.

To the SVG Jedi who might come across this topic, please let me know if I should change some of the animation attributes to make it more smooth/performant. This is the product of many trials & errors and I'm no expert in the field.

The relevant part is here


    <line :x1="ox" :y1="oy" :stroke="isHeading ? 'white' : '#FFFFF0'">
      <animateTransform
        id="pause"
        begin="expandAnim.end"
        dur="3s"
        type="translate"
        attributeType="XML"
        attributeName="transform"
        repeatCount="indefinite"
      />
      <animateTransform
        id="pause2"
        begin="pause.end"
        dur="3s"
        type="translate"
        attributeType="XML"
        attributeName="transform"
        repeatCount="indefinite"
      />
      <animate
        id="expandAnim"
        attributeName="x2"
        :from="cx"
        :to="dx"
        dur="3s"
        begin="0; pause.end"
        repeatCount="indefinite"
      />
      <animate
        fill="freeze"
        attributeName="y2"
        :from="cy"
        :to="dy"
        dur="3s"
        begin="0; pause.end"
        repeatCount="indefinite"
      />
      <animate
        id="collapseAnim"
        attributeName="x2"
        fill="freeze"
        :from="dx"
        :to="cx"
        dur="3s"
        begin="3; expandAnim.end"
        repeatCount="indefinite"
      />
      <animate
        attributeName="y2"
        fill="freeze"
        :from="dy"
        :to="cy"
        dur="3s"
        begin="3; expandAnim.end"
        repeatCount="indefinite"
      />
    </line>

Here is a complete snippet version (please edit if you know how to collapse the code)

svg {
  background-color:black
}
.is-hl {
  fill: white;
  stroke: white;
}
.heading-placeholder {
  fill: transparent;
  stroke: white;
}
circle {
  fill: transparent;
  stroke: white;
}
<svg xmlns="http://www.w3.org/2000/svg" width="250" height="250" class="article-fingerprint d-flex">
  <rect id="overlay" width="100%" height="100%" fill="url(#g1)"></rect>
  <g transform="translate(125, 125)">
    <circle fill="url(#bgGradient)" cx="0" cy="0" r="64.66666666666667"></circle>
    <g class="type-element" idx="0">
      <line x1="3.959691317243109e-15" y1="-64.66666666666667" stroke="#FFFFF0">
        <animateTransform id="pause" begin="expandAnim.end" dur="3s" type="translate" attributeType="XML" attributeName="transform" repeatCount="indefinite"></animateTransform>
        <animateTransform id="pause2" begin="pause.end" dur="3s" type="translate" attributeType="XML" attributeName="transform" repeatCount="indefinite"></animateTransform>
        <animate id="expandAnim" attributeName="x2" from="5.5460389524011505e-15" to="6.158362351974827e-15" dur="3s" begin="0; pause.end" repeatCount="indefinite"></animate>
        <animate fill="freeze" attributeName="y2" from="-90.57368959380808" to="-100.57368959380808" dur="3s" begin="0; pause.end" repeatCount="indefinite"></animate>
        <animate id="collapseAnim" attributeName="x2" fill="freeze" from="6.158362351974827e-15" to="5.5460389524011505e-15" dur="3s" begin="3; expandAnim.end" repeatCount="indefinite"></animate>
        <animate attributeName="y2" fill="freeze" from="-100.57368959380808" to="-90.57368959380808" dur="3s" begin="3; expandAnim.end" repeatCount="indefinite"></animate>
      </line>
      <circle cx="3.959691317243109e-15" cy="-64.66666666666667" r="1" class="origin"></circle>
      <!---->
      <!---->
      <path id="circlePath24336" d="M5.5460389524011505e-15,-90.57368959380808 L6.158362351974827e-15,-100.57368959380808 L5.5460389524011505e-15,-90.57368959380808" fill="none"></path>
      <circle r="2.590702292714141">
        <animateMotion dur="6s" repeatCount="indefinite" fill="freeze">
          <mpath xlink:href="#circlePath24336"></mpath>
        </animateMotion>
      </circle>
    </g>
  </g>
</svg>

As a side question, as I didn't dive in the performance aspect of it yet, does it look like a wise way to proceed with this animation? Or would it be better to stick to a CSS scale animation with the center as origin?

Extra question also: is it feasible to trigger this animation on hover? I haven't spent too much time on it but since the small animated lines and circles are in a child component of the overlay used to trigger, I'm not sure of how to propagate a SVG event such as e.g. overlay.mouseover to it. Note that I'm using vue.


Solution

  • Since your animation was complicated. I didn't bother trying to debug it. I just rewrote it in a more simple form.

    svg {
      background-color:black
    }
    .is-hl {
      fill: white;
      stroke: white;
    }
    .heading-placeholder {
      fill: transparent;
      stroke: white;
    }
    circle {
      fill: transparent;
      stroke: white;
    }
    <svg xmlns="http://www.w3.org/2000/svg" width="250" height="250" class="article-fingerprint d-flex">
      <rect id="overlay" width="100%" height="100%" fill="url(#g1)"></rect>
      <g transform="translate(125, 125)">
        <circle fill="url(#bgGradient)" cx="0" cy="0" r="64.66666666666667"></circle>
        <g class="type-element" idx="0">
          <line x1="3.959691317243109e-15" y1="-64.66666666666667" stroke="#FFFFF0">
            <animate attributeName="x2"
                     dur="6s" repeatCount="indefinite"
                     values="0; 0; 0"
                     keyTimes="0; 0.5; 1"/>
            <animate attributeName="y2"
                     dur="6s" repeatCount="indefinite"
                     values="-90.573; -100.573; -90.573"
                     keyTimes="0; 0.5; 1"/>
          </line>
          <circle r="2.590702292714141">
            <animateTransform attributeName="transform"
                     type="translate"
                     dur="6s" repeatCount="indefinite"
                     values="0,-90.573; 0,-100.573; 0,-90.573"
                     keyTimes="0; 0.5; 1"/>
          </circle>
        </g>
      </g>
    </svg>