如何使用大量对象提高canvas fabric.js性能

Rit*_*tin 3 svg html5-canvas fabricjs

我需要制作一个具有约30k对象的应用程序,用户可以平移,缩放或“单击时选择”任何这些对象。正在使用Fabric.js画布

我已经使用SVG和svg-pan-zoom插件(没有Canvas元素)进行了相同的操作,效果更好

问题:缩放,平移或单击对象时出现严重滞后

  1. 删除Fabric.js会提高性能吗?
  2. 切换到WebGL会改善性能吗?

尝试了特定于面料的选项

fabric.Object.prototype.objectCaching = false;
fabric.Object.prototype.statefullCache = false;
fabric.Object.prototype.noScaleCache = true;
fabric.Object.prototype.needsItsOwnCache = false;
Run Code Online (Sandbox Code Playgroud)

更新 这里更新的小提琴

以供参考 :

  1. canvas-vs-svg-vs-div Stackoverflow

  2. 堆栈溢出

Bli*_*n67 5

不要在IO事件中渲染!

尽管不能完全解决更新速度问题,但此答案将使交互速度提高一倍。

鼠标和事件与画布(和DOM)交互时,常见的,几乎是标准的错误是将渲染委托给鼠标/触摸事件。这是非常不好的做法,因为鼠标事件的触发速率远高于显示器显示的速率。当您将鼠标事件(伪渲染事件)排队并为鼠标的每次移动进行重新渲染时,渲染时间过长时,情况会变得更糟

请注意,阻塞代码将停止鼠标事件,但是一旦引擎处于空闲状态,鼠标将再次以全速启动。

使用鼠标事件只是为了获取鼠标状态。使用同步到显示的动画循环仅在需要时且有可用时间时才进行渲染。滚轮和鼠标移动增量之类的内容应累积记录。

mouse.dx += event.movementX; 
mouse.dy += event.movementY; 
mouse.wheel += event.wheelDelta;
Run Code Online (Sandbox Code Playgroud)

并在主渲染循环中使用它们...

function update(){

    // ... code to use mouse
    // consume deltas
    mouse.x = mouse.y = mouse.wheel = 0;
Run Code Online (Sandbox Code Playgroud)

...这可以确保在渲染更新之间可能有许多鼠标事件时,可以准确地跟踪鼠标状态。

例如,将事件与渲染分开。

在提供给您的小提琴中更改代码,在我的机器上将渲染速度提高一倍(这仍然很慢)。

// from just after the function applyZoom replace all the code 
var mouse = {  // holds the mouse state
    x : 0,
    y : 0,
    down : false,
    w : 0,
    delta : new fabric.Point(0,0),
}
// event just track mouse state
function zoom(e) {
    if(e != null) { e.preventDefault() }
    var evt=window.event || e;
    mouse.x = e.offsetX;
    mouse.y = e.offsetY;
    mouse.w += evt.detail? evt.detail*(-120) : evt.wheelDelta;
    return false;
}
canvas.on('mouse:up', function (e) { mouse.down = false });
canvas.on('mouse:out', function (e) { mouse.down = false });
canvas.on('mouse:down', function (e) { mouse.down = true });
canvas.on('mouse:move', function(e) {
    if (e && e.e) {
        mouse.delta.x += e.e.movementX;
        mouse.delta.y += e.e.movementY;
    }
});
// main animation loop
function update(){
    if(mouse.w !== 0){  // if the wheel has moved do zoom
        var curZoom = canvas.getZoom();
         canvas.zoomToPoint(
             { x : mouse.x, y: mouse.y }, 
             canvas.getZoom() + mouse.w / 4000
         );
         mouse.w = 0; // consume wheel delta
    }else if(mouse.down) {  // if mouse button down
         canvas.relativePan(mouse.delta);
    }
    // consume mouse delta
    mouse.delta.x = 0;
    mouse.delta.y = 0;
    requestAnimationFrame(update);
}
requestAnimationFrame(update);
Run Code Online (Sandbox Code Playgroud)