Search code examples
javascriptanimationsvgsnap.svg

snap svg animation does not works


I'm trying to animate lines with stroke-dashoffset and stroke-dasharray attributes. It's complicate figure with circles and line-connectors. I use Snapsvg, here is my figure, it was simplified for example:

<svg version="1.1" id="fImg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 345 320">
  <g id="balls">
    <circle cx="125" cy="9.3" r="6.7"/>
    <circle cx="230.2" cy="63.5" r="6.7"/>
    <circle cx="211.6" cy="18.3" r="6.7"/>
    <circle cx="292.6" cy="63.5" r="6.7"/>
  </g>
 <g id="lines">
    <line class="st0" x1="103.8" y1="11.6" x2="125" y2="9.3"/>
    <line class="st0" x1="103.8" y1="11.6" x2="115.8" y2="44.9"/>
    <line class="st0" x1="103.8" y1="11.6" x2="85.9" y2="32.4"/>
    <line class="st0" x1="85.9" y1="32.4" x2="115.8" y2="44.9"/>
</g>
</svg>

I use Snap function to set attributes for circles and animate it. lineDrow - callback function for lines, but it works only before .animate({.....}, 1000):

var balls = Snap("#balls");
balls.attr({
    fill:'rgba(0,0,0,0)'
}).animate({
    fill: '#ccc'
}, 2000, mina.easeout, lineDraw);


function lineDraw() {
    var lines = document.querySelectorAll("#lines line");
    for (var i = 0; i < lines.length; i++) {
        var line = Snap(lines[i]),
            x = Math.ceil(line.getTotalLength());

        line.attr({
            'strokeDasharray': x,
            'strokeDashoffset': x,
            'stroke-width': 1,
            'stroke-linecap':'round',
            'stroke': '#ccc'
        }).animate({
            'strokeDasharray': 0,
            'strokeDashoffset': 0
        }, 1000);
    }
}

And it makes me crease! What's wrong?


Solution

  • There's a couple of issues with your code.

    Firstly, you can't use getTotalLength on a line I don't think, so you'll have to create a small function or something to calculate the length of a line (or use paths, as getTotalLength works there).

    Snap doesn't have strokeDasharray and strokeDashoffset as animatable attributes (unless it does in the latest version), however, we can animate between any 2 values with the Snap.animate method

    Snap.animate( from, to, function, duration, callback). Note from and to can also be arrays of values to interpolate between, eg [0,0,0] to [3,100,5].

    So just using the Snap.animate method, we can interpolate from the line length to 0. Note, I've had to use an immediate mode function closure in this case, just as you are using it with lots of different lines, and we want to make sure each animation has the line in scope when called (otherwise it will only animate the last line). If you only have 1 thing to animate, you can get rid of the extra function/closure code.

    So it would look something like this (just swap in a value for the line lengths instead of 100), this was a similar question I think you maybe asked in the Snap slack channel which I answered there. The code should be similar enough still to match your amended code.

    (function() {
      var lineClosure = line;
      Snap.animate(100, 0, function( val ){
          lineClosure.attr({
                    'strokeDasharray': val,
                    'strokeDashoffset': val,
                });
    
    
           }, 1000);
     })();
    

    jsfiddle