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

Posted

技术标签:

【中文标题】如何在 html 5 画布上旋转单个对象?【英文标题】:How do I rotate a single object on an html 5 canvas? 【发布时间】:2011-02-10 06:48:50 【问题描述】:

我试图弄清楚如何在 html 5 画布上旋转单个对象。

例如:http://screencast.com/t/NTQ5M2E3Mzct - 我希望这些卡片中的每一张都以不同的角度旋转。

到目前为止,我所看到的都是展示如何旋转整个画布的文章和示例。现在,我猜我必须旋转画布,绘制图像,然后在绘制第二张图像之前将画布旋转回原来的位置。如果是这样的话,那就让我知道吧!我只是觉得还有另一种方法。

有人知道吗?

提前致谢!

【问题讨论】:

【参考方案1】:

很遗憾,在 HTML5 画布元素中,您无法旋转单个元素。

动画的工作方式就像在 MS Paint 中绘图:你画一些东西,制作一个屏幕.. 使用橡皮擦删除一些东西,绘制不同的东西,制作一个屏幕.. 在顶部绘制其他东西,制作一个屏幕.. 等等.

如果您在画布上有一个现有项目 - 您必须将其擦除(例如使用 ctx.fillRect()clearRect()),然后绘制旋转的对象。

如果您在开始绘制时不确定如何旋转它:

ctx.save();
ctx.rotate(0.17);
// draw your object
ctx.restore();

【讨论】:

无赖!我想这是必须的,Artiom!感谢您的回复! 是的,我知道.. 当编写更复杂的动画时,这个问题变得更大,因为你必须从头开始重绘整个画布:) 建议您将答案中的fillRect() 替换为clearRect() 嗯..这取决于你想要做什么。如果一般背景是绿色的,那么fillRect()更合适:) 我知道这已经得到解答,但是对于任何通过 Google 或搜索遇到此问题的人,请牢记这一基本原则:双缓冲是一种常见做法,您可以在屏幕外进行所有渲染并复制将整个图像作为一张图像放到您实际可见的画布上。它尤其有助于动画。 Artiom(等人),请记住,即使像 Java 这样的语言也被设计为在更新时完全重绘每一帧。因此,尽管稍微复杂一些,但它基于扎根的原则并有其好处。完全值得学习和实施。【参考方案2】:

要旋转单个对象,您必须设置转换矩阵。这很简单:

            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   id="pageCanvas">
            You do not have a canvas enabled browser
        </canvas>

【讨论】:

【参考方案3】:

这段 html/javascript 代码可能会对这个问题有所了解:

<!DOCTYPE html>
<html>
<body>

<canvas id="myCanvas"   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>

我发现查看与旋转相关的数学很有帮助,我希望这对你也有帮助。

【讨论】:

【参考方案4】:

我在最近的一个项目中遇到了同样的问题(我把旋转的外星人踢得满地都是)。我只是使用了这个不起眼的函数,它做同样的事情,可以像 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();

是的,我的第一个答案!

【讨论】:

这应该内置在画布中。完美运行。谢谢分享! 这个现在应该被标记为真正的答案。太糟糕了,不允许在以后选择更新的答案作为答案。也许这是应该考虑的事情,因为技术发生了变化,人们提出了更新更正确的答案。 反复旋转会不会导致背景退化? 太棒了!谢谢! 不会使用saverestore 来节省时间和重置的麻烦吗?【参考方案5】:

基本上,要使对象正确旋转而不会旋转其他形状,您需要:

    保存上下文:ctx.save() 将轴心点移动到所需位置:ctx.translate(200, 200); 旋转:context.rotate(45 * Math.PI / 180); 绘制形状、精灵,随便什么:ctx.draw... 重置枢轴:ctx.translate(-200, -200); 将上下文恢复到其原始状态: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();

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

在上述列表之外绘制的形状不会受到影响。我希望它有所帮助。

【讨论】:

那么轮换呢?你从来没有提到过。 这正是我需要知道的,谢谢!也许如果你把轮换部分,你会得到更多的选票..【参考方案6】:
<!DOCTYPE html>
<html>
<body>

<canvas id="myCanvas"   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>

【讨论】:

【参考方案7】:

要旋转对象,您可以使用 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

【讨论】:

【参考方案8】:

我发现这个问题是因为我在画布上有一堆东西,用画布线条精心绘制,然后决定应该旋转其中一些。不想再做一大堆复杂的事情,我想轮换我拥有的东西。我发现一个简单的解决方案是这样的:

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();

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

Look at all those rotated elements!

【讨论】:

不知道为什么,但这是唯一对我有用的

以上是关于如何在 html 5 画布上旋转单个对象?的主要内容,如果未能解决你的问题,请参考以下文章

画布旋转后如何检测画布上的点

如何旋转 HTML5 画布的现有内容?

我们如何才能在旋转后的准确点停止这个 HTML5 画布轮?

在画布上绘制一个旋转的 Path2D 对象

在 HTML5 画布上绘制旋转文本

如何使用 clearRect 不在画布上绘制移动对象