如何在HTML 5画布上旋转单个对象?

41
我正在尝试找出如何在HTML 5画布上旋转单个对象的方法。
例如:http://screencast.com/t/NTQ5M2E3Mzct - 我希望每张卡片都以不同的角度旋转。
到目前为止,我看到的所有文章和示例都演示了如何旋转整个画布。现在,我猜想我将不得不旋转画布,绘制图像,然后将画布旋转回原始位置再绘制第二个图像。如果是这种情况,请告诉我!我只是有一种感觉还有其他方式。
有人有任何想法吗?
8个回答

84

我最近在一个项目中遇到了同样的问题(我在那里踢旋转的外星人)。我只是使用了这个简单的函数,它可以做同样的事情,并且可以像ctx.rotate一样使用,但可以传递一个角度。对我来说很有效。

function drawImageRot(img,x,y,width,height,deg){
    // Store the current context state (i.e. rotation, translation etc..)
    ctx.save()

    //Convert degrees to radian 
    var rad = deg * Math.PI / 180;

    //Set the origin to the center of the image
    ctx.translate(x + width / 2, y + height / 2);

    //Rotate the canvas around the origin
    ctx.rotate(rad);

    //draw the image    
    ctx.drawImage(img,width / 2 * (-1),height / 2 * (-1),width,height);

    // Restore canvas state as saved from above
    ctx.restore();
}

太棒了,我的第一个答案!


1
这应该内置到画布中。完美地工作。谢谢分享! - Synexis
3
这个问题现在应该标记为答案了。很遗憾,SO不允许在以后选择更新的答案作为答案。也许这是需要考虑的事情,因为技术在不断变化,人们提出了更新、更正确的答案。 - raddevus
1
如果你一遍又一遍地旋转它,难道不会导致背景的退化吗? - v010dya
太棒了!谢谢你! - sean
2
使用“保存”和“恢复”功能不会为重置节省时间和麻烦吗? - Lee Goddard
这个函数必须内置到画布中,你帮我节省了很多时间,谢谢。 - Mohamed Akram

38
抱歉,在HTML5的画布元素中,您无法旋转单个元素。
动画的工作方式类似于在MS Paint中绘图:您绘制一些东西,制作一个屏幕..使用橡皮擦删除一些内容,以不同的方式绘制一些东西,制作一个屏幕..在顶部绘制其他内容,制作一个屏幕等等。
如果您在画布上有现有项,则必须擦除它(例如使用ctx.fillRect()clearRect()),然后绘制旋转的对象。
如果您不确定如何在第一次绘制时旋转,请参考以下内容:
ctx.save();
ctx.rotate(0.17);
// draw your object
ctx.restore();

3
我知道,当写更复杂的动画时这个问题变得更加严重,因为你必须在每一帧重新从头开始重新绘制整个画布 :) - Artiom Chilaru
2
建议您在答案中将 fillRect() 替换为 clearRect() - Phrogz
我不明白为什么在制定规格时他们没有采用类似于 Flash 的方法。 - UpTheCreek
我正在尝试的一些东西...你可以使用var indv_elem = document.createElement('canvas');var indv_ctx = indiv_elem.getContext('2d');来创建一个专门为该对象设计的独特画布。然后,你可以旋转那个单独的画布(离屏),在进行变换后,使用indv_ctx.drawImage(...)将其绘制到主画布上...只是一个想法而已 ;] - Danny Bullis
4
我知道这个问题已经有答案了,但是对于通过谷歌或搜索找到这个问题的任何人来说,请记住这个基本原则:双缓冲是一种常见的做法,您可以在屏幕外进行所有渲染,并将整个图像作为一个图像复制到您实际可见的画布上。它特别有助于动画效果。Artiom(等人),请记住,即使像Java这样的语言也是设计成在更新时完全重新绘制每一帧的。因此,尽管稍微更复杂一些,但它基于扎实的原则并具有其优点。完全值得学习和实现。 - Danny Bullis
显示剩余2条评论

19

要旋转单个对象,您需要设置变换矩阵。这非常简单:

            var context = document.getElementById('pageCanvas').getContext('2d');
            var angle = 0;
            function convertToRadians(degree) {
                return degree*(Math.PI/180);
            }
            
            function incrementAngle() {
                angle++;
                if(angle > 360) {
                    angle = 0;
                }
            }
            
            function drawRandomlyColoredRectangle() {  
                // clear the drawing surface
                context.clearRect(0,0,1280,720);
                // you can also stroke a rect, the operations need to happen in order 
                incrementAngle();
                context.save();                
                context.lineWidth = 10;  
                context.translate(200,200);
                context.rotate(convertToRadians(angle));
                // set the fill style
                context.fillStyle = '#'+Math.floor(Math.random()*16777215).toString(16);
                context.fillRect(-25,-25,50,50);
                context.strokeRect(-25,-25,50,50);                
                context.restore();
            }
            
            // Ideally use getAnimationFrame but for simplicity:
            setInterval(drawRandomlyColoredRectangle, 20);
        <canvas width="1280" height="720" id="pageCanvas">
            You do not have a canvas enabled browser
        </canvas>


9

