Flickering during resizing of HTML5 canvas - html

I'm observing some flickering during the resizing of an animated canvas control.
You can see it in action at this page. Drag the 'width' slider left and right to try it for yourself. I see this flickering in Chrome 26.0.1410.43 running on Linux. Currently this page won't work in Firefox until it supports HTML5's <input type="range">.
I've tried to reproduce the issue on a smaller scale in this jsFiddle. It's not as noticeable, but occurs for me when the canvas is around 90% of the available width wide.
The code traps requestAnimationFrame, and resizing wipes the canvas. I would hope that the render callback would be called before the browser's frame was painted. This doesn't seem to be the case, as the white background shows through occasionally during resizing.
Is there anything that can be done to avoid this?

When you set canvas.width or canvas.height it clears the canvas, combined with the redrawing this causes the flicker you see.
You can mitigate this to a reasonable extent by saving the canvas to a temporary canvas before resizing and then drawing it back again afterwards.
Here's my resize function:
function resize(width, height) {
//Create temp canvas and context
var tempContext = Utils.Canvas.Create2DContext(context.canvas.width, context.canvas.height);
//Draw current canvas to temp canvas
tempContext.drawImage(context.canvas, 0, 0);
//Resize current canvas
context.canvas.height = height;
context.canvas.width = width;
//Draw temp canvas back to the current canvas
context.drawImage(tempContext.canvas, 0, 0);
}
If you resize to a smaller size then the temp canvas is "overdrawn" so it'll completely fill the current canvas. However if you resize to a larger size then your temp canvas will only fill part of the current canvas. The part it doesn't fill will still flicker as it's redrawn.
If you wanted to get a bit more fancy you could try drawing a temp canvas of the correct (final) size rather than simply copying the current canvas. This would be slower but could well eliminate all flicker.
In my case I'm resizing to fill a div, so having a little flicker along the bottom and right edges is tolerable, and certainly much better than the whole thing flickering.
EDIT:
Here's an update of your jsFiddle with my changes applied:
jsfiddle.net/Uz5Pt/13
It seems to work better than where I'm using it in my app! You can hardly see any flashing on any newly created bits of canvas.

Related

html5 canvas animation. moving an images gives flickering or a trail

I've seen other posts about this but I can't find anything to help me out.
I'm drawing an image on the canvas which moves, when it moves it leaves a trail of itself behind which hasn't been cleared. If I draw this image on top of another I get no trail but the image on top flickers. I don't think clearRect will work for me.
Can I save the canvas state between the image animation? Or should I be using a second canvas?
I'm not quite sure how to proceed, any advice would be great
* added examples - jsfiddle.net/zE67k/2 with an image and flicker. jsfiddle.net/zE67k/3 without an image and trail. this is just an example, I'm trying to achieve this with a background image to the canvas also.
* I also tried placing one canvas on top of another and I still get the flicker, I think the problem is where I place the clearRect. It does work if I put the clearRect just before the eye is drawn, but the way this code draws and updates the eyes does so one at a time, therefore the previous eye is cleared leaving only one. I'm trying it from this tutorial http://astronautz.com/wordpress/html5-eyes-that-follow-the-mouse/
You should save the clean canvas before drawing the other image ontop and restore that saved clean state before drawing the moved image again. You can use an additional canvas to save a clean state:
// create clean buffer
var buffer = document.createElement('canvas'),
canvas = document.getElementById('myCanvas');
buffer.width = canvas.width;
buffer.height = canvas.height;
// draw "background"/clean state to canvas
drawBackground(canvas);
// save clean state
buffer.getContext('2d').drawImage(canvas);
Then whenver you want to draw / move your other image/item simply restore the clean state:
canvas.getContext('2d').drawImage(buffer);
drawObject(canvas, x, y, w, h);

"googlemaps" dragging with html5 canvas

I have a large html5 canvas (much larger than the screen), and I want to implement a "google-maps" dragging.
I want the canvas to be dragable by mouse, and I want it to render only the part we can see on the screen each time I drag it.
Does someone have a good idea?
I solved this problem by using the jQuery UI draggable component on the canvas element.
I enclosed it in a div - with overflow set to hidden, and made the canvas as large as I need it to be. Works a charm
http://jqueryui.com/demos/draggable/
To render your canvas only on the part of the screen that we can see you could use the drawImage function :
drawImage(image, x, y, width, height)
With "image" as your original entire canvas, "x" and "y" representing the offset that move when dragging and "width/height" the size of the actual windows.
See documentation :
http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#dom-context-2d-drawimage
and a great tutorial from mdc :
https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Canvas_tutorial/Using_images

