问题
New to raphael.js, I'm looking for an explanation on how to do something like move planets around a sun in an orbit. I'm stuck trying to create a path and animate the movement of the circle around it.
Thanks for any pointers in the right direction!
回答1:
My friend @Kevin Nielsen is right, you'll want "getPointAtLength." There's a nice little Raphael function here that adds an .animateAlong() function, though it needs a little modification to work on circular objects. I stripped it to the necessities for you.
Assuming you recognize post-1609 astronomy, you'll want elliptical orbits. (Though the difference in the short and long radii are quite small in reality, which is why Copernicus was a bit off the mark.) But you can't use the .ellipse() function, since you need the ellipse as a path in order to animate along it. See the SVG specifications for the elliptical arc, or just try a bunch of combinations until it looks right, like I did:
var paper = Raphael("canvas", 500, 500);
var center = {x: 200, y: 100 };
var a = 100;
var b = 80;
//see http://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands
var ellipse = "M" + (center.x - a) + "," + center.y + " a " + a + "," + b + " 0 1,1 0,0.1";
var orbit = paper.path(ellipse);
Now you want to draw the earth at one of the foci of the ellipse, and the moon along the path. We'll start it at the perigee.
var focus = Math.pow(a*a - b*b, 0.5);
var palebluedot = paper.circle(center.x - focus, center.y, 25)
.attr({
stroke: 0,
fill: "blue"
});
var moon = paper.circle(center.x - a, center.y, 10)
.attr({
stroke: 0,
fill: "#CCC"
});
And here's your modified "animateAlong" function:
//Adapted from https://github.com/brianblakely/raphael-animate-along/blob/master/raphael-animate-along.js
Raphael.el.animateAlong = function(path, duration, easing, callback) {
var element = this;
element.path = path;
element.pathLen = element.path.getTotalLength();
duration = (typeof duration === "undefined") ? 5000 : duration;
easing = (typeof easing === "undefined") ? "linear" : duration;
//create an "along" function to take a variable from zero to 1 and return coordinates. Note we're using cx and cy specifically for a circle
paper.customAttributes.along = function(v) {
var point = this.path.getPointAtLength(v * this.pathLen),
attrs = {
cx: point.x,
cy: point.y
};
this.rotateWith && (attrs.transform = 'r'+point.alpha);
return attrs;
};
element.attr({along: 0 }).animate({along: 1}, duration, easing, function() {
callback && callback.call(element);
});
};
and here it is:
moon.animateAlong(orbit, 2000);
jsFiddle
回答2:
@Chris Wilson's answer is right on the money.
One slight modification I needed was to have the animation repeat indefinitely. @boom doesn't ask for it specifically, but as I can imagine this could be a common requirement for orbit animations, here's my modification to Chris's version of .animateAlong()
:
Raphael.el.animateAlong = function(path, duration, repetitions) {
var element = this;
element.path = path;
element.pathLen = element.path.getTotalLength();
duration = (typeof duration === "undefined") ? 5000 : duration;
repetitions = (typeof repetitions === "undefined") ? 1 : repetitions;
paper.customAttributes.along = function(v) {
var point = this.path.getPointAtLength(v * this.pathLen),
attrs = { cx: point.x, cy: point.y };
this.rotateWith && (attrs.transform = 'r'+point.alpha);
return attrs;
};
element.attr({along:0});
var anim = Raphael.animation({along: 1}, duration);
element.animate(anim.repeat(repetitions));
};
Note that I've dropped the easing and callback parameters (as I didn't need them) and added the repetitions
parameter, which specifies the number of repetitions to perform.
An example call (starting an endlessly looping orbit animation) is:
moon.animateAlong(orbit, 2000, Infinity);
来源:https://stackoverflow.com/questions/15341165/orbit-animation-with-raphael-js