【问题标题】:Fabric.js animate object/imageFabric.js 动画对象/图像
【发布时间】:2016-08-11 11:01:19
【问题描述】:

大家好,这是我一直在使用的代码。它将一个对象从 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>

【问题讨论】:

    标签: javascript animation fabricjs


    【解决方案1】:

    您面临的问题是动画函数不会相互阻塞,因此当您的 fireAnimation() 函数运行时,它会同时启动两个动画,并且每个动画更改都应用于每一帧,这表示两个动画同时发生。

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

    鉴于您提议可能有一个动画列表以逐个应用,您可以通过创建一个通用函数来更好地服务,该函数基于这样的动画参数的输入列表应用动画(代码中的 cmets 中的解释):

    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);
      }
    }
    

    【讨论】:

    • +1 表示列表。 @Yondaru,我建议您研究状态机,它们是处理动画序列的最佳方法。
    • @nickvans,非常感谢,很有魅力。如果您有此画布的图像上传器并且您想为每个上传的图像分配一个命令列表,您能告诉我您会怎么做吗?
    • 首先为每个 animationQueue 对象添加一个附加属性,该属性将在您创建图像后存储图像的结构对象。 {"fabricShape": newlyAddedShape, "left": "+=0",... 更改闭包函数以使用 animationDefinition.newlyAddedShape 而不是 triangle 在您的上传者的完成事件(上传成功时触发的事件)中,只需为该对象创建一个新的动画队列列表并将其传递给 startAnimationQueue 函数.
    • 另外不要忘记将我的回复标记为回答您的问题(投票箭头下方的绿色勾号),以帮助其他人找到类似问题的答案(如果他们有)。
    • 是的,这应该不是问题。我从未使用过精灵动画,但看起来它们与其他织物对象一样具有顶部/左侧属性,因此您应该能够以相同的方式为其位置设置动画。对于文本气泡,您希望将气泡与精灵组合(使用 fabric.Group)或简单地将相同的动画应用于精灵和气泡。对于气泡,我建议使用这样的 SVG 路径:upload.wikimedia.org/wikipedia/commons/7/7f/Speech_bubble.svg(查看页面源代码以查看 SVG 代码)
    猜你喜欢
    • 1970-01-01
    • 2015-04-02
    • 2017-06-11
    • 2016-04-24
    • 2015-10-10
    • 2014-05-17
    • 2013-02-08
    • 2021-01-04
    • 2015-09-15
    相关资源
    最近更新 更多