HTML Canvas horizontal flip only works every second click

I have a canvas element with a photo loaded on it. When clicking a link, the following is performed:
var ctx = canvas.getContext("2d");
ctx.scale(-1,1);
ctx.drawImage(canvas, canvas.width * -1, 0, canvas.width, canvas.height);
This works as expected (the image is flipped horizontally) on the first click, the third click, the fifth click, etc. On the second click, the fourth click, the sixth click, etc, nothing happens.
Any ideas on how I can get this to work for every click?
Yeah, the problem is because you're not restoring the canvas scale to 1,1 after you draw the image, so basically the first time the event is called your canvas scale is gonna be turned into -1,1 the next time it's gonna be 1,1 but you need it to be always -1,1. That's because you're drawing the image directly from the canvas and not from an image element thus, you gonna need to flip it every time.
Try using ctx.save() before the scaling and ctx.restore() after drawing the image. Or calling ctx.scale(-1, 1) again after drawing the image. Or you could just do the scaling outside the event (but after you've drawn the image to the canvas the first time) if your canvas is only used for this.
This here works for every click:
http://jsfiddle.net/4kcjn/2/
Ask yourself, what is different between it and yours?
It could be image-load related. Try yours without an image. Does it still have the same problem?

html canvas pixel buffer

I don't know the correct term, but in GTK I believe it was called a pixel buffer. You could copy all or some of the drawing area to a pixbuf, and then later dump the pixbuf back to the screen, rather than going through and rendering the entire thing all over again. I am implementing a menubar, and the menubar drops down and occludes everything underneath it. However, it takes a few seconds to draw the entire canvas, so I was wondering if there is a correct way to copy everything that will be occluded by the drop down menu, then when the drop down menu is closed, redraw it to the screen. I imagine this can be done with the context.getImageData() function, but I have read that it is extremely inefficient.
It is true, getImageData() is far too inefficient. But there's a better start for specifically what you're trying to do:
With canvas context's drawImage method, you can pass in an image but you can also pass in another canvas. So construct a temp canvas that will never be added to the page:
// only exists in javascript, not on the page
tempcanvas = document.createElement('canvas');
tempcanvas.height = (normal canvas width);
tempcanvas.width = (normal canvas height);
Then you can call tempcanvasContext.drawImage(normalCanvas, 0, 0) to take a snapshot of the current canvas right before the drop down menu is created. When the drop down menu disappears, you call normalcanvasContext.drawImage(tempcanvas, 0, 0) to draw it back.
I hope this gives a good general idea, and it should be much faster than getImageData. You can make it even more efficient by only copying the exact portions of the screen you want to redraw.

Zoom or slice a section of canvas HTML5

I working on HTML Canvas library to construct a "PIE Chart" Now to finish it I need the
given section of PIE Chart to Zoom or Slice once clicked on the section.
I almost done with the PIE Chart with the above exception only
Please do not recommend me to use any charting library available already
What you want cannot directly be done: when you draw on the canvas, you paint pixels that instantly dry onto the canvas. If you want to "zoom in" you'll have to erase the canvas (ctx.clearRect(...)) and re-paint your pie chart using more pixels. This is what a non-retained drawing mode (or immediate drawing mode) graphics API like Canvas requires.
Contrast this with SVG, a retained drawing mode graphics system, where the commands to draw content result in elements being created that you may track events for, adjust properties on, and see the visual results updated for you.
You can "zoom in"--redraw your pie chart larger--either by changing your drawing commands (bigger arc radius, lineWidth, etc.) or by transforming your context (changing the scale and translation) and then issuing the same drawing commands again.
There is also one non-option: if you leave the width and height attributes of the canvas unchanged but change the CSS to height and width properties you can 'zoom in' on your canvas without re-drawing. This is going to cause each virtual pixel on the canvas to grow on your screen, however, resulting in pixelation.