Is calling requestAnimationFrame with Raphael a performance hit? - javascript

I'm working on a fairly resource hungry web application which heavily relies on Raphael.js for roughly 50% of the animations used, the rest I have rolled my own animation method which uses webkitRequestAnimationFrame in conjunction with the the Web Audio API's context.currentTime to sync animations with the audio component.
I am experiencing pretty terrible performance at the moment and looking through Raphael's source I see that it also uses requestAnimationFrame. Most of the lag I am experiencing seems to occur when both my animations and Raphael's are running concurrently. Is this because requestAnimationFrame is essentially being called twice per draw cycle?
Essentially what I'm asking is basically do I have to re-roll my own implementation of an animate for raphael objects and stick it in with my existing requestAnimationFrame?

Hmmm as far as I know the whole point of RAF is to sync everything so that its ready for the next render update. I would be doing exactly the same as you as the this is the whole point of it.
As per the spec:
The expectation is that the user agent will run tasks from the animation task source at at a regular interval matching the display's refresh rate. Running tasks at a lower rate can result in animations not appearing smooth. Running tasks at a higher rate can cause extra computation to occur without a user-visible benefit.
So I would say NO it shouldn't be a performance hit.

I'm having a similar issue with sluggish SVG animation. My understanding of RAF is that it batches updates together wherever they come from, so I dont think that was your problem.
I've found that most of my cycles are taken up by repainting. There's not much you can do JS-wise to speed up repainting. But I think you can make it easier on the browser by cutting down on transparency effects, filters, and large areas of the screen changing. Also, repainting is a function of the the amount of pixels that you're updating. I'm making a full-screen site and when I double the viewport size, it doubles my paint time.

Related

Slow down world time and rendering in Javascript for Webkit / Chrome

I would like to record browser animations in the smoothest possible framerate, including an alpha channel. Due to single threaded performance limitations I am looking for a way to slow down the producer of these animations. I currently achieve this by increasing the delay and duration of timers (in my case anime.js), this allows me to sample screen at a lower frame rate, while the target frame rate can be achieved.
The change of duration and delays is not overly painful, but I would like to do this in a more generic way. For example instruct the browser to have a world clock that runs on 10% of real speed. I have already found the Proxy suggestion below, but this does not seem to impact the current animation rendering.
Slow down time with JavaScript
What can be done to globally reduce all the animation, as if everything would take 10 times longer?

requestAnimationFrame resource consumption: redrawing whole or part of canvas

As seen from Stuck with SetInterval ,SetTimeOut and Requestanimationframe or the like, requestAnimationFrame repeat "once the browser is ready". In other words, it keeps the browser busy.
I'm creating a "hover" effect using "mousemove" when plotting a chart with many data points. It's easy to do by reploting the whole chart/canvas using requestAnimationFrame repeatedly. Code is short in this case.
Instead of the whole canvas, I tried to replot only the data point under mouse (hover, <1% of the canvas) using requestAnimationFrame. For that several arrays need to be added and the code is longer.
It can be different from case to case, but in general, is requestAnimationFrame a resource-intensive method? Redrawing the whole canvas for the sake of <1% of the area seems not sound economically.
requestAnimationFrame is not resource intensive, its purpose is to adjust the CPU consumption to what the screen can display (in terms of framerate).
You can assume that requestAnimationFrame allows your code to be ran once per frame of the screen. It's up to you to optimize the code of the callback so it doesn't recompute positions, shapes and colors of static things (only the point under the cursor).
Redrawing the whole canvas isn't the problem, the problem is redrawing the same image every frame.
Instead, redraw only when something has changed in your graphic.
You could start an infinite requestAnimationFrame (rAF) loop waiting for the state to change, but this will force the browser to stay in an animated mode, which forces it to enter some branches in the event-loop that it could otherwise ignore (specs). See this answer of mine for more details.
Given that mouse events are now throttled to screen refresh rate, in modern browsers you wouldn't even win by throttling this event in rAF, except that all the browsers still don't do that, looking at you Safari....
So to summarize,
Clear all / Redraw all. Painting only part of the canvas doesn't improve perfs that much, and this way you avoid a lot of trouble at coding.
Redraw only when your graphics changed. Avoid useless renderings.
Avoid keeping a requestAnimationFrame loop active for nothing. It just saves trees.

Does requestAnimationFrame can be stuck by long javascript

I know the requestAnimationFrame be invoked before the re-rendering of the browser, and the frequency is about 60fps, but if there is a very long javascript in the callback of requestAnimationFrame does it can block the re-rendering of the Browser? and therefore stuck the next requestAnimationFrame?
And move over, Why the browser re-rendering in 60fps, if there no content or style changed?
Yes.
As with any event-based function call (requestAnimationFrame, setTimeout, addEventListener, etc.) if the JS engine is busy running another function (even the same function from an earlier iteration) then the new function can't run until the previous one is finished.
I'm a game developer and quite familiar with this. Any frame that takes too long to render will not only drop the frame-rate but will also lock up the DOM.
I strongly suggest you look into webworkers and offscreen canvas'. This allows you to push heavy loads into background processes that won't interfere with animation frames or the DOM.
An couple of excellent demos can be found here: https://developers.google.com/web/updates/2018/08/offscreen-canvas
While what you said is true regarding 60fps, only sometimes as per the docs
requestAnimationFrame() calls are paused in most browsers when running in background tabs or hidden iframes in order to improve performance and battery life.

Multiple canvases on a page. Optimization questions

I have a very long page with multiple canvases. They don't overlap each other, and are mostly used separately for PIXI.js to play spritesheets.
I use requestAnimationFrame to render each canvas.
I have a few questions since I'm unsure how to optimize.
1) When a canvas is offscreen, do I need to cancelAnimationFrame? Or does it not matter because it is offscreen and therefore won't be painted?
2) Should I have all my render functions within the same requestAnimationFrame? Will that improve performance?
Any other suggestions?
Comments provide most of the information, let me still answer all the points:
requestAnimationFrame is naturally a window, not canvas method. Thus it is not aware of canvas visibility. There is "element" parameter in WebKit, but it is not in current spec http://www.w3.org/TR/animation-timing/#requestAnimationFrame. Thus there are no benefits in having multiple handlers, it will improve performance if you have just one requestAnimationFrame taking care of the entire flow.
Browsers (tested on Safari/FF/Chrome) will not call requestAnimationFrame if tab is not visible at all. There's no much benefit in cancelling animation frame request manually.
PIXI is not checking for canvas visibility in renderer.render(stage). You can use getBoundingClientRect to check canvas visibility before rendering. This may increase performance quite a bit. How to tell if a DOM element is visible in the current viewport?
Best way to profile this particular scenario is probably through Chrome timeline view https://developer.chrome.com/devtools/docs/timeline . Animation skipping may reduce browser composite/paint times. Only checking javascript execution time might be a little misleading, especially if we remember that WebGL calls may execute asynchronously.

JavaScript speed optimization for iPad/ Phonegap DHTML game?

I'm creating a game for the iPad using Phonegap, which means I'm using JavaScript/ CSS/ HTML for iPad's Safari. Basically, I'm moving around lots of img elements (sometimes changing their src) on 1024x768 resolution, just local files without any net connection. On the desktop Safari things work smoothly, but on the iPad, my setInterval feels delayed and flickering. Do you have any speed optimization tips for me that I could try? Thanks!
PS: I'm aware that switching to the iOS's native Objective-C would likely be much, much faster, but I'd really love to try it with standard JS/HTML/CSS.
You've run into one of the most common browser scripting issue with animated webpages.
The reason why your application slows down is because the browser is a single-threaded environment. As soon as you forget that you'll get into trouble.
setInterval makes you believe that your actions will happen in parallel like in a multi-threaded environment. But what really happens is that setInterval pushes the action to the UI stack to be handled at a later time. But if too many things are getting in to this stack at one time some actions will lag. The setInterval will keep pushing new actions, but the old ones will be still there, and the whole rendering becomes a sluggish mess.
As to when it happens, it depends on the hardware/software capabilities. iPad has much lower horse power than a desktop PC, that is pretty obvious.
Things you can do in order to avoid lag.
Trade smoothness for speed: raise your delay between intervals, so as to avoid cumulative actions in the UI stack.
setTimeout: this alternative is very similar to setInterval, except that it doesn't ensures a given interval between repetition, rather focuses on how long the browser should wait until repeating the action. So in order to make it more like setInterval you may need to keep track of the elapsed time between actions and calculate the measure of the change that has to be taken care of.
Group animations: you can have one interval for some related animations (you manage a mini-queue for them) and so you decrease the actual setInterval calls, and gain more power over controlling race conditions.
Also make sure to read this piece of article:
Making an iPad HTML5 App & making it really fast (Thomas Fuchs the creator of script.aculo.us)
Use CSS3 animations that use GPU acceleration... This will have a huge effect on any animations.

Categories

Resources