svgsmil

animate back and forth with svg/smil (NOT CSS)


How would you set up a svg animateTransform to rotate an arrow back and forth infinitely, slowing down as it reaches its extremities? (like a pendulum).

Looking at the spec there is an attribute called autoReverse - https://www.w3.org/TR/SMIL3/smil-timemanip.html#TimeManip-autoReverseSyntax - but it doesn't work and perhaps has not been implemented anywhere.

I want the rotating element to repeat going back and forth forever, rotating around the centrepoint of the circles, like in the example below.

<?xml version="1.0" encoding="UTF-8"?>
<svg id="a" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 701.09 165.13">
    <circle cx="347.37" cy="177.35" r="35.19" fill="#e4e7ea" stroke-width="0" />
    <circle cx="347.37" cy="177.35" r="31.52" transform="translate(94.42 474.22) rotate(-76.61)"
        fill="#edf1f4" stroke-width="0" />
    <path d="m348.28,113.8c-.2-1.09-1.63-1.09-1.84,0l-4.56,35.94,5.48,17.44,5.48-17.44-4.56-35.94Z"
        fill="#373838" stroke-width="0">
        <animateTransform attributeType="xml" attributeName="transform" type="rotate" to="-45 347.37 177.35" from="45 347.37 177.35" dur="1s" repeatCount="indefinite"
        accelerate=".5" decelerate=".5" autoReverse="true" />

    </path>
    <circle cx="347.37" cy="177.35" r="17.72" transform="translate(94.66 474.42) rotate(-76.66)"
        fill="#fff" stroke-width="0" />
    <path
        d="m347.37,195.96c-10.27,0-18.62-8.35-18.62-18.62s8.35-18.62,18.62-18.62,18.62,8.35,18.62,18.62-8.35,18.62-18.62,18.62Zm0-35.45c-9.28,0-16.83,7.55-16.83,16.83s7.55,16.83,16.83,16.83,16.83-7.55,16.83-16.83-7.55-16.83-16.83-16.83Z"
        fill="#373838" stroke-width="0" />
</svg>

I build the basic shape in Illustrator and then opened the SVG in a text editor and started copying and pasting the numbers into the animateTransform from and to until it worked. I don't really understand the numbers other than figuring they are x and y coordinates. I certainly have no clue about how curves work, even after watching bezier explainer videos. So don't math at me.

I've seen various mentions of "keytimes" and "splines" (the documentation of which is effectively meaningless gibberish to me).

Any thoughts / simple explanations appreciated.


Solution

  • There is not much benefit in reading the SMIL specification. If you want to find out what is implemented in browsers, read SVG animations. Despite the "draft" status, for now it is more or less the same as the Animation chapter in SVG 1.1 and has only minor differences to existing implementations.

    accelerate, decelerate and autoReverse are all not part of SVG animations. To reverse an animation, you have to define a forth-and-back movement. Instead of defining from and to, define a values list, each value separated with a semicolon. Add to that a keyTimes list with exactly the same number of entries, the first one 0, the last one 1, and all others inbetween as relative times, just like the percentage values in CSS keyframes animations.

    Define the interpolation mode with calcMode="spline" and define the splines to use for each movement from frame to frame as a list with keySplines. The number of entries, again separated with a semicolon, must be exactly one less than the number of values and of keyTimes.

    <?xml version="1.0" encoding="UTF-8"?>
    <svg id="a" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 701.09 165.13">
        <circle cx="347.37" cy="177.35" r="35.19" fill="#e4e7ea" stroke-width="0" />
        <circle cx="347.37" cy="177.35" r="31.52" transform="translate(94.42 474.22) rotate(-76.61)"
            fill="#edf1f4" stroke-width="0" />
        <path d="m348.28,113.8c-.2-1.09-1.63-1.09-1.84,0l-4.56,35.94,5.48,17.44,5.48-17.44-4.56-35.94Z"
            fill="#373838" stroke-width="0">
            <animateTransform attributeType="xml" attributeName="transform" type="rotate"
            values="45 347.37 177.35;
                   -45 347.37 177.35;
                    45 347.37 177.35"
            keyTimes="0;0.5;1" calcMode="spline"
            keySplines=".7 0 .3 1;.7 0 .3 1"
            dur="2s" repeatCount="indefinite" />
    
        </path>
        <circle cx="347.37" cy="177.35" r="17.72" transform="translate(94.66 474.42) rotate(-76.66)"
            fill="#fff" stroke-width="0" />
        <path
            d="m347.37,195.96c-10.27,0-18.62-8.35-18.62-18.62s8.35-18.62,18.62-18.62,18.62,8.35,18.62,18.62-8.35,18.62-18.62,18.62Zm0-35.45c-9.28,0-16.83,7.55-16.83,16.83s7.55,16.83,16.83,16.83,16.83-7.55,16.83-16.83-7.55-16.83-16.83-16.83Z"
            fill="#373838" stroke-width="0" />
    </svg>