Search code examples
cssanimationsvgcss-animationssvg-animate

Animate SVG fill shape by following the form


i wonder how to fill a form continously with html5/css3 to create a loading icon (spinner). The fill should follow the red line (3) and leave the shape in same direction when it reaches the end (6)

The fill should follow the red line (3) and leave the shape in same direction when it reaches the end (6) If it would be a thin line i could work with fake line animation, but how i can do this with a thicker shape like this?

<svg version="1.1" id="Loader" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
     viewBox="0 0 255 255" style="enable-background:new 0 0 255 255; width: 255px; height: 255px" xml:space="preserve">
<g>
    <path d="M169.9,73.6c9,6.2,15.3,14.9,20,23.3c4.7,8.3,7.1,17.2,7.1,26.7c0,4.9-0.7,9.6-2.1,14c-1.4,4.5-3.5,8.7-6.3,12.6
        c-7.1,9.8-16.7,17.7-28.7,23.6c-12.1,5.9-24.7,8.9-37.8,8.9c-7.9,0-15.5-1.6-23-4.8c-7.5-3.2-14.2-7.8-20.1-13.7
        c-5.8-6-10.4-12.6-13.5-20.1c-3.2-7.4-4.8-15-4.8-22.8c0-10.4,3.1-20.1,9.2-29.1c6.1-9,15.5-17.5,28-25.5c0,0,5.8-4.2,10.9-4.2
        c5.1,0,11.1,3.1,6.6,10.3c-4.5,7.2-6.8,14.3-6.8,21.1c0,6.7,2.3,12.4,6.8,16.8c4.5,4.5,10.2,6.7,17,6.7c6.2,0,11.4-2.3,15.6-7
        c4.1-4.7,6.2-10.6,6.2-17.7c0-4.9-1-9.5-3-13.7c-2-4.3-1.3-10.6,4.2-11.5C160.7,66.7,169.9,73.6,169.9,73.6z"/>
</g>
</svg>


Solution

  • The main idea is using a very thick line with a changing stroke-dashoffset. I clip the line with your path.

    In order to understand it better you may remove the clip-path attribute.

    I'm using an input type range to change the value of the stroke-dashoffset

    itr.addEventListener("input",()=>{pth.setAttribute("stroke-dashoffset",itr.value)})
    <p><input type="range" min="0" max="235" value="235" id="itr"/></p>
    
    <svg version="1.1" id="Loader" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
         viewBox="0 0 255 255" style="enable-background:new 0 0 255 255; width: 255px; height: 255px" xml:space="preserve">
    
      <clipPath id="clip">
        <path d="M169.9,73.6c9,6.2,15.3,14.9,20,23.3c4.7,8.3,7.1,17.2,7.1,26.7c0,4.9-0.7,9.6-2.1,14c-1.4,4.5-3.5,8.7-6.3,12.6
            c-7.1,9.8-16.7,17.7-28.7,23.6c-12.1,5.9-24.7,8.9-37.8,8.9c-7.9,0-15.5-1.6-23-4.8c-7.5-3.2-14.2-7.8-20.1-13.7
            c-5.8-6-10.4-12.6-13.5-20.1c-3.2-7.4-4.8-15-4.8-22.8c0-10.4,3.1-20.1,9.2-29.1c6.1-9,15.5-17.5,28-25.5c0,0,5.8-4.2,10.9-4.2
            c5.1,0,11.1,3.1,6.6,10.3c-4.5,7.2-6.8,14.3-6.8,21.1c0,6.7,2.3,12.4,6.8,16.8c4.5,4.5,10.2,6.7,17,6.7c6.2,0,11.4-2.3,15.6-7
            c4.1-4.7,6.2-10.6,6.2-17.7c0-4.9-1-9.5-3-13.7c-2-4.3-1.3-10.6,4.2-11.5C160.7,66.7,169.9,73.6,169.9,73.6z"/>
    </clipPath>
      
      <path id="pth" fill="none" stroke-dasharray="235" stroke-dashoffset="235" stroke="rgb(250,0,0)" stroke-width="72" d="M115,60C15,175 235,175 155,65" clip-path="url(#clip)" />
    </svg>

    UPDATE

    The OP is commenting:

    Is it possible to leave the scale-input and animate the filling so the fillup is automatically and when reaching the end that the fill is removing the same direction and when the filling stroke is then empty again, then start from beginning?

    For this I'm animating the stroke-dashoffset of the red line from 235 to -235. This way after animating all the dash (from 235 to 0) the animation follows (from 0 to -235) and the gap is now visible.

    @keyframes anim {
      100% {
        stroke-dashoffset: -235;
      }
    }
    
    #pth {
      animation: anim 5s linear infinite;
    }
    <svg version="1.1" id="Loader" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 255 255" style="enable-background:new 0 0 255 255; width: 255px; height: 255px" xml:space="preserve">
    
      <clipPath id="clip">
        <path id="base" d="M169.9,73.6c9,6.2,15.3,14.9,20,23.3c4.7,8.3,7.1,17.2,7.1,26.7c0,4.9-0.7,9.6-2.1,14c-1.4,4.5-3.5,8.7-6.3,12.6
            c-7.1,9.8-16.7,17.7-28.7,23.6c-12.1,5.9-24.7,8.9-37.8,8.9c-7.9,0-15.5-1.6-23-4.8c-7.5-3.2-14.2-7.8-20.1-13.7
            c-5.8-6-10.4-12.6-13.5-20.1c-3.2-7.4-4.8-15-4.8-22.8c0-10.4,3.1-20.1,9.2-29.1c6.1-9,15.5-17.5,28-25.5c0,0,5.8-4.2,10.9-4.2
            c5.1,0,11.1,3.1,6.6,10.3c-4.5,7.2-6.8,14.3-6.8,21.1c0,6.7,2.3,12.4,6.8,16.8c4.5,4.5,10.2,6.7,17,6.7c6.2,0,11.4-2.3,15.6-7
            c4.1-4.7,6.2-10.6,6.2-17.7c0-4.9-1-9.5-3-13.7c-2-4.3-1.3-10.6,4.2-11.5C160.7,66.7,169.9,73.6,169.9,73.6z" />
      </clipPath>
    
      <use href="#base" />
    
      <path id="pth" fill="none" style="stroke-dasharray:235; stroke-dashoffset:235;" stroke="rgb(250,0,0)" stroke-width="72" d="M115,60C15,175 235,175 155,65" clip-path="url(#clip)" />
    </svg>