views:

557

answers:

2

I want to implement vertical scrolling of the contents of a HTML5 canvas element. I don't want to render the whole content again. Instead I would like to move the whole content down/up and only render the area, which has been scrolled into view.

I experimented with the getImageData and putImageData functions but in my tests they are almost as slow as repainting the whole scene.

// scroll 20px down
var data = ctx.getImageData(0, 0, width, height-20);
ctx.putImageData(0, 20);

What is the fastest way to copy rectangular pixel regions inside of a canvas element?

+5  A: 

For absolute speed, I would use an over-sized <canvas> inside a <div> with overflow:hidden set then use regular DOM methods to scroll the <canvas> inside the <div>.

Of course, this sacrifices memory usage in favor of speed.

slebetman
Good idea but unfortunately I don't know the exact size in advance and the scroll area is potentially thousands of pixel height so I don't think this will work for me.
Fabian Jakobs
I wish I had known of this approach before I implemented scrolling in my application. I use double buffering with a large hidden Canvas and a small viewport canvas. Then I copy the new visible portion from the hidden to the viewport. It works, but probably could be faster. And if the image could be thousands of pixels high, my solution would not work.
Paul Chernoch
But if there is no expectation of being able to scroll back down, when you reach the bottom, you can just repaint the last screen on a new "extra large" canvas. And if you have any down time (like a pause in the message stream), you can repaint and truncate then with noone even noticing. The former technique doesn't eliminate the delay, but it certainly limits it to happen much less.
Will Hartung
+2  A: 

Try this:

ctx.drawImage(ctx.canvas, 0, 0, width, height-20, 0, 20, width, height-20);

drawImage can take either an HTMLImageElement, an HTMLCanvasElement, or an HTMLVideoElement for the first argument.

Juan