Ben
Ben

Reputation: 11502

raphaelJS 2.1 animate along path

I want to animate a path (actually a set of paths, but I'll get to that) along a curved path.

RaphaelJS 2 removed the animateAlong method, for reasons I haven't been able to discern. Digging into the Raphael documentation's gears demo as abstracted by Zevan, I have got this far:

//adding a custom attribute to Raphael
(function() {
  Raphael.fn.addGuides = function() {
    this.ca.guide = function(g) {
      return {
        guide: g
      };
    };
    this.ca.along = function(percent) {
      var g = this.attr("guide");
      var len = g.getTotalLength();
      var point = g.getPointAtLength(percent * len);
      var t = {
        transform: "t" + [point.x, point.y]
      };
      return t;
    };
  };
})();

var paper = Raphael("container", 600, 600);

paper.addGuides();

// the paths
var circ1 = paper.circle(50, 150, 40);
var circ2 = paper.circle(150, 150, 40);
var circ3 = paper.circle(250, 150, 40);
var circ4 = paper.circle(350, 150, 40);

var arc1 = paper.path("M179,204c22.667-7,37,5,38,9").attr({'stroke-width': '2', 'stroke': 'red'});

// the animation

// works but not at the right place
circ3.attr({guide : arc1, along : 1})
         .animate({along : 0}, 2000, "linear");

http://jsfiddle.net/hKGLG/4/

I want the third circle to animate along the red path. It is animating now, but at a distance from the red path equal to the third circle's original coordinates. The weird thing is that this happens whether the transform translate in the along object is relative (lowercase "t") or absolute (uppercase "T"). It also always animates in the same spot, even if I nudge it with a transform translation just before the animate call.

Any help very appreciated. I just got off the boat here in vector-land. Pointers are helpful--a working fiddle is even better.

Upvotes: 1

Views: 2101

Answers (1)

Kevin Nielsen
Kevin Nielsen

Reputation: 4433

You're just a hop, skip, and jump away from the functionality that you want. The confusion here concerns the interaction between transformations and object properties -- specifically, that transformations do not modify the original object properties. Translating simply adds to, rather than replaces, the original coordinates of your circles.

The solution is extremely straightforward. In your along method:

this.ca.along = function(percent) {
  var box = this.getBBox( false );  // determine the fundamental location of the object before transformation occurs
  var g = this.attr("guide");
  var len = g.getTotalLength();
  var point = g.getPointAtLength(percent * len);
  var t = {
    transform: "...T" + [point.x - ( box.x + ( box.width / 2 ) ), point.y - ( box.y + ( box.height / 2 ) )]  // subtract the center coordinates of the object from the translation offset at this point in the guide.
  };
  return t;

Obviously, there's some room for optimization here (i.e., it might make sense to create all your circles at 0,0 and then translate them to the display coordinates you want, avoiding a lot of iterative math). But it's functional... see here.

One other caveat: the ...T translation won't effect any other transforms that have already been applied to a given circle. This implementation is not guaranteed to play nicely with other transforms.

Upvotes: 5

Related Questions