简体   繁体   中英

How to animate a Raphael object along a path?

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.

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

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);
    });
};

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)

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM