在canvas中,经常会用到画布旋转的操作,但是在旋转过程中会遇到一些令人费解的问题,今天就对canvas旋转做一个详细的解释。
Canvas旋转语法
Canvas提供了rotate方法来对画布上的绘图进行旋转。
<!-- canvas标签,必须具备id,width,height三个属性 -->
<canvas id="myCanvas" width="200" height="100">浏览器不支持Canvas</canvas>
// 通过getElementById方法,在JS中找到对应的Canvas元素
const canvas = document.getElementById("myCanvas");
// getContext() 是一个内置的HTML对象,它提供了用于绘图的属性和方法
// 这里接收的参数是'2d',说明这个canvas标签用于绘制平面图案,如果想要绘制立体图案,参数改为'webg1'即可
const ctx = canvas.getContext("2d");
// 将画布的填充样式设置为红色
// 这里的值可以是颜色,渐变或图案,默认的fillStyle是黑色
ctx.fillStyle="#f00";
// 旋转30°
ctx.rotate(Math.PI / 6);
ctx.fillRect(0,0,150,75);
rotate()
,这个方法是又Canvas的context提供的,它接收一个参数,这个参数指的是当前绘图顺时针旋转的角度,如上面代码所示,rotate方法的参数是“Math.PI / 6”,所以绘图应该会沿顺时针方向旋转30度。
如果希望绘图按照逆时针方向旋转呢?在参数前面加一个负号即可。
// 逆时针旋转30°
ctx.rotate(-Math.PI / 6);
ctx.fillRect(0,0,150,75);
以绘图自身中心点进行旋转
通过上面两次旋转发现,canvas中的rotate方法是绕着画布的原点(0,0)进行旋转的。但是在实际的使用中,经常需要的是围绕绘图自身的中心店进行旋转,下面就来进行这一种操作。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<canvas
id="myCanvas"
width="1000"
height="1000"
style="background-color: green"
>浏览器不支持Canvas</canvas
>
</body>
<script>
const canvas = document.getElementById("myCanvas");
const ctx = canvas.getContext("2d");
ctx.fillStyle = "#f00";
ctx.moveTo(0, 500);
ctx.lineTo(1000, 500);
ctx.moveTo(500, 0);
ctx.lineTo(500, 1000);
ctx.strokeStyle = "red";
ctx.stroke();
ctx.translate(canvas.width / 2, canvas.height / 2);
ctx.rotate(Math.PI / 9);
ctx.fillRect(-80, -50, 160, 100);
</script>
</html>
首选,我定义了一个1000*1000的正方形画布,然后在画布上绘制了两条交叉的分割线,用来定位整个画布的中心点,也是我希望围绕着旋转的中心点。
const canvas = document.getElementById("myCanvas");
const ctx = canvas.getContext("2d");
ctx.fillStyle = "#f00";
ctx.moveTo(0, 500);
ctx.lineTo(1000, 500);
ctx.moveTo(500, 0);
ctx.lineTo(500, 1000);
ctx.strokeStyle = "red";
ctx.stroke();
然后,我把画布的坐标原点从右上角改为整个画布的中心,也就是两条线的交叉点
ctx.translate(canvas.width / 2, canvas.height / 2);
接下来,设置绘图旋转的角度,这里我设置了顺时针旋转20度。
ctx.rotate(Math.PI / 9);
最后,设置绘图的中心点和画布的中心点重合,并且开始绘图。
ctx.fillRect(-80, -50, 160, 100);
上图就是最终渲染出来的效果,这是目前我想到的一种解决办法,还是感觉有点不太满意,大家有比较好的解决办法吗?