Warm tip: This article is reproduced from stackoverflow.com, please click
canvas fabricjs

Canvas Animation CPU issue

发布于 2020-04-11 22:19:15

We are using fabricjs Animation Easing with Sprite and it's kinda lagging. We also check other canvas project without fabricjs and they are also eating much of cpu. Is there a good way to solve this under canvas?

Questioner
Gonchar Denys
Viewed
64
markE 2016-05-16 04:35

Disclaimer: I'm not a FabricJS Guru!

So take my analysis lightly... :-)

Why your animation might be lagging when many objects are involved

As @Blindman67 implies in his comment, FabricJS's "smart" objects are too heavy to be animated in very large quantities.

  • Smart == event-aware, code-controllable (Nice!).
  • Heavy == resource intensive (not so Nice!).

If your animations are almost-but-not-quite responsive...

You might try grouping your re-renderings to do fewer redraws during your animation cycle.

  • Don't set the onChange callback for anything that is animating.
  • When animation starts, create a separate requestAnimationFrame (aka rAF) callback and only re-render (with canvas.renderAll) in this separate rAF loop.
  • Throttle the rAF callback loop to fire at a speed that reduces lagging but which is still visually appealing.

Notes:

By default, the rAF loop that FabricJS uses will try to loop at 60fps. Assigning onChange callbacks on every animating object will almost certainly cause that animation loop to redraw at 60 frames-per-second.

Grouping causes all redrawings to be done in a single animation loop so that the re-renderings can be done at less than the overwhelming 60fps -- perhaps 30fps. This slower fps likely will not impair the animation effect but will give the CPU+GPU twice the time to do their renderings!

To help, the rAF loop comes with a timestamp argument that you can use to throttle the loop to execute code at less than 60fps.

Here's starting code for you to build upon

// animation related vars
var fps=30;
var delay=1000/fps;
var nextTime=0;
var isAnimating=true;
requestAnimationFrame(animate);

// Usage:
// * call startAnimating()
// * Set many objects to .animate
// * Optionally, when all animating objects report "onComplete"
//       call stopAnimating()

function startAnimating(){
    // set the isAnimating flag to start the animation loop
    isAnimating=true;
}

function stopAnimating(){
    isAnimating=false;
}

function animate(time){
    // if we're not animating anything or if desired delay 
    //    hasn't occurred, just request another loop and return
    if(!isAnimating || time<nextTime){
        requestAnimationFrame(animate);
        return;
    }
    // set nextTime to the next elapsed time
    nextTime=time+delay;
    // re-render everything
    canvas.renderAll();
    // request another loop
    requestAnimationFrame(animate);
}