1
  • I want a smooth transition between the shapes (the example below shows a sudden transition just so you get an idea where I need a smooth transition).
  • The order of the shapes is determined by Javascript (for the example I fixed an arbitrary sequence, but in the actual problem user input determines which shape is choosen, so it isn't known beforehand).

example.svg:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>

<svg xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    width="100%" height="100%" viewBox="0 0 400 400">
<script>
window.animate = function( fromId, toId, next )
{
    return function()
    {
        var elem = document.getElementById( 'elem' );
        /* Here a smooth animation is supposed to happen. */
        elem.setAttribute( 'xlink:href', '#' + toId );

        if( next )
        {
            window.setTimeout( next, 1000 );
        }
    };
};

window.onload = function()
{
    /* The animation order is determined by javascript. */
    var step3 = window.animate( 'path-2', 'path-1', null );
    var step2 = window.animate( 'path-1', 'path-2', step3 );
    var step1 = window.animate( 'path-0', 'path-1', step2 );
    var step0 = window.animate( 'path-0', 'path-0', step1 );

    step0();
};
</script>

<style>path{stroke:#000;}</style>

<defs>
<path id="path-0" style="fill:#fcc" d="M0,0 h100 v100 h-100 v-100" />
<path id="path-1" style="fill:#ccf" d="M0,0 h50 l50 50 l-100 50 v-100" />
<path id="path-2" style="fill:#cfc" d="M0,0 h150 l-50 50 l-100 50 v-100" />
</defs>

<use id="elem" xlink:href="#path-0" x="150" y="150" />
</svg>

Supposedly it's somehow doable with <animate>, but I can't get it to work.

animate.svg:

<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>

<svg xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    width="100%" height="100%" viewBox="0 0 400 400">
<script>
window.set_animation = function( animId, fromId, toId )
{
    var anim = document.getElementById( animId );
    var from = document.getElementById( fromId );
    var to = document.getElementById( toId );
    anim.setAttribute( 'from', from.getAttribute( 'd' ) );
    anim.setAttribute( 'to', to.getAttribute( 'd' ) );
};

window.onload = function()
{
    /* The animation order is determined by javascript. */
    window.set_animation( 'anim-0', 'path-0', 'path-1' );
    window.set_animation( 'anim-1', 'path-1', 'path-2' );
    window.set_animation( 'anim-2', 'path-2', 'path-1' );

    /* Can start animation only once animation steps are defined. */
    var anim = document.getElementById( 'anim-0' );
    anim.beginElement();
};
</script>

<style>path{stroke:#000;}</style>

<defs>
    <path id="path-0" style="fill:#fcc" d="M0,0 l100,0 l0,100 l-100,0 l0,-100" />
    <path id="path-1" style="fill:#ccf" d="M0,0 l50,0 l50,50 l-100,50 l0,-100" />
    <path id="path-2" style="fill:#cfc" d="M0,0 l150,0 l-50,50 l-100,50 l0,-100" />
</defs>

<path id="elem" x="150" y="150" d="">
    <animate id="anim-0" begin="indefinite" attributeType="XML" attributeName="d" dur="2s" from="[set by javascript]" to="[set by javascript]" />
    <animate id="anim-1" begin="anim-1.end" attributeType="XML" attributeName="d" dur="2s" from="[set by javascript]" to="[set by javascript]" />
    <animate id="anim-2" begin="anim-2.end" attributeType="XML" attributeName="d" dur="2s" from="[set by javascript]" to="[set by javascript]" />
</path>
</svg>
Limon Monte
  • 52,539
  • 45
  • 182
  • 213
user66554
  • 558
  • 2
  • 14

2 Answers2

1

With <animate> the rule is that the two paths have to:

  1. have the same number of path elements
  2. have matching path commands

Your animations won't work because the paths are incompatible:

path-0: M h v h v
path-1: M h l l v
Paul LeBeau
  • 97,474
  • 9
  • 154
  • 181
  • Okay. I knew that some commands are incompatible, but not that all are (`h`, `v` and `l` are all lines, after all). Fixed that. Still, it still doesn't quite work (and I've heard something about `` going to be dropped?). – user66554 May 14 '16 at 16:09
  • Yes SMIL animations are probably going to be removed by at least some browsers, in lieu of the new Web Animations API. However there will be polyfills available vi third parties to provide backward compatibility. – Paul LeBeau May 15 '16 at 07:16
1

It's easier to put all the values into a single animation as I've done here. If you don't then you have to start each subsequent animation as the previous one finishes which is doable but more complicated.

You'll need fakeSmile or the Chrome SMIL shim for IE/Chrome but this does play without plugins on Firefox.

<svg xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    width="100%" height="100%" viewBox="0 0 400 400">
<script>

function create_animation(animId, paths, attribute)
{
    var anim = document.getElementById( animId );
    var values = paths.map(function(item) { return document.getElementById(item).getAttribute(attribute) }).join(';'); 
        
    anim.setAttribute( 'values', values );
}

window.set_animation = function( animId, paths )
{
    create_animation(animId, paths, 'd');
    create_animation(animId + '-colour', paths, 'fill');
};

window.onload = function()
{
    /* The animation order is determined by javascript. */
    window.set_animation( 'anim-0', ['path-0', 'path-1', 'path-2'] );
};
</script>

<style>path{stroke:#000;}</style>

<defs>
    <path id="path-0" fill="#fcc" d="M0,0 l100,0 l0,100 l-100,0 l0,-100" />
    <path id="path-1" fill="#ccf" d="M0,0 l50,0 l50,50 l-100,50 l0,-100" />
    <path id="path-2" fill="#cfc" d="M0,0 l150,0 l-50,50 l-100,50 l0,-100" />
</defs>
  
<path>
  <animate id='anim-0' dur="3s" attributeName='d' fill="freeze"/>
  <animate id='anim-0-colour' dur="3s" attributeName='fill' fill="freeze"/>
</path>
Robert Longson
  • 118,664
  • 26
  • 252
  • 242
  • I had it in separate animations since the duration of the individual animation segments is variable, which I know is supposed to be achievable by ``, but I cannot figure out how I should achieve it if it is all in one animation. Can you amend your answer or should I ask a new question for that? – user66554 May 17 '16 at 06:33
  • You could use keyTimes to achieve that. If you want more, ask a new question. – Robert Longson May 17 '16 at 06:38