使用一些自定义属性,单个路径的简单动画非常简单:
(function() {
Raphael.fn.addGuides = function() {
this.ca.guide = function(g) {
return {
guide: g
};
};
this.ca.along = function(percent) {
var box = this.getBBox( false );
var g = this.attr("guide");
var len = g.getTotalLength();
var point = g.getPointAtLength(percent * len);
var t = {
transform: "...t" + [point.x - box.x, point.y - box.y]
};
return t;
};
};
})();
var paper = Raphael("container", 600, 600);
paper.addGuides();
var circ1 = paper.circle(50, 50, 40);
var circ2 = paper.circle(150, 50, 40);
var circ3 = paper.circle(250, 50, 40);
var circ4 = paper.circle(350, 50, 40);
var redarc = "M200,100 c 22-7,37,5,38,9";
var redarcpath = paper.path(redarc).attr({'stroke-width': '2', 'stroke': 'red'});
circ3.attr({guide : redarcpath, along : 1})
.animate({along : 0}, 2000, "linear");
见:http: //jsfiddle.net/p6Q3x/1/
但是当你animate
在一个集合上调用这个相同的方法时,集合内元素的相对定位会被折叠。例如,这个“目标”的同心圆都在集合边界框的左上角堆叠在一起:
paper.setStart();
var inner = paper.circle(50, 250, 15);
var middle = paper.circle(50, 250, 30);
var outer = paper.circle(50, 250, 45);
var target = paper.setFinish();
var redarc = "M200,100 c 22-7,37,5,38,9";
var redarcpath = paper.path(redarc).attr({'stroke-width': '2', 'stroke': 'red'});
// basic animation of target on red arc collapses the shapes
target.attr({guide : redarcpath, along : 1})
.animate({along : 0}, 2000, "linear");
见:http: //jsfiddle.net/p6Q3x/3/
这很奇怪,因为该along
方法中的小写相对“t”表明将保留相对定位。但不是。所以我开始克隆集合中每个元素的运动路径,并根据集合边界框中“子”路径的相对位置,对每个克隆路径应用不同的变换。但即使这样还不够,因为当路径用于动画时,变换矩阵会被忽略。因此,每个转换后的运动路径都必须“展平”回原始路径数据。我在这里使用了Timo 的函数来进行展平部分:
function animateSet(set, pathToFollow) {
var setBBox = set.getBBox(false);
set.forEach(function (el) {
var pathBBox = el.getBBox( false );
// get the difference between the element's BBox
// and its "parent" set's BBox coordinates
var offset = "...t" + [pathBBox.x - setBBox.x, pathBBox.y - setBBox.y];
// use offset to create a new, unique, displaced motion path
var transformedPath = pathToFollow.clone()
.hide()
.transform(offset);
// flatten that transformation back into raw path data
var flatPathString = flatten_transformations(transformedPath, normalize_path, to_relative, dec);
// and make a new Raphael path array out of that flattened data
var shiftedPath = paper.path(flatPathString).hide();
el.attr({guide : shiftedPath, along : 1})
.animate({along : 0}, 2000, "linear", function() {
transformedPath.remove(); // wipe out temporary motion paths
shiftedPath.remove(); // when animation completes
});
});
}
好消息是它有效!http://jsfiddle.net/p6Q3x/
但这感觉真的很丑陋、臃肿、呆滞。我不敢相信这需要如此复杂。任何人都可以向新手推荐一种更简单、更清洁、更有效的方法吗?我的感觉是,需要为集合重写沿方法,以便集合的成员每个都有自己的边界框,但我不知道如何准确地做到这一点。非常感谢所有帮助。