How to draw a vector path progressively? (Raphael.js)

Maybe someone is searching for an answer, like me for two days now:

// Draw a path and hide it:
var root = paper.path('M0 50L30 50Q100 100 50 50').hide();
var length = root.getTotalLength();

// Setup your animation (in my case jQuery):
element.animate({ 'to': 1 }, {
    duration: 500,
    step: function(pos, fx) {
        var offset = length * fx.pos;
        var subpath = root.getSubpath(0, offset);
        paper.clear();
        paper.path(subpath);
    }
});

That did the trick for me, only by using RaphaelJS methods.

Here is a jsFiddle example as requested in the comments, http://jsfiddle.net/eA8bj/


Eureka! (Maybe - assuming you're comfortable stepping outside the friendly realm of Raphael into pure SVG land...)

You can use SVG keyTimes and keySplines.

Here's a working example:

http://www.carto.net/svg/samples/animated_bustrack.shtml

...and here's some potentially useful explanation:

http://msdn.microsoft.com/en-us/library/ms533119(v=vs.85).aspx


I'd like to offer an alternative, Raphael+JS-only solution that I have made substantial use of in my own work. It has several advantages over davidenke's solution:

  1. Doesn't clear the paper with each cycle, allowing the animated path to coexist nicely with other elements;
  2. Reuses a single path with Raphael's own progressive animation, making for smoother animations;
  3. Substantially less resource intensive.

Here's the method (which could quite easily be retooled into an extension):

function drawpath( canvas, pathstr, duration, attr, callback )
{
    var guide_path = canvas.path( pathstr ).attr( { stroke: "none", fill: "none" } );
    var path = canvas.path( guide_path.getSubpath( 0, 1 ) ).attr( attr );
    var total_length = guide_path.getTotalLength( guide_path );
    var last_point = guide_path.getPointAtLength( 0 );
    var start_time = new Date().getTime();
    var interval_length = 50;
    var result = path;        

    var interval_id = setInterval( function()
    {
        var elapsed_time = new Date().getTime() - start_time;
        var this_length = elapsed_time / duration * total_length;
        var subpathstr = guide_path.getSubpath( 0, this_length );            
        attr.path = subpathstr;

        path.animate( attr, interval_length );
        if ( elapsed_time >= duration )
        {
            clearInterval( interval_id );
            if ( callback != undefined ) callback();
                guide_path.remove();
        }                                       
    }, interval_length );  
    return result;
}

And here are two samples of its usage on my site: one for Path Transformation, and the other for Progressive Lettering.


I've created a script for this: Scribble.js, based on this great dasharray/dashoffset technique.

Just instantiate it overs a bunch of SVG <path>s:

var scribble = new Scribble(paths, {duration: 3000});
scribble.erase();
scribble.draw(function () {
    // done
});

--

NB: Full USAGE code here: https://gist.github.com/abernier/e082a201b0865de1a41f#file-index-html-L31

Enjoy ;)