如何在画布中旋转一张图片?

20

我正在制作一个HTML5画布游戏,希望旋转其中的一张图片。

var link = new Image();
link.src='img/link.png';
link.onload=function(){
    ctx.drawImage(link,x,y,20,20); // draws a chain link or dagger
}

我想旋转这张图片。标准的图片旋转方式是在画布上下文对象上设置旋转角度。但这样会将整个游戏都旋转!我不想这样做,只想旋转这一个精灵。我该如何做到呢?


5
1.8万次浏览量,4个赞...这有点奇怪。 - Radvylf Programs
6个回答

11

使用 .save().restore() 方法(更多信息):

link.onload=function(){
    ctx.save(); // save current state
    ctx.rotate(Math.PI); // rotate
    ctx.drawImage(link,x,y,20,20); // draws a chain link or dagger
    ctx.restore(); // restore original states (no rotation etc)
}

酷,谢谢!你有关于在进行任意角度旋转时重新调整图像尺寸的数学计算方法吗? - Razor Storm
@Razor Storm:你需要将中点进行翻译,然后再将其翻译回来,但你已经做到了,因为你已经发布了它。 - pimvdb
1
我认为在drawImage之后进行反向旋转比保存和恢复更有效率。 - Gustavo6046
@Gustavo6046 这是到目前为止我在其他地方搜索时看到的每个人都在说的。 - oldboy
2
有没有办法旋转drawImage元素而不旋转canvas本身? - oldboy
@oldboy 我认为更容易的方法是在完成操作后旋转画布,然后再将其旋转回来?也许可以将此功能提取到一个函数中,以确保不会出现问题。如果你很在意,甚至可以使用装饰器,像 f(g()) { return function new_g() { do_stuff_before(); g(); do_stuff_after(); } } - Gustavo6046

6

您可能想在那里放置一个 translate();,因为图像将围绕原点旋转,而默认情况下原点位于左上角,因此您可以使用 translate(); 来更改原点。

link.onload=function(){
    ctx.save();
    ctx.translate(x, y); // change origin
    ctx.rotate(Math.PI);
    ctx.drawImage(link,-10,-10,10,10);
    ctx.restore()
}

哎呀,位置还是乱的。 - Razor Storm
1
好的,所以你有一个位置,你想要绘制一张图像(x,y)。所以你想做的是将原点(0,0)转换到位置(x,y),使得该位置现在为(0,0),并在原点正上方绘制你的图像。所以如果你的图像高度和宽度都是20px,ctx.drawImage(link,-10,-10,10,10); 你将能够绕其中心旋转图像。 - Carb0n1c

5

看看我的解决方案。它是完整的例子,也是最易理解的。

    var drawRotate = (clockwise) => {
        const degrees = clockwise == true? 90: -90;
        let canvas = $('<canvas />')[0];
        let img = $(".img-view")[0];

        const iw = img.naturalWidth;
        const ih = img.naturalHeight;

        canvas.width = ih;
        canvas.height = iw;

        let ctx = canvas.getContext('2d');

        if(clockwise){
            ctx.translate(ih, 0);
        } else {
            ctx.translate(0, iw);
        }

        ctx.rotate(degrees*Math.PI/180);
        ctx.drawImage(img, 0, 0);

        let rotated = canvas.toDataURL();        
        img.src = rotated;
    }

5
您的原始“解决方案”如下所示:
ctx.save();
ctx.translate(x,y);
ctx.rotate(-this.angle + Math.PI/2.0);
ctx.translate(-x, -y); 
ctx.drawImage(this.daggerImage,x,y,20,20);
ctx.restore();

然而,可以使用以下代码使其更加高效(无需saverestore):
ctx.translate(x,y);
ctx.rotate(-this.angle + Math.PI/2.0);
ctx.drawImage(this.daggerImage,x,y,20,20);
ctx.rotate(this.angle - Math.PI/2.0);
ctx.translate(-x, -y); 

哦,不错!我会在 我的 游戏中使用这个。 - Radvylf Programs
1
有没有办法在不旋转 canvas 本身的情况下旋转 drawImage 元素? - oldboy

3

我在这里为我的游戏之一创建了一个可工作的示例。你可以从这里获取图像。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset=utf-8 />
<title>Test</title>
</head>
<body>
<canvas id="canvas" width="100" height="100"></canvas>
<script type="text/javascript">

var ctx = document.getElementById('canvas').getContext('2d');
var play = setInterval('Rotate()',16);
var i = 0;
var shipImg = new Image();
shipImg.src = 'ship.png';

function Rotate() {
  ctx.fillStyle = '#000';
  ctx.fillRect(0,0,100,100);

  ctx.save();
  ctx.translate(50, 50);
  ctx.rotate(i / 180 / Math.PI);
  ctx.drawImage(shipImg, -16, -16);
  ctx.restore();
  i += 10;
};

</script>
</body>
</html>

1
有没有办法旋转 drawImage 元素而不旋转 canvas 本身? - oldboy

1

我最终不得不做:

ctx.save();
ctx.translate(x,y);
ctx.rotate(-this.angle + Math.PI/2.0);
ctx.translate(-x, -y); 
ctx.drawImage(this.daggerImage,x,y,20,20);
ctx.restore();

你只需要在第一个翻译中使用x和y值,可以删除第二个翻译并停止将x和y值放入“drawImage();”中,这样会使值加倍。相反,请使用“drawImage(this.daggerImage,-10,-10,10,10);”。关于这方面的更多信息,请参见https://developer.mozilla.org/en/Canvas_tutorial/Transformations。 - Carb0n1c

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接