Fabric.js动画对象/图像

时间:2016-04-19 10:17:50

标签: javascript animation fabricjs

大家好,这是我一直在使用的代码。它将一个对象从A移动到B.我想要做的是有多个点可以移动。所以从起始位置A - > B,然后从B - >; C等等。也许有一些包含坐标集的变量,这些坐标会被作为参数输入到一些动画函数中。但是我尝试过的任何事情都只会导致执行最后一个命令,所以它会直接从A - > C,忽略B.任何建议/演示赞赏。

的Javascript

var canvas = new fabric.Canvas('scene', { backgroundColor: 'green'});

var triangle = new fabric.Triangle({
    width: 30
  , height: 30
  , fill: 'red'
  , left: 30
  , top: 0
});

canvas.add(triangle);

function animateTop() {
  triangle.animate('top', '+=55', {
    duration: 1000,
    onChange: canvas.renderAll.bind(canvas)
  });
}

function animateLeft() {
  triangle.animate('left', '+=100', {
    duration: 1000,
    onChange: canvas.renderAll.bind(canvas)
  });
}

function fireAnimation() {
  animateTop();
  animateLeft();
}

document.onreadystatechange = function () {
  if (document.readyState == "complete") {
    fireAnimation();
  }
}

HTML

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>JS Bin</title>
  <script src="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.4.0/fabric.min.js"></script>
</head>
<body>
  <canvas id="scene" width="400" height="400" />
</body>
</html>

1 个答案:

答案 0 :(得分:1)

您遇到的问题是动画功能不会相互阻挡,因此当您的fireAnimation()功能运行时,它会同时启动两个动画,并且每个动画更改都应用于每个帧,这意味着两个动画同时发生。

解决此问题的一种方法是使用动画.onComplete事件链接动画调用。如果您需要更新动画的顺序,这样做可能会让您陷入一种地狱般的境地。

鉴于你提议可能有一个接一个地应用的动画列表,你可以通过创建一个基于动画参数的输入列表来应用动画的通用函数来更好地服务(代码中的注释中的解释): / p>

function startAnimationQueue(animationQueue){
    // queues up the animations for the shape

    var runningDuration = 0; // variable that adds up the animationQueue durations
    for (var i=0; i<animationQueue.length; i++){
        var animationDefinition = animationQueue[i];

        // Create a closure around the animationDefiniton so that each setTimeout gets sequential animationDefinition inputs
        var fn = (function(animationDefinition){
            return function(){
                triangle.animate('left', animationDefinition.left, {duration: animationDefinition.duration, onChange:canvas.renderAll.bind(canvas)})
                triangle.animate('top', animationDefinition.top, {duration: animationDefinition.duration, onChange:canvas.renderAll.bind(canvas)})
                // Note: you can animate additional attributes here if you want, just add additional attributes to the objects in
                //   the animationQueue list. You could also have one of those inputs be the object to be animated in case you want
                //   to animate multiple objects using the same queue.
                };
            })

        // Create the timeout that will apply the transformations sequentially
        // If you want you could set the window.setTimeout to a variable that you could destroy if you need 
        // to interrupt the animation queue after you create it (but before it finishes)
        window.setTimeout(fn(animationDefinition), runningDuration);

        // set the next setTimeout duration to be .duration later than the previous one
        // this makes the second animation fire after the first one completes
        runningDuration += animationDefinition.duration;
    }
}

document.onreadystatechange = function () {
  if (document.readyState == "complete") {

    // I put the canvas init stuff in here because of (I think) a failed race condition or something that caused
    // your original method to fail in Chrome
    window.canvas = new fabric.Canvas('scene');

    window.triangle = new fabric.Triangle({
        width: 30
      , height: 30
      , fill: 'red'
      , left: 30
      , top: 0
    });

    window.canvas.add(window.triangle);
    window.canvas.renderAll();

    // Create a list of animations to apply
    var animationQueue = [
        {"left": "+=0", "top": "+=100", "duration": 1000},
        {"left": "+=55", "top": "+=0", "duration": 2000}

    ]

    // Apply the animations in sequence using window.setTimeout
    startAnimationQueue(animationQueue);
  }
}