Fabric.js:在许多对象上使用animate方法是如此之慢

时间:2017-01-24 02:50:55

标签: fabricjs

我使用animate方法为100个对象制作动画,但在我的情况下,性能太慢,我该如何解决?

我的演示代码: https://jsfiddle.net/cs6jqj2w/

2 个答案:

答案 0 :(得分:2)

请查看fabricJS demo

另外,我使用你的函数修改了一些演示,用于生成随机数并在此fiddle

中创建了100个shpaes
(function() {
  var canvas = this.__canvas = new fabric.Canvas('c');
  fabric.Object.prototype.transparentCorners = false;

  var Cross = fabric.util.createClass(fabric.Object, {
    objectCaching: false,
    initialize: function(options) {
      this.callSuper('initialize', options);
      this.animDirection = 'up';

      this.width = 100;
      this.height = 100;

      this.w1 = this.h2 = 100;
      this.h1 = this.w2 = 30;
    },

    animateWidthHeight: function() {
      var interval = 2;

      if (this.h2 >= 30 && this.h2 <= 100) {
        var actualInterval = (this.animDirection === 'up' ? interval : -interval);
        this.h2 += actualInterval;
        this.w1 += actualInterval;
      }

      if (this.h2 >= 100) {
        this.animDirection = 'down';
        this.h2 -= interval;
        this.w1 -= interval;
      }
      if (this.h2 <= 30) {
        this.animDirection = 'up';
        this.h2 += interval;
        this.w1 += interval;
      }
    },

    _render: function(ctx) {
      ctx.fillRect(-this.w1 / 2, -this.h1 / 2, this.w1, this.h1);
      ctx.fillRect(-this.w2 / 2, -this.h2 / 2, this.w2, this.h2);
    }
  });


  for (var i = 0; i < 100; i++){
   canvas.add(
   new Cross({ top: getRandomInt(0,500), left: getRandomInt(0,500)})
   );
  }


  setTimeout(function animate() {
    canvas.forEachObject(function(obj){ obj.animateWidthHeight(); obj.dirty = true; });
    canvas.renderAll();
    setTimeout(animate, 10);
  }, 10);
})();

function getRandomInt(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

<强>更新 你的动画不起作用,因为你必须渲染画布。

您必须生成99个项目而不进行渲染,最后一个项目需要渲染。此外,最后一项对我来说具有动画的最大持续时间,以便完成所有形状的动画。

var fabric = window.fabric

var canvas = new fabric.StaticCanvas('c')


function createItem(canvas) {
  var item = new fabric.Circle({
    left: -100,
    top: getRandomInt(0, 500),
    opacity: Math.random().toFixed(2),
    radius: getRandomInt(10, 50),
  })
  item.keepGoing = true
  canvas.add(item)
 // itemTopAnim(canvas, item, getNextTop(item.top))
//  itemLeftAnim(canvas, item)
return item;
}

function getRandomInt(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

function getNextTop(top) {
  if (top < (canvas.height / 2)) {
    return top + getRandomInt(50, 200)
  }
  return top - getRandomInt(50, 200)
}

function itemTopAnim(canvas, item, top) {
  item.animate('top', top, {
    duration: getRandomInt(1, 3) * 1000,
   // onChange: canvas.renderAll.bind(canvas),
    easing: fabric.util.ease.easeInOutCubic,
    onComplete: function() {
      item.keepGoing && itemTopAnim(canvas, item, getNextTop(item.top))
    }
  })
}

function itemTopAnimLast(canvas, item, top) {
  item.animate('top', top, {
    duration: 3 * 1000,
    onChange: canvas.renderAll.bind(canvas),
    easing: fabric.util.ease.easeInOutCubic,
    onComplete: function() {
      item.keepGoing && itemTopAnim(canvas, item, getNextTop(item.top))
    }
  })
}

function itemLeftAnim(canvas, item) {
  item.animate('left', canvas.width - item.radius, {
    duration: getRandomInt(5, 10) * 1000,
    //onChange: canvas.renderAll.bind(canvas),
    onComplete: function() {
      item.keepGoing = false
    }
  })
}

function itemLeftAnimLast(canvas, item) {
  item.animate('left', canvas.width - item.radius, {
    duration: 10 * 1000,
    onChange: canvas.renderAll.bind(canvas),
    onComplete: function() {
      item.keepGoing = true
    }
  })
}

for (var i = 0; i < 100; i++) {
var item = createItem(canvas);
if (i == 99){
itemLeftAnimLast(canvas, item)
itemTopAnimLast(canvas, item, getNextTop(item.top))
} else {
itemLeftAnim(canvas, item)
itemTopAnim(canvas, item, getNextTop(item.top))
}

}

检查此更新的fiddle

希望它能让您更好地了解它现在是如何运作的。

答案 1 :(得分:0)

听起来你现在已经开始工作了。我想我会补充说http://fabricjs.com/fabric-intro-part-2上的文档还提到在动画大量对象时可能需要使用requestAnimationFrame而不是onChange回调:

  

动画在每次更改后不会自动重新渲染画布的原因是由于性能原因。毕竟,我们可以在画布上拥有数百或数千个动画对象,如果每个人都试图重新渲染屏幕就不会有好处。对于许多对象,您可以使用requestAnimationFrame(或其他基于计时器的)循环来自行连续渲染画布,而无需为每个对象调用renderAll。但大多数情况下,您可能需要将canvas.renderAll明确指定为“onChange”回调。

我遇到了类似的问题,这个建议很有效。