1

Assuming i have an HTML5 canvas on which i've already drawn multiple images, and i don't have the final resulting image "in hand", and now i want to move the whole image in the canvas up? (just if like the user chose to 'scroll down' the image)

If i had the final image, i could have clear the canvas and draw it again in a 'y' coordinate which is negative, that'll work. The problem is that calling toDataUrl() in order to get the final image - is very CPU consuming.

Any other way to achieve this? Why can't i just tell the canvas to 'move everything up / down' by x pixels...?

thanks!

Amit Kanfer
  • 41
  • 1
  • 5

2 Answers2

4

Canvas drawImage() method accept an other canvas as source.
You can also draw the canvas on itself, but at each iteration, your image will have changed.

So the easiest way is to create an other canvas, which will keep your actual canvas image, and draw this new canvas to the one in the document :

var canvas = document.querySelector('canvas'),
  ctx = canvas.getContext('2d'),
  img = new Image(),
  // a ghost canvas that will keep our original image
  gCanvas = document.createElement('canvas'),
  gCtx = gCanvas.getContext('2d');
gCanvas.width = canvas.width;
gCanvas.height = canvas.height;


img.onload = function() {
  ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
  gCtx.drawImage(canvas, 0, 0, canvas.width, canvas.height);
  requestAnimationFrame(moveUp);
}
img.src = "http://lorempixel.com/200/200";

var y = 0;
function moveUp() {
  if (--y < (canvas.height * -0.5)) return;
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.drawImage(gCanvas, 0, y, canvas.width, canvas.height);
  requestAnimationFrame(moveUp)
}
<canvas width=200 height=200></canvas>
Kaiido
  • 123,334
  • 13
  • 219
  • 285
  • Didn't know that draw can accept the canvas itself as an argument. That did the trick!! thanks alot! – Amit Kanfer Sep 08 '15 at 09:02
  • Yes it can, but then it becomes kind of difficult to get what you are drawing, since each time you do it, the drawn image will be updated with the last drawn... It's easier to keep an other canvas, with our wanted state drawn on it. – Kaiido Sep 08 '15 at 09:04
  • @AmitKanfer If it solved your issue, remember to "accept the answer" thanks to the check on its left, that way, other answerers won't see this question in their list of "should be answered" – Kaiido Sep 08 '15 at 09:15
1

You can use ctx.getImageData (https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/getImageData) to get the image data and ctx.putImageData (https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/putImageData) to put the image data where you want.

Edit

Kaido's solution is the better alternative though.

Reference

Why is putImageData so slow?

Community
  • 1
  • 1
potatopeelings
  • 40,709
  • 7
  • 95
  • 119
  • I think it's at least as much consumptive as toDataURL isn't it ? – Kaiido Sep 08 '15 at 07:48
  • toDataURL converts it to a string. this one doesn't. The good part is that once you have the data from the first step you can reuse it multiple times without doing a getImageData again. – potatopeelings Sep 08 '15 at 07:49
  • Ok for the second part, but the first part... It does transform it to an array, and then iterate through this array to redraw... without GPU acceleration. – Kaiido Sep 08 '15 at 07:51
  • Sorry, I don't know enough about the GPU acceleration part. But I ran a quick test and the getImageData has a slight edge over toDataURL. Slight though... – potatopeelings Sep 08 '15 at 08:01
  • Yes, I think that both are really consumptive, maybe @markE could tell us more about it if he comes around... – Kaiido Sep 08 '15 at 08:02
  • 1
    Got it - what you are doing is best http://stackoverflow.com/questions/3952856/why-is-putimagedata-so-slow – potatopeelings Sep 08 '15 at 08:06