Javascript 使用RaphaelJS与两个动画同步计时

Javascript 使用RaphaelJS与两个动画同步计时,javascript,path,drawing,raphael,graphael,Javascript,Path,Drawing,Raphael,Graphael,使用RaphaelJS,我改编了两个脚本来创建我想要组合的两个动画: 首先,绘制坐标虚线 var canvas = Raphael('canvas_container', 322, 273); var set = canvas.set(canvas.circle(110, 265, 7), canvas.circle(110, 7, 7), canvas.circle(7, 151, 7)).attr({ stroke: "none", fill: "#666" }); var

使用RaphaelJS,我改编了两个脚本来创建我想要组合的两个动画:

  • 首先,绘制坐标虚线

    var canvas = Raphael('canvas_container', 322, 273);
    var set = canvas.set(canvas.circle(110, 265, 7), canvas.circle(110, 7, 7), canvas.circle(7, 151, 7)).attr({
        stroke: "none",
        fill: "#666" });
    
    var pathstr = "M 109 255 l 0 -245 l -103 141 l 265 0";
    var path = dashline(canvas, pathstr, 4000, {
        stroke: '#828282',
        'stroke-dasharray': "--",
        'stroke-linecap': "butt",
        'stroke-width': 1,
        'fill-opacity': 0 }, 1000);
    
    function dashline(canvas, pathstr, duration, attr) {
    
        var guide_path = canvas.path(pathstr).attr({
            stroke: "none",
            fill: "none"
        });
        var path = canvas.path(guide_path.getSubpath(0, 1)).attr(attr);
        var total_length = guide_path.getTotalLength(guide_path);
        var start_time = new Date().getTime();
        var interval_length = 20;
    
        var interval_id = setInterval(function() {
            var elapsed_time = new Date().getTime() - start_time;
            var this_length = elapsed_time / duration * total_length;
            var subpathstr = guide_path.getSubpath(0, this_length);
            attr.path = subpathstr;
            path.animate(attr, interval_length);
        }, interval_length);
        return path;
    }​;​
    
    和,当到达坐标时,在路径上放松并设置圆动画

  • 我想让圆圈动画作为虚线路径到达他们的坐标。如果我能得到虚线路径来使用easing,那将是一个加号,但大多数情况下,我只是希望将两者结合为一

    我能够更好地阅读javascript,而不是编写自己的脚本,但是如果有人对如何分解虚线脚本和代码所采取的步骤有任何见解,那将对我大有裨益


    我关于堆栈溢出的第一篇文章(yeesh,关于时间)希望我足够具体

    我本人从未使用过拉斐尔,但以下是我发现的解决方案:

    第一个动画在4(4000毫秒)秒内运行,您可以在以下块中看到:

    var path = dashline(canvas, pathstr, 4000, {
        stroke: '#828282',
        'stroke-dasharray': "--",
        'stroke-linecap': "butt",
        'stroke-width': 1,
        'fill-opacity': 0
    }, 1000);
    
    下一步是识别渲染圆的块,这里给它3秒钟的运行时间,这可以通过将最后一个参数更改为4000来解决。接下来,您将注意到百分比。这些应该包括转换计算,以将毫秒(4000)转换为每个动画点的百分比

    我仔细观察了动画点,但结尾代码如下所示:

    function animateCirc() {
        var easex = ">",
            easey = ">";
        c.stop().animate({
            "0%":  {cy: 265, easing: easey, callback: fade(0)},
            "35%": {cy: 7, easing: easey, callback: fade(1)},
            "60%": {cy: 151, easing: easey, callback: fade(2)},
            "100%": {cy: 151, easing: easey, callback: fade(3)}
        }, 4000).animate({
            "0%":  {cx: 110, easing: easex},
            "35%": {cx: 110, easing: easex},
            "60%": {cx: 7, easing: easex},
            "100%": {cx: 300, easing: easex}
        }, 4000);
        return run;                
    };
    
    您可以看到更新的(但不是100%同步的)版本

    ​请注意,您实际上可以使用Raphael、画架、Kinetic或任何类型的Canvas/SVG渲染工具

    希望这有帮助

    @是一个简洁、非常简单的修改(他比我快,当他提交他的答案时,我还在写我的答案)。但这似乎并不涉及真正的排队。必须手动计算计时以完全同步动画。但是,我下面的答案将大大改变代码。可能需要,也可能不需要

    要做的第一件事是将虚线路径分割成线(在您的例子中,分割成3个单独的线段)并在队列中设置它们的动画。可能可以对单个(组合)路径进行排队,但我还没有尝试过

    为了简化这个过程,我提取了所有的路径坐标,因为它们也被圆使用。这样我们就可以把所有元素画成一个循环

    var canvas = Raphael('canvas_container', 322, 273),
        // here are the coordinates
        points = [ [110,265], [110,7], [7,151], [300,151] ],
        mCircle = canvas.circle(points[0][0],points[0][1],10).attr({stroke: "#999", "stroke-width": 4}),
        path = [],
        circles = [];
    
    // draw the dots and (starting point of) lines
    // note the lines are of 0 length so it's invisible, we only mark its starting point
    for (var i = 0; i < points.length - 1; i++) {
        circles[i] = canvas.circle(points[i][0],points[i][1],7).attr({stroke: "none", fill: "#666"});
        path[i] = canvas.path('M'+points[i][0]+' '+points[i][1]).attr({
            stroke: '#828282',
            'stroke-dasharray': "--",
            'stroke-linecap': "butt",
            'stroke-width': 1,
            'fill-opacity': 0
        });
    

    最难的部分来了。管理动画队列。实际上,您可以使用其他库,如jQuery。然而,经过数小时的绝望之后,我决定编写自己的(非常简单的)队列系统

    // my custom Queue class
    var Queue = function() {
        this.actionCount = 0;
        this.actions = [];
    
        var self = this;
        self._cb = function() {
            if (++self.actionCount != self.actions.length) self.run();
        };
    };
    Queue.prototype.run = function() {
        this.actions[this.actionCount](this._cb);
    };
    Queue.prototype.add = function(fn) {
        this.actions.push(fn);
    };
    
    在循环中,我们可以将生成的每组动画注册到队列中。并在循环完成后运行队列

    for (var i = 0; i < points.length - 1; i++) {
        circles[i] = canvas.circle(points[i][0],points[i][1],7).attr({stroke: "none", fill: "#666"});
        path[i] = canvas.path(/*...*/);
    
        queue.add(fn(i));
    }
    queue.run();
    
    for(变量i=0;i
    这是你的电话号码

    注意事项

    • 虚线路径动画已缓和:p
    • 添加更多要设置动画的点非常简单,只需将它们添加到
      数组中,其余部分将自动完成-
    • 您应该能够通过
      fn
      功能调整动画
    • queue类非常简单,没有任何检查,并且未经生产测试。我创建它的唯一目的就是回答这个问题。标准预防措施适用
    • 这是我第一次和拉斐尔在一起,欢迎大家指正
    • 循环不会传递JSLint,因为我调用了一个创建另一个函数的工厂函数。在循环中这样做似乎是件坏事
    • 由于我在回答之前创建了JSFIDLE,因此这里的代码注释比JSFIDLE更好

    我从未使用过拉斐尔,但有没有一种带有回调的动画方法?jQuery的animate函数有一个回调函数,这意味着您可以为每个刻度应用动画,使所有内容保持完全同步。请看我在这里的回答,以获取一个示例:对于您的情况,可能有类似的方法?
    // function to generate each set of animation
    var fn = function(index) {
        var cPath = path[index], cCircle = circles[index],
            x1 = points[index][0], 
            x2 = points[index+1][0], 
            y1 = points[index][1], 
            y2 = points[index+1][1];
    
        return function(cb) {
            cPath.animate({path:'M'+x1+' '+y1+' L'+x2+' '+y2},500,'easeOut');
            mCircle.animate({cx:x2,cy:y2},500,'easeOut');
            cCircle.attr({fill: "#fff", r: 12}).animate({fill: "#77bf00", r: 8}, 500, cb);
        };
    };
    
    // my custom Queue class
    var Queue = function() {
        this.actionCount = 0;
        this.actions = [];
    
        var self = this;
        self._cb = function() {
            if (++self.actionCount != self.actions.length) self.run();
        };
    };
    Queue.prototype.run = function() {
        this.actions[this.actionCount](this._cb);
    };
    Queue.prototype.add = function(fn) {
        this.actions.push(fn);
    };
    
    for (var i = 0; i < points.length - 1; i++) {
        circles[i] = canvas.circle(points[i][0],points[i][1],7).attr({stroke: "none", fill: "#666"});
        path[i] = canvas.path(/*...*/);
    
        queue.add(fn(i));
    }
    queue.run();