Search code examples
svgsvg-filterssvg-animate

How to make SVG gradient animation fluid instead of shocking?


I've got an SVG where I want to animate the gradient, so that the colors look dynamic. In order to do this, I need a repeatable animation that looks like it's doing something most of the time.

However, when trying to animate the animation I've got at the moment, it resets it self instead of animating back. Thus creating an ugly animation. How do I fix this?

Here's my fiddle: https://codepen.io/basdvries/pen/JpXoOd

And the code:

<svg xmlns="http://www.w3.org/2000/svg" width="777" height="795" viewBox="0 0 777 795">
  <defs>
    <radialGradient id="cloudradial-a" cx="0%" cy="0%" r="109.117%" fx="0%" fy="0%" gradientTransform="matrix(-.63364 -.76096 .74317 -.6488 0 0)">
      <stop offset="0%" stop-color="#F06CA6"/>
      <stop offset="61.832%" stop-color="#DC8BFF"/>
      <stop offset="100%" stop-color="#FF8D72"/>
            <animate id="anim1" attributeName="r" begin="0;anim2.end" dur="2000ms" from="0%" to="100%" repeatCount="indefinite" />
    </radialGradient>
    <radialGradient id="cloudradial-c" cx="0%" cy="0%" r="109.117%" fx="0%" fy="0%" gradientTransform="matrix(-.63364 -.76096 .74317 -.6488 0 0)">
      <stop offset="0%" stop-color="#F06CA6"/>
      <stop offset="61.832%" stop-color="#DC8BFF"/>
      <stop offset="100%" stop-color="#FF8D72"/>
            <animate id="anim2" attributeName="r" dur="200ms" begin="anim1.end" from="0%" to="100%" repeatCount="indefinite" />
    </radialGradient>
        <filter id="cloudradial" width="144.2%" height="145.3%" x="-22.1%" y="-22.6%" filterUnits="objectBoundingBox">
      <feGaussianBlur in="SourceGraphic" stdDeviation="43.94"/>
    </filter>
  </defs>
  <path fill="url(#cloudradial-a)" fill-opacity=".45" stroke="#979797" stroke-width="1.35" d="M805.657915,689.505516 C852.226063,735.051611 978.113939,702.66067 1070.4988,689.505516 C1156.9714,677.192238 1164.21484,670.424935 1208.56625,689.505516 C1417.97128,779.594417 1356.62755,441.622549 1356.62755,366.157732 C1356.62755,219.157682 1224.61976,128 1077.83353,128 C974.605539,128 893.432513,139.313122 844.998833,232.603176 C824.561683,271.967992 763.933077,319.848065 788.872748,388.981412 C812.522966,454.540365 808.724453,478.962707 788.872748,522.206752 C753.584402,599.077269 759.089767,643.959421 805.657915,689.505516 Z" filter="url(#cloudradial-b)" transform="translate(-663 -23)"/>
</svg>

Solution

  • If you want the animation to go back and forth, there's good information here:
    https://css-tricks.com/guide-svg-animations-smil/

    Unfortunately, SMIL does not include a way to go back and forth between the start and end values like CSS animations allow us to do.
    (...)
    [As a workaround], you can set the animation to start from a value, and end at the same value as well with to, except that you specify what you would have set to be a final value, as an intermediate value between from and to.
    (...)
    The equivalent in SMIL is to use the values attribute, (...)

    So, use the same from and to value, add the values attribute and describe the animation steps there:

    <animate attributeName="r" dur="2000ms" repeatCount="indefinite"
             from="0%" to="0%" values="0%; 100%; 40%; 150%; 0%;" />
    

    Updated pen: https://codepen.io/Sphinxxxx/pen/LQNpGJ?editors=1000

    Edit: Actually, from and to are no longer needed in this case:
    https://www.w3.org/TR/smil-animation/#ValuesAttribute

    If a list of values is specified, any from, to and by attribute values are ignored.