Jem
Jem

Reputation: 6406

HTML Canvas: How to draw a flipped/mirrored image?

I'm trying to flip/mirror an image as I paint it on an HTML canvas; I found a game tutorial showing a sprite sheet per direction a character has to face, but this doesn't seem quite right to me. Especially since each frame has a different size.

What would be the best technique to reach this goal?

I tried to call the setScale(-1, 1); on my canvas with no success. Maybe that isn't meant for this.

Thanks

Upvotes: 49

Views: 66860

Answers (4)

L777
L777

Reputation: 8457

If you just flip it horizontally using ctx.scale(-1, 1) it will get off of bounds... so use translate to adjust its position:

ctx.translate(canvas.width, 0);
ctx.scale(-1, 1);
ctx.drawImage(img, 0, 0);

For a shorter code you can remove the translate and use the image size as negative offset in the second parameter of the drawImage (x coordinate) instead:

ctx.scale(-1, 1);
ctx.drawImage(img, canvas.width * -1, 0);

If you want to restore the context later, add save/restore before and after it all:

ctx.save();
ctx.scale(-1, 1);
ctx.drawImage(img, canvas.width * -1, 0);
ctx.restore();

Upvotes: 21

digitaltag
digitaltag

Reputation: 331

You need to set the scale of the canvas as well as inverting the width.

function drawToCanvas(img, context, width, height){
    context.save();
    context.scale(-1, 1);
    context.drawImage(img, 0, 0, width*-1, height);
    context.restore();
}

There are probably some performance issues with this but for me that was not an issue.

Upvotes: 33

jerry
jerry

Reputation: 397

You don't need to redraw the entire image when creating a reflection. An original reflection simply shows the bottom part of the image. This way you are redrawing a smaller part of the image which provides better performance and also you don't need to create linear gradient to hide the lower part of the image (since you never draw it).

 var img = new Image();
 img.src = "//vignette2.wikia.nocookie.net/tomandjerryfan/images/9/99/Jerry_Mouse.jpg/revision/latest?cb=20110522075610";
 img.onload = function() {
   var thumbWidth = 250;
   var REFLECTION_HEIGHT = 50;
   var c = document.getElementById("output");
   var ctx = c.getContext("2d");
   var x = 1;
   var y = 1;

	//draw the original image
   ctx.drawImage(img, x, y, thumbWidth, thumbWidth);
	ctx.save();
	//translate to a point from where we want to redraw the new image
   ctx.translate(0, y + thumbWidth + REFLECTION_HEIGHT + 10);
   ctx.scale(1, -1);
   ctx.globalAlpha = 0.25;
   
   //redraw only bottom part of the image
   //g.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
   ctx.drawImage(img, 0, img.height - REFLECTION_HEIGHT, img.width, REFLECTION_HEIGHT, x, y, thumbWidth, REFLECTION_HEIGHT);

   // Revert transform and scale
  ctx.restore();

 };
 body {
   background-color: #FFF;
   text-align: center;
   padding-top: 10px;
 }
<canvas id="output" width="500" height="500"></canvas>

Upvotes: 4

Phrogz
Phrogz

Reputation: 303205

  1. You can do this by transforming the context with myContext.scale(-1,1) before drawing your image, however

  2. This is going to slow down your game. It's a better idea to have a separate, reversed sprite.

Upvotes: 40

Related Questions