3

In attempting to get a drawing of a canvas and redrawing it onto the same canvas later is giving unexpected behavior. See Jsfiddle for example.

The logic is fairly straight forward:

  • Given an image on the canvas, and translation to the center (I'm using a rectangle to demonstrate).
  • Clip out a section of the image. I'm simply copying the entire "image" in the example.
  • Possibly do manipulation.
  • Paste back to the same canvas after clearing it. The point being to clip a section of the original image at a given point with a width / height, and paste it later with modifications.

var c=document.getElementById("cvs1"),
    ctx = c.getContext("2d"),
    bufferCvs = document.createElement('canvas'),
    bufferCtx = bufferCvs.getContext('2d');


bufferCvs.width = c.width;
bufferCvs.height = c.height;

ctx.translate( c.width/2, c.height/2 );
ctx.fillStyle="#FF0000";
ctx.fillRect( -75, -50 ,150,100);

//Image data experiment
//Set the buffer width / height same size as rectangle
bufferCvs.width = 150;
bufferCvs.height = 100;
//Draw the "image" from the first context to the buffer by clipping the first, and pasting to 0,0 width the same "image" dimensions.
bufferCtx.drawImage( c, -75, -50, 150, 100, 0, 0, 150, 100 );
//clear out old canvas drawing
ctx.save()
ctx.setTransform(1,0,0,1,0,0,1,0,0);
ctx.clearRect(0, 0, c.width, c.height);
ctx.restore();

ctx.drawImage( bufferCvs, -75, -50, 150, 100 );

Since I'm keeping the exact same coordinates / dimensions, the expected output would be what was originally on canvas to begin with. However, only part of the upper left corner is drawn (see fiddle). I'm using drawImage for efficiency reasons, but I've used get/putImageData with the same results. Both width and height are defined as mentioned to fix other strange behaviors.

How would you go about making sure everything stored in the buffer canvas is drawn, instead of just the top corner?

Edit: To help with my question and what behavior I believe is going on I'll post some screens.

Step 1: Translate context 1 to the center, and draw a rectangle to represent an image.

ctx.translate( c.width/2, c.height/2 );
ctx.fillStyle="#FF0000";
ctx.fillRect( -75, -50 ,150,100);

Translate / Add Rect

Step 2: Use drawImage to "clip" from the -75, -50 point and cut out just the rectangle using the width 150, 100. This should be drawn onto the canvas buffer, but it is not

bufferCvs.width = 150;
bufferCvs.height = 100;
//Draw the "image" from the first context to the buffer by clipping the first at -75, -50 (the start of the image), and pasting to 0,0 width the same "image" dimensions.
bufferCtx.drawImage( c, -75, -50, 150, 100, 0, 0, 150, 100 );

I would expect the buffer canvas to look like this (It is not):

Expected buffer canvas

However, if I change the drawImage to

bufferCtx.drawImage( c, 0, 0, 150, 100, 0, 0, 150, 100 );

I get an expected amount of white space on the buffer (and the last drawImage back to the context without issue)

Step 3: Clear out the old "image" from the first context. This shouldn't change the translation since I restore the context state after performing the clear. (This works as expected)

ctx.save()
ctx.setTransform(1,0,0,1,0,0,1,0,0);
ctx.clearRect(0, 0, c.width, c.height);
ctx.restore();

Step 4: Simply take what is in the buffer canvas and draw it onto the original context where it started to return to this:

Translate / Add Rect

The idea is to more "clip" a region of the original, clear the old image, and paste the new clipped region centered back into the original context. I have looked at MDN's example, but the clipping portion of drawImage isn't performing as I expect.

Community
  • 1
  • 1
Ryan Q
  • 10,273
  • 2
  • 34
  • 39

1 Answers1

0

The main issue is that the first canvas drawn over the bufferCvs is not drawn on the place where you expect. The easiest way to prove this is by adding bufferCvs to the DOM tree: http://jsfiddle.net/CdWn6/4/

I guess this is what you're looking for: http://jsfiddle.net/CdWn6/6/

var c=document.getElementById("cvs1"),
    c2 = document.getElementById("cvs2"),
    bufferCvs = document.createElement('canvas'),
    bufferCtx = bufferCvs.getContext('2d'),
    ctx = c.getContext("2d"),
    ctx2 = c2.getContext("2d");

bufferCvs.width = c.width;
bufferCvs.height = c.height;

ctx.translate( c.width/2, c.height/2 );
ctx.fillStyle="#FF0000";
ctx2.translate( c.width/2, c.height/2 );
ctx2.fillStyle="#FF0000";

bufferCtx.translate( c.width/2, c.height/2 );

ctx.fillRect( -75, -50 ,150,100);
ctx2.fillRect( -75, -50 ,150,100);

//Image data experiment
bufferCtx.drawImage( c, -135, -110, 270, 220);

ctx.save()
ctx.setTransform(1,0,0,1,0,0,1,0,0);
ctx.clearRect(0, 0, c.width, c.height);
ctx.restore();

//Draw background to demonstrate coordinates still work
ctx.fillStyle="#00FF00";
//ctx.fillRect( -75, -50 ,150,100);

ctx.drawImage( bufferCvs, -75, -50, 150, 100 );
Minko Gechev
  • 25,304
  • 9
  • 61
  • 68
  • Not sure that's quite what I'm looking for. The point of the save / restore section is simply to clear out the existing canvas. The final drawImage still only draws a fraction of what I expected even in this example. – Ryan Q Mar 23 '13 at 09:20
  • You use translation over all but the buffer canvas. There's also a issue when you draw the first canvas onto the buffer. You draw everything including the white regions (because the rectangle inside the first canvas is surrounded by white "border") this makes the red region even smaller. – Minko Gechev Mar 23 '13 at 09:55
  • The part which seems to be throwing me off is why you perform: bufferCtx.drawImage( c, -135, -110, 270, 220). -135, -110 would be a coordinate which is off the canvas (even if the buffer canvas was translated to the center) – Ryan Q Mar 24 '13 at 07:12