How to animate a Raphael object along a path?

14,330

Solution 1

Just in case you are trying to use this with RaphaelJS 2 (animateAlong doesn't exist anymore), here you can see a possible solution: http://jsfiddle.net/gyeSf/17/.

And here the original discussion: https://groups.google.com/forum/#!searchin/raphaeljs/animatealong/raphaeljs/W9bA0SkArVY/KnPRKi8uFrsJ

Edit: And here another example: http://raphaeljs.com/gear.html

Solution 2

Just use the .animateAlong() method.

It takes 4 arguments:

  1. path - object or string path element or path string along which the element will be animated
  2. ms - number - The duration of the animation, given in milliseconds.
  3. rotate - boolean - [optional] if true, element will be rotated along the path
  4. callback - function - [optional]

Essentially from the documentation:

window.onload = function() {
    var r = Raphael("canvas", 200, 200), 
        p = r.path("M10,50C10,100,90,0,90,50C90,100,10,0,10,50Z")
             .attr({stroke: "#ddd"}),
        e = r.ellipse(10, 50, 4, 4).attr({stroke: "none", fill: "#f00"});
    r.rect(0, 0, 200, 200).attr({stroke: "none", fill: "#000", opacity: 0})
     .click(function () {
         e.attr({rx: 5, ry: 3})
          .animateAlong(p, 4000, true, function () {        // Animate along path
              e.attr({rx: 4, ry: 4});
          });
     });
}​;

Try it out with this jsFiddle (click to activate)

Solution 3

There's a nice solution here.

I've copied the code below:

/*

You can copy and paste the below into your codebase somewhere.
As long as Raphael is a global object, it'll just work.

USAGE (same default values for optional parameters as Raphaël's "animate" method)
=====
element.animateAlong({
    path: REQUIRED - Path data string or path element,
    rotate: OPTIONAL - Boolean whether to rotate element with the direction it is moving
                       (this is a beta feature - currently kills existing transformations
                        and rotation may not be perfect),
    duration: OPTIONAL - Number in milliseconds,
    easing: OPTIONAL - String (see Raphaël's docs),
    debug: OPTIONAL - Boolean, when set to true, paints the animating path, which is
                      helpful if it isn't already rendered to the screen
},
props - Object literal containing other properties to animate,
callback - Function where the "this" object refers to the element itself
);

EXAMPLE
=======
var rect = paper.rect(0,0,50,50);
rect.animateAlong({
    path: "M0,0L100,100",
    rotate: true,
    duration: 5000,
    easing: 'ease-out',
    debug: true
},
{
    transform: 's0.25',
    opacity: 0
},
function() {
    alert("Our opacity is now:" + this.attr('opacity'));
});

*/

Raphael.el.animateAlong = function(params, props, callback) {
    var element = this,
        paper = element.paper,
        path = params.path,
        rotate = params.rotate,
        duration = params.duration,
        easing = params.easing,
        debug = params.debug,
        isElem = typeof path !== 'string';

    element.path = 
        isElem
            ? path
            : paper.path(path);
    element.pathLen = element.path.getTotalLength();
    element.rotateWith = rotate;

    element.path.attr({
        stroke: debug ? 'red' : isElem ? path.attr('stroke') : 'rgba(0,0,0,0)',
        'stroke-width': debug ? 2 : isElem ? path.attr('stroke-width') : 0
    });

    paper.customAttributes.along = function(v) {
        var point = this.path.getPointAtLength(v * this.pathLen),
            attrs = {
                x: point.x,
                y: point.y 
            };
        this.rotateWith && (attrs.transform = 'r'+point.alpha);
        // TODO: rotate along a path while also not messing
        //       up existing transformations

        return attrs;
    };

    if(props instanceof Function) {
        callback = props;
        props = null;
    }
    if(!props) {
        props = {
            along: 1
        };
    } else {
        props.along = 1;    
    }

    var startAlong = element.attr('along') || 0;

    element.attr({along: startAlong}).animate(props, duration, easing, function() {
        !isElem && element.path.remove();

        callback && callback.call(element);
    });
};

Solution 4

It seems that you cant do that using Raphaёl animate() method (since it changes object attributes linearly).

I would offer you to implement a function that changes object position each millisecond or so according to Bézier curve formula. Use Raphaёl translate() method and JavaScript timers.

Share:
14,330

Related videos on Youtube

Mike
Author by

Mike

Have a BS in computer science from SIUE Worked @ Motorola for 6 years as an embedded systems software engineer Currently reside in OH working for Emerson as a software engineer

Updated on April 19, 2022

Comments

  • Mike
    Mike about 2 years

    The object could be simple, a rect or circle. But the path should be a bezier curve. Please provide javascript/Raphael code if not too much trouble.

    It will be nice if there is trailing effect of the moving object during annimation.

    • Adriano Varoli Piazza
      Adriano Varoli Piazza about 15 years
      This question smells of 'do my homework for me'
    • Prasad
      Prasad about 15 years
      Google it before posting the question
    • mheavers
      mheavers over 12 years
      It's good to post the things that you've tried before posting on stack so people know you're not just asking them to do your work for you.
  • Ajax3.14
    Ajax3.14 about 11 years
    you are passing a red dot right, is it possible to pass a image through that path?