HTML5画布在角度上绘制图像

44

我正在尝试在<canvas>中进行动画制作,但不知道如何绘制旋转的图片。希望实现的效果是绘制几张普通图片,其中一张图片缓慢旋转。(如果这张图片不在屏幕中心,是否会有任何影响呢?)

3个回答

90

在绘制需要旋转的图像之前,您需要修改变换矩阵。

假设图像指向一个HTMLImageElement对象。

var x = canvas.width / 2;
var y = canvas.height / 2;
var width = image.width;
var height = image.height;

context.translate(x, y);
context.rotate(angleInRadians);
context.drawImage(image, -width / 2, -height / 2, width, height);
context.rotate(-angleInRadians);
context.translate(-x, -y);

x,y坐标是画布上图像的中心点。


9
在最后不需要旋转/平移时,你可以在进行变换和绘制之前和之后使用context.save()context.restore() - Matthew Crumley
41
虽然使用save()/restore()可能会看起来更加清晰,但这样做会使程序变得更加低效。引擎将不得不存储/恢复所有上下文属性,而不仅仅是我们在此处操作的属性。在一个敏感的代码路径上,这是很重要的。 - Jakub Wieczorek
10
不,引擎可以轻松地在每个上下文属性上保留“脏”标记,并且只会惰性保存(然后还原)在“保存()”和“还原()”之间被触及的属性。手动调整此操作是过早的优化。 - s4y
2
使用translate()rotate()来恢复变换矩阵是非常糟糕的建议。由于浮点运算的舍入,这将无法可靠地将矩阵恢复到其原始值。 - Feuermurmel
3
@JakubWieczorek 你有这两种方法的性能测试结果吗?如果需要调用两个三角函数的rotate()方法比复制整个变换矩阵(如果实现为6个64位浮点数,则为48字节)更快,我会感到惊讶。 - Feuermurmel
显示剩余2条评论

20

有趣的是,第一种解决方案适用于如此之多的人,但并没有给我需要的结果。最终我不得不这样做:

ctx.save();
ctx.translate(positionX, positionY);
ctx.rotate(angle);
ctx.translate(-x,-y);
ctx.drawImage(image,0,0);
ctx.restore();

其中(positionX, positionY)是我想要图片所在画布上的坐标,(x, y)是我想要旋转的图片上的点。


15

我写了一个函数(基于Jakub的回答),允许用户根据自定义旋转点和自定义旋转角度在X,Y位置上绘制图像:

function rotateAndPaintImage ( context, image, angleInRad , positionX, positionY, axisX, axisY ) {
  context.translate( positionX, positionY );
  context.rotate( angleInRad );
  context.drawImage( image, -axisX, -axisY );
  context.rotate( -angleInRad );
  context.translate( -positionX, -positionY );
}

然后您可以这样调用它:

var TO_RADIANS = Math.PI/180; 
ctx = document.getElementById("canvasDiv").getContext("2d");
var imgSprite = new Image();
imgSprite.src = "img/sprite.png";

// rotate 45º image "imgSprite", based on its rotation axis located at x=20,y=30 and draw it on context "ctx" of the canvas on coordinates x=200,y=100
rotateAndPaintImage ( ctx, imgSprite, 45*TO_RADIANS, 200, 100, 20, 30 );

2
使用translate()rotate()来恢复变换矩阵是非常糟糕的建议。由于浮点运算的舍入,这将无法可靠地将矩阵恢复到其原始值。 - Feuermurmel

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