-
-
Notifications
You must be signed in to change notification settings - Fork 3.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
renderAll does not use requestAnimationFrame #1979
Comments
@jagi, did you use fabric with metoer js? i saw you wanted to do a package somewhere. |
Hi, I upvote this, Would be great to have this feature.
I guess requestAnimationFrame would be more accurate. Not sure what s the matter with meteor, it happen to me with mutiple dom events interaction. This simple trick helped a lot. |
@asturur yes I've made Fabric.js package for Meteor but didn't publish it yet. However I'm planning to. Ok no problem, email me (email is in my profile info). |
Using |
I'm not sure it would help but I'm open to see a comparison. Could you create a demo? rAF is a different concept — renderAll is an on-demand call whereas rAF is a continuous loop. But, like I said, would love to see a comparison. |
Even when rendering on demand doesn't mean that it shouldn't be in sync with browser rendering frames. Developers should use |
I was trying to prepare comparison but without success. With Let's cite official specification:
and
Summing it up, we can say the same about moving object on canvas. When you move objects you render even 120 frames per second when you could just end up on 60 fps and still have smooth animation and save processing power and your battery. However I'm not 100% sure how to show this difference. Probably I should investigate it using Chrome Dev Tools. |
@jagi just to clarify — I know about rAF benefts, and I'm all for using it :) I'm just unsure about applicability towards canvas. For DOM animations (when browser needs to repaint), it's useful. But I'm not sure canvas applies. On the other hand, this article suggests using rAF with canvas as well, so there might be some truth to it. |
@jagi, yep you have right. I was certainly lazy to get a decent cross browser implementation and underscore was already loaded : D Now, i ve made some effort, ahahah, i m working with a render loop such
I also had to borrow this from the internet
I also keep using _.throttle to avoid sur numerous DOM events. This said i have not tested it to make sure it work well on major browsers. BTW, i also implemented a pseudo fps counter. I request another frame to realize the counting. |
@kangax rAF was designed at first for working with Canvas. There was similar feature in Flash. However it can speed up any rendering and should be used wherever it's possible. |
interesting, if i had time, i would inform myself about this matter. Still how it will work under nodejs? does it? |
I think it's not going to work in nodejs, for node there have to be different version of render function. |
Hi, Using 2000 elements on scene, i found this was super good to smooth the rendering process. fabric.fastCanvas = function(_super){
var __hasProp = {}.hasOwnProperty;
var __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
return (function(_super) {
__extends(fastCanvas, _super);
function fastCanvas() {
this.frame;
fastCanvas.__super__.constructor.apply(this, arguments);
}
fastCanvas.prototype.renderAll = function() {
var args = arguments;
var that = this;
window.cancelAnimationFrame(this.frame);
this.frame = window.requestAnimationFrame(function(){
fastCanvas.__super__.renderAll.apply(that, args);
});
};
return fastCanvas;
})(_super || fabric.Canvas);
};
//var fastCanvas = fabric.fastCanvas(fabric.StaticCanvas)
//var fastCanvas = fabric.fastCanvas(fabric.Canvas)
var fastCanvas = fabric.fastCanvas(fabric.CanvasWithViewport)
var canvas = new fastCanvas( .... as usual ); Borrowed some code from https://github.com/rstgroup/fabricjs-viewport |
Other than for simply drawing something once, Its aforementioned usage for queuing up DOM manipulation calls into a single browser render loop tick is simply a nice added benefit. Using The point being that the browser would then automatically sync up fabrics draw calls with the browsers internal render loop/refresh rate, never going above 60 times per second and dropping calls when necessary. Meaning that fabric could internally be calling the Right now fabric is doing a lot of extra unnecessary work on fast systems, drawing frames over and over again, multiple times for no reason. On slower systems it will choke and end up out of sync with any mouse/touch input. Using Just change the
And for At some point in the future consider implementing a render loop that starts when properties are changed via the |
Not that is important to me, but i have a 144hz framerate. |
|
If anyone is interested adding something along these lines into you application code should quickly monkeypatch fabric without modifying any of the source code: Warning: this is completely untested, but should do the job.
Whenever ( At the end of each frame we start a 300ms timeout, which if it gets fired will stop the render loop. And at the beginning of frame, we cancel it out. So whats basically happening is that if renderAll isn't called by fabric for 300ms, the loop stops, further saving resources. This in my eyes is a good temporary compromise until @kangax decides what should be done. Since it keeps the current behaviour of fabric 100% intact. Though personally I think hooking into the Though i'm not sure thats the way @kangax wants to go of course. |
I would still love to see a simple demo comparing current approach with the new one :) |
@kangax i'll put one together when I get a chance later on. It really is a no brainer if i'm honest. While there will be no noticeable difference on simple scenes and on high end hardware (other than a reduction in CPU consumption and temperature), the difference when rendering something more stressful should be dramatic. Think of it like playing an FPS shooter like quake or whatever. If the framerate drops to 25fps everything still remains locked to the users input, because all that is happening is that rendering frames are being dropped while all game logic and input code continues to run and update in real time. With the rendering pathway hardwired in as it currently is, each and every fabric render call that has occurred in a single browser tick has to complete before the browser can update object positions/properties. Meaning that as soon as the framerate drops in a stressful scene, rendering lags behind user input. It basically makes rendering asynchronous. Come to think it, if fabric goes this route it might be worth adding a callback to |
@kangax Okay here's a quick demo... I've chosen to modify your svg caching demo as it proves very stressfull. Using Chromes built in FPS counter i get about 13fps meaning that each This shows your standard demo with caching disabled. Grab one of the tiger heads and move it around. On my laptop at least (mobile core i7 CPU) all tiger heads stutter dramatically and the movement and object positions stop updating frequently, particularly when first grabbing a tiger head. Also note how far the tiger head lags behind the mouse input and how long it takes for the object controls to appear. Now try: http://jsfiddle.net/h8tfkokt/1/ Here we are using Obviously this is an extreme demo. Meaning that With a more reasonable workload most Whereas without it you find that for each browser tick we often have to perform Obviously how noticeable the above demo's are will depend on your hardware, but for me the difference is very dramatic, both demos result in about 12-13fps but using If you use the console to monitor how many times Interacting with objects in Fabric.js is exactly the kind of thing Hope this helps!! |
Great example :) and it's what I was talking about :) |
@godyr, thanks ! very interesting and experienced feeback ! : ) |
Any thoughts @kangax ??? As I said before it really is a no brainer and would be great to not have to patch this in the hacky way I am currently doing. |
I have thoughts but not time :) maybe later today, sorry |
how do i activate internal frame counter? |
Can someone update the wiki until one of the core maintainer has time to pick this issue ? |
@maboiteaspam "said the user with word 'spam' in the nickname" :D eheheh i could not resist, no offense of course. I will add a note in the wiki. @kangax could: |
@gordyr great demos, thanks. I looked at the CPU usage and — while I'm not seeing as significant improvement in snappiness as you are — rAF version does seem to take slightly less. I imagine on slower machines it's more noticeable. Looking at the timeline in DevTools I'm seeing some improvement as well. So... could you submit a PR and we'll go from there? :) Thanks! |
Keep in mind that following rAF will also improve overall rendering quality; synchronizing with the hardware's refresh rate (which, I believe, rAF does by default) will prevent duplicate and skipped frames insofar possible. This makes for less 'stuttering', even if the GPU/CPU power is not being maxed out. |
i would like to see how it behaves with my 144hz monitor. 60 does not go well with 144. |
This has landed in a simpler way. |
I realized that
renderAll
function does not userequestAnimationFrame
to sync with browser. I know that it's used in animations but it should be also used inrenderAll
. Why? When moving object it's just rendering new position usingrenderAll
and it's like the animation, so it's not efficient when not usingrequestAnimationFrame
. What do you think about it? I could create PR for this.Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.
The text was updated successfully, but these errors were encountered: