Search code examples
svg-animate

Get SVG attribute after <animate> has started


Is there a way to read the value (final or intermediate) of a SVG attribute, like x1 in the following example, after a svg-animation is started/applied?

The result of .getAttribute is always the initial value, not the current one used to render the element.

After many cumulative animations, it gets hard to keep track of every one to calculate it, so some property, or some way to apply it to the element, must exist. CSS animations do get .commitStyles and I found no SVG counterpart.

        setInterval(function() {
            console.log(theLine.getAttribute("x1")); //always 10, but should change to become 100 at the end
        }, 1000);
<svg id="mainSvg" width="400" height="300">
    <line id="theLine" x1="10" y1="100" x2="100" y2="50" style="stroke: #000">
        <animate
            attributeName="x1"
            begin="1s"
            dur="2s"
            values="20;100"
            calcMode="spline"
            keySplines="0.6 0 0.4 1"
            repeatCount="1"
            fill="freeze"
            additive="sum">
        </animate>
    </line>
</svg>


Solution

  • You can use SVGAnimatedString.animVal to retrieve the currently animated value.

    let x1 = theLine.x1.animVal.value;
    

    lineAni.beginElement();
    let interval = setInterval(getAttAnim, 100);
    let loops = 50;
    let i=0;
    function getAttAnim(){
      if(i<=loops){
          let x1 = theLine.x1.animVal.value;
          i++
          //console.log(x1)
          currentVal.textContent = x1;
        
      }else{
          clearInterval(interval);
      }
    }
    <svg id="mainSvg" width="400" height="300">
        <line id="theLine" x1="10" y1="100" x2="100" y2="50" style="stroke: #000">
            <animate
                id="lineAni"
                attributeName="x1"
                begin="indefinite"
                dur="5s"
                values="10;100"
                calcMode="linear"
                repeatCount="0"
                fill="freeze"
                >
            </animate>
        </line>
    </svg>
    <p id="currentVal">10</p>