简单来说,要使一个对象旋转而不影响其他形状的旋转,您需要执行以下步骤:

  1. 保存上下文:ctx.save()
  2. 将中心点移动到所需位置:ctx.translate(200, 200);
  3. 旋转:context.rotate(45 * Math.PI / 180);
  4. 绘制形状、精灵或其他内容:ctx.draw...
  5. 重置中心点:ctx.translate(-200, -200);
  6. 将上下文还原为其原始状态:ctx.restore();

function spinDrawing() {
    ctx.save();
    ctx.translate(200, 200);
    context.rotate(45 * Math.PI / 180);
    ctx.draw //your drawing function
    ctx.translate(-200, -200);
    ctx.restore();
}

注意事项:翻译后,画布的原点会发生改变,这意味着当您绘制形状时,形状的坐标应相应地对齐。

在上述列表之外绘制的形状不会受到影响。希望这能帮到您。


2
而旋转呢?你从来没有提到过它。 - Andrew S
这正是我需要知道的,谢谢!如果您加上了旋转部分,可能会得到更多的赞。 - Sfp

5
这段HTML/JavaScript代码或许可以阐明这个问题:
<!DOCTYPE html>
<html>
<body>

<canvas id="myCanvas" width="233" height="233" style="border:1px solid #d3d3d3;">
your browser does not support the canvas tag </canvas>

<script type="text/javascript">

var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
var canvasWidth=233;
var canvasHeight=233;
var rectWidth=100;
var rectHeight=150;
var x=30;
var y=30;
var translateX= x+(rectWidth/2);
var translateY= y+(rectHeight/2);

ctx.fillRect(x,y,rectWidth,rectHeight);

ctx.translate(translateX,translateY);
ctx.rotate(5*Math.PI/64); /* just a random rotate number */
ctx.translate(-translateX,-translateY); 
ctx.fillRect(x,y,rectWidth,rectHeight);


</script>

</body>
</html>

我认为查看与旋转相关的数学内容是有帮助的,希望这对你也有帮助。


2

要旋转一个对象,您可以使用 rotate() 方法。以下是将矩形对象顺时针旋转 135 度的示例。

 <script>
  var canvas = document.getElementById('Canvas01');
  var ctx = canvas.getContext('2d');

  var rectWidth = 100;
  var rectHeight = 50;

  //create line
  ctx.strokeStyle= '#ccc';
  ctx.beginPath();
  ctx.moveTo(canvas.width / 2, 0);
  ctx.lineTo(canvas.width / 2, canvas.height);
  ctx.stroke();
  ctx.closePath();

  ctx.beginPath();
  ctx.moveTo(0, canvas.height/2);
  ctx.lineTo(canvas.width, canvas.height/2);
  ctx.stroke();
  ctx.closePath();

  // translate ctx to center of canvas
  ctx.translate(canvas.width / 2, canvas.height / 2);

  // rotate the rect to 135 degrees of clockwise
  ctx.rotate((Math.PI / 180)*135);

  ctx.fillStyle = 'blue';
  ctx.fillRect(0, 0, rectWidth, rectHeight);
</script>
</body>

这里有一个演示,你可以自己尝试:http://okeschool.com/examples/canvas/html5-canvas-rotate


2
<!DOCTYPE html>
<html>
<body>

<canvas id="myCanvas" width="500" height="450" style="border:1px solid #d3d3d3;">
</canvas>

<Button id = "right" onclick = "rotateRight()">Right</option>
<Button id = "left" onclick = "rotateLeft()">Left</option>
<script src = "zoom.js">

</script>

<script>
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");

createRect();

function rotateRight()
{
 ctx.save();
 ctx.clearRect(0,0,500,450);
 ctx.translate(c.width/2,c.height/2);
 ctx.rotate(10*Math.PI/180 );  
 ctx.translate(-c.width/2,-c.height/2);
 createRect();

}

function rotateLeft()
{
 ctx.save();
 ctx.clearRect(0,0,500,450);
 ctx.translate(c.width/2,c.height/2);
 ctx.rotate(-10*Math.PI/180 );  
 ctx.translate(-c.width/2,-c.height/2);
 createRect();  
}



function createRect()
{
 ctx.beginPath();
 ctx.fillStyle = "#AAAA00";
 ctx.fillRect(250,250,90,50);
}
</script>

</body>
</html>

1
我发现这个问题是因为我在画布上用画布线绘制了一堆东西,然后决定旋转其中一些。不想再做一堆复杂的事情,我想要旋转我已经有的东西。我找到的一个简单的解决方案是这样的:
ctx.save();

ctx.translate(x+width_of_item/2,y+height_of_item/2);
ctx.rotate(degrees*(Math.PI/180));
ctx.translate(-(x+width_of_item/2),-(y+height_of_item/2));

// THIS IS THE STUFF YOU WANT ROTATED
// do whatever it is you need to do here, moveto and lineto is all i used 
// I would expect anything to work. use normal grid coordinates as if its a
// normal 0,0 in the top left kind of grid

ctx.stroke();
ctx.restore();

无论如何 - 这可能不是特别优雅,但这是一种非常简单的方法,可以将一个特定元素旋转到您的画布上。

看看所有这些旋转的元素!


不确定为什么,但这是唯一对我起作用的。 - Gabriel Petersson

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