How to improve performance of canvas fabric.js with lots of objects

I need to create an application containing about 30k objects, the user can pan, zoom, or "select on click" of any of these objects. Used Canvas Fabric.js

I did the same with SVG and svg-pan-zoom plugin (no canvas) with better results

Problem: There is significant lag while zooming, panning, or an object when pressed

  • will remove Fabric.js for better performance?
  • will switch to WebGL to improve performance?

Tried custom parameters for Fabric

fabric.Object.prototype.objectCaching = false;
fabric.Object.prototype.statefullCache = false;
fabric.Object.prototype.noScaleCache = true;
fabric.Object.prototype.needsItsOwnCache = false;

      

UPDATE Heres updated Fiddle

for reference:

+3


source to share


1 answer


Do not show in IO EVENTS!

While this is not a complete fix for refresh rate, this answer will roughly double the interaction rate.

A common, almost standard mistake made with mouse and canvas (and DOM) events is delegating rendering to mouse / touch events. This is very bad practice as the mouse firing is much faster than the display can display. Degrades when your render time is long when you queue mouse events (pseudo-environment events) and render for every mouse movement.

Note blocking code stops mouse events, but as soon as the engine is running, the mouse will start firing again at full speed.

Use mouse events to get the state of the mouse. Use an animation loop that syncs with the display to only display when needed and when available. Things like the delta of wheel and mouse movements should be logged cumulatively.

mouse.dx += event.movementX; 
mouse.dy += event.movementY; 
mouse.wheel += event.wheelDelta;

      



And consume them in the main render loop ...

function update(){

    // ... code to use mouse
    // consume deltas
    mouse.x = mouse.y = mouse.wheel = 0;

      

... this will ensure the mouse state is respected exactly if you might have many mouse events between render updates.

An example separating events from rendering.

Change your code in the script you provided, on my machine, about twice the render speed (which is still very slow).

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

      

+2


source







All Articles