3 votes

Comment améliorer les performances de canvas fabric.js avec un grand nombre d'objets ?

J'ai besoin de faire une application qui a environ 30k objets, un utilisateur peut Pan, Zoom ou "Select on click" n'importe lequel de ces objets. Fabric.js Canvas est utilisé

J'ai fait la même chose en utilisant des SVG et le plugin svg-pan-zoom (sans élément Canvas) avec de meilleurs résultats.

Problème : il y a un décalage important lors du zoom, du panoramique ou de l'objet sur le clic.

  1. La suppression de Fabric.js améliorera-t-elle les performances ?
  2. Le passage à WebGL améliorera-t-il les performances ?

J'ai essayé les options spécifiques au tissu

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

UPDATE Voici la mise à jour Violon

pour référence :

  1. toile-vs-svg-vs-div Stackoverflow

  2. Stackoverflow

4voto

user3877726 Points 11

Ne rendez pas dans IO EVENTS !

Bien qu'il ne s'agisse pas d'une solution complète au problème de la vitesse de mise à jour, cette réponse permettra de doubler la vitesse d'interaction.

Une erreur courante, presque standard, commise avec l'interaction de la souris et des événements avec le canevas (et le DOM) est de déléguer le rendu aux événements de la souris/du toucher. Il s'agit d'une très mauvaise pratique, car les événements de la souris se déclenchent à une vitesse bien supérieure à celle que l'écran peut afficher. C'est encore pire lorsque le temps de rendu est élevé, car vous mettez en file d'attente les événements de la souris (pseudo-événements de rendu) et effectuez un nouveau rendu à chaque mouvement de la souris.

Note Le code de blocage arrêtera les événements de la souris mais dès que le moteur sera au ralenti, la souris recommencera à tirer à plein régime.

Utilisez les événements de la souris juste pour obtenir l'état de la souris. Utilisez une boucle d'animation synchronisée avec l'affichage pour effectuer le rendu uniquement lorsque cela est nécessaire et qu'il y a du temps disponible. Les éléments tels que la roue et les deltas de mouvement de la souris doivent être enregistrés de manière cumulative.

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

Et les consommer dans la boucle de rendu principale...

function update(){

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

...cela permet de s'assurer que l'état de la souris est suivi avec précision lorsque vous pouvez avoir de nombreux événements de souris entre les mises à jour du rendu.

Exemple, séparer les événements du rendu.

Changez votre code dans le fiddle que vous avez fourni par le suivant, sur ma machine cela a doublé la vitesse de rendu (qui est toujours très lente).

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X