Panning Html5 canvas without rerendering - html

I would like to pan on my Html5 canvas without having to rerender, in a smooth transition (not jumpy). Is this possible? Are there code examples?
If possible, can this also be applied for zooming?
I have a performance issue when running on a lower end system (windows tablet), where panning just uses up too much cpu and ends up unusable. The scope is ~2000 graphic objects.

Unfortunately, you can't transform a canvas without redrawing it; however, if it is really just a matter of having too many draw calls, you can render the canvas once, cache the result, then on subsequent draws redraw the cached image. Note, this method won't really take well to scaling beyond maybe 150%, depending on the actual stuff you are drawing.
I made a fiddle that shows what this might look like:
http://jsfiddle.net/mobidevelop/sBvab/
There can be a little bit of jumpiness, but it's generally better than it is without caching the image.
Your mileage may vary.

In short, no. You must redraw the scene if you want panning on the canvas, unless you're doing something bad, like using CSS to limit visible canvas size and your canvas is actually larger. (Don't do this, it isn't a performance gain).
But redrawing your canvas as you pan ought to be fast if you've written it well. If it is "jumpy", then odds are something else is wrong here.
The above is also true for zooming, especially if you want your vector paths/text/etc to scale.

Related

HTML5 Canvas and Game Programming

I hope this isn't too open ended.
I'm wondering if there is a better (more battery-friendly) way of doing this --
I have a small HTML 5 game, drawn in a canvas (let's say 500x500). I have some objects whose positions I update every 50ms or so. My current implementation re-draws the entire canvas every 50ms. I can't imagine that being very good for battery life on mobile platforms.
Is there a better way to do this? This must be a common pattern with games.
EDIT:
as requested, here are some more updates:
Right now, the objects are geometric primitives drawn via arcs and lines. I'm not opposed to making these small png/jpg/gif files instead of that'd help out. These are small graphics -- just 15x15 or so.
As the game progresses, more and more of the screen changes at a time. However, at the start, the screen changes relatively slowly (the objects randomly moved a few pixels every 50ms).
Nearly every game with continuous animation like this redraws everything every frame; clever updating algorithms are only applicable when a small part of the screen is changing and there is a nice rule to figure out what is overlapping that part.
Here is some general optimization advice:
Make sure that as much as possible of your graphics are handled by the GPU and not the CPU. (This may be impossible if the user's browser does not use the GPU for 2D canvas rendering, but you can expect upgrades may change that as HTML5 gaming gains popularity.)
This means that you should avoid elaborate clever algorithms in favor of doing as little work as possible in JS code — except that avoiding performing a lot of drawing when it is easy to determine that it will be invisible (e.g. outside the bounds of the screen) is generally worthwhile.
If your target platforms support it (generally not the case for current mobile devices), try using WebGL instead of 2D Canvas. You will have to do more detail work, but WebGL allows you to use operations which are much more likely to be provided efficiently by the GPU hardware.
If your game becomes idle — that is, nothing is actually animating at the moment — stop redrawing. Stop your update loop until the user interacts with the game or a timeout occurs.
It may be helpful for you to add to your question details of what types of graphics you are drawing (e.g. are you using sprites, or geometric primitives? Are you drawing images rotated/scaled? Does most of the screen change or just a few small objects? Are you blending many layers?) and perhaps even a screenshot or two; then we can suggest what sort of optimizations are suitable for your particular game.
Don't draw a background, make it an image and set the CSS background-image of the canvas.
Using requestAnimationFrame should help with battery life.
http://paulirish.com/2011/requestanimationframe-for-smart-animating/
Only do a redraw if something has actually changed. If you haven't already, introduce the concept of invalidations. (ie, the canvas is valid so nothing redraws until something moves. Anything moving within the window of the canvas causes the canvas to become invalid, thus needing a redraw)
If you want to be battery friendly you can use Crafty. This game engine is using modern CSS3 technology so it doesn't need to update a canvas all the time. Look at this example game here.
The way you don't want to redraw entire canvas every frame, it only can be the "Dirty-Check" or "Dirty Matrix" algorithms.
Dirty-check seems more efficient than entire redraw. but I think it depends on your render implementation.
it is not necessary to use it if you are using canvas2D to render. Nearly every game has complex sprites and animation. if you use dirty-check, when a part of sprite or background map need to update, you have to figure out what is overlapping this part. and then clearRect this small area of canvas, and then redraw every sprite or map. etc, what is overlapping.
It means your had to run canvas render api more times than normal render implementation because of the overlapping part. And Canvas2d render performance usually does't sounds efficient.
But if you use WebGL, that maybe quite difference. even though I am not family with WebGL, I do knew that maybe more efficient. Dirty-Check should be a good Choice to match your propose.

Do browsers render canvas elements that are not inside the viewport?

I have a page that has pretty heavy (mid-weight rather) canvas operations going on. To cater for users on mobile devices and older computers I was thinking I could implement a mechanism that will check if the canvas element is actually visible and decide if the constant calculations and canvas updates (animation running at 30fps) do have to be done or not.
This is working fine, yet when doing a performance test with the Chrome Dev Tools I noticed that even when I disable my visibility check and just let things render all the time the CPU usage of the function in question drops quite a bit when no part of the canvas element(s) is visible (although in theory it should still be performing the same tasks). So: at least on my computer running Chrome 17 it does not make a real difference if I check for the element's actual visibility.
To cut a long story short: Do I need to do this or are browsers smart enough to handle such a case without even telling them (and I can save the visibility checking)?
EDIT:
So I made some "research" on this topic and built this fiddle.
What happens is that it just generates noise at 30 frames per second. Not too pleasing to the eye but, well... The upper part is just a plain div to block the viewport. When I scroll down and have the canvas element in the viewport CPU Usage tells me it's taking up about 40%, so apparently the browser does have quite a lot to do here. When I scroll back up so that I just have the maroon colored div in my viewport and profile the CPU usage it drops to sth around 10%. When I scroll back down: usage goes up again.
So when I implement a visibility check like in this modified fiddle, I do see an increase (a tiny one to be honest) in CPU usage instead of a drop (as it has the additional task of checking if the canvas is inside the viewport).
So I am still wondering if this is some side effect of something that I am not aware of (or I am making some major mistake when profiling) or if I can expect browsers to be smart enough to handle such situations?
If anyone could shed a light on that I'd be very thankful!
I think you're confused between whether the logic is running and whether the rendering is happening. Many browsers now hardware-accelerate their canvases so all rendering happens on the GPU, so actual pixel pushing takes no CPU time anyway. However your tick function has non-trivial code to generate random noise on the CPU. So you're only really concerned over whether the tick function is running. If the canvas is offscreen, it certainly won't be rendered to the display (it's not visible). As for the canvas draw calls, it probably depends on the browser. It could render all draw calls to an off-screen canvas in case you suddenly scroll it back in to view, or it could just queue up all the draw calls and not actually do anything with them until you scroll the canvas in to view. I'm not sure what each browser does there.
However, you shouldn't use setInterval or setTimeout for animating Canvas. Use the new requestAnimationFrame API. Browsers don't know what you do in a timer call so will always call the timer. requestAnimationFrame on the other hand is designed specifically for visual things, so the browser has the opportunity to not call the tick function, or to reduce the rate it's called at, if the canvas or page is not visible.
As for how browsers actually handle it, I'm not sure. However, you should definitely prefer it since future browsers may be able to better optimise requestAnimationFrame in ways they cannot optimise setInterval or setTimeout. I think modern browsers also reduce the ordinary timers to 1 Hz if the page is not visible, but it's definitely much easier for the browser to optimise requestAnimationFrame, plus some browsers get you V-syncing and other niceness with it.
So I'm not certain requestAnimationFrame will mean your tick function is not called if the canvas is scrolled out of view. So I'd recommend using both requestAnimationFrame and the existing visibility check. That should guarantee you the most efficient rendering.
From my own experience it renders whatever you tell it to render regardless of position on screen.
An example is if you draw tiles, that exceeds the canvas size, you will still see the performance drop unless you optimize the script.
Try your function with a performance demanding animation, and see if you still get the same results.

Zooming in and out on canvas

I wrote a paint application using the HTML5 canvas element.
Now I want to give the user an option to zoom in and out while painting.
How can I do this?
There are a few ways. It really depends on what you're looking for.
You could do it by scaling the entire context, as in ctx.scale(2,2), and then redrawing everything at this larger scale. Several things drawn, like paths and text, will scale gracefully. To accomplish this you will need to keep good track of everything drawn so far.
Another way is to take the entire canvas and draw it back to itself. This requires a temporary canvas because the operation is really: Draw to temp canvas, clear main, draw back to main scaled.
Another way is to use CSS transforms to merely zoom the canvas itself, which will make the image blurry (its zoomed!) but does not require changing any of the pixels already on the canvas.

How to properly render a html5 canvas game with best performance results

I hope my English is good enough.
The Problem:
I am developing some canvas game, using context2d. I did a perfomance test to see how well canvas render and stuff.
For painting, the method drawImage was used with some 50x50 jpg preloaded in memory at start.
My test was to instantiate a lot of logic square 50x50 objects moving random in the canvas
with no collission just to see the fps.
main loop was done with interval.
The problem, i noticed low fps when about 3000 random 50x50 on the screen, well i know the more you render, the less framerate. But i wanna ask something.
The question:
Is a good idea render every logic object in the canvas screen alone?
For example, with no collision, if i overlap two 50x50 in the same position, or almost the same position, the visible output is something lesser than (50·50)2 pixels, but i am drawing (50·50)2 pixels using drawimage for each element in the main loop.
Hope you guys understand the problem and the question.
Render alternatives? some logic techniques to archieve this instead of rendering every object alone?
I understand what you are asking, you are asking maybe you should try and rendering the collisions so you don't have to draw twice. Well frankly, I think you'd be better off just drawing the second square on top of the first one, and I'll tell you why:
Your logic will probably take more actions to determine the amount of overlapping and drawing the more complex shape, then actually drawing it.
So in my opinion, you'd be better off not testing for collisions in this one.
People, correct me if I'm wrong.
Definitely just draw. The bitblt (pixel copy) is optimized and will certainly be faster than collision logic between sprites. However, the one exception is possibly testing for off-screen sprites. This is a fast test because you're only checking against the screen bounds, that is, if a sprite is off the screen. If you have 10,000+ sprites, and many are off-screen most of the time - for example when zoomed in - then the test is worth it.. If they're always on screen, then just draw.

Will avoid drawing half pixel in HTML5 canvas improve speed?

I am drawing a sprite (of a ball) on a canvas element. As the ball moves however, the x or y position of the ball may become a fraction, eg. (20.153; 63.638). When canvas is used to draw this image, it attempts to use transparent pixels to make the ball appear in it's position more accurately.
I was wondering whether I should use Math.round() before drawing the ball to avoid the transparent pixel stuff, and possibly speeding up the game a lot. Will this help much? The game is a sorta complex pong game.
The image below should help with my explanation:
At least this guy seems to believe so. As Gabe mentioned, it depends on the implementation.
Note that some sort anti-aliasing seems to kick in if you are using regular coords (1, 14, etc.). For this reason some guides (Dive Into HTML5 mainly) seem to suggest that you are better off by rending using half pixels (ie. 1.5, 14.5, etc.). I don't know if this makes any difference to performance, though. It's noticeable on render result at least.
You might also want to experiment with various layering schemes. See this question for more information. Depending on your situation you might want to treat your objects as separate canvases even and just offset them on top of the background.
Alternatively you could try to render it all on one canvas. In this case you have some extra stuff to keep track of. This library seems to handle all the bookkeeping for you.