HTML5 Canvas 旋转函数
HTML5 Canvas rotate function
function drawNumbers(){
var rad, num;
cx.font= "30px Arial";
cx.textAlign = "center";
cx.textBaseline = "middle";
//numbers around the inner circumference
for(num=1; num < 13; num++){
rad = num * Math.PI/6; //angle for every number
cx.rotate(rad);
cx.translate(0, -175);
cx.rotate(-rad);
cx.fillText(num.toString(),0,0);
cx.rotate(rad);
cx.translate(0, 175);
cx.rotate(-rad);
}
}
function drawHands(){
//getting the time
var time = new Date();
var hours = time.getHours();
var minutes = time.getMinutes();
var seconds = time.getSeconds();
//setting the radians based on the time
//hour hand
hours %= 12;
hours = (hours * Math.PI/6) + (minutes * Math.PI/360) + (seconds * Math.PI/21600);
hands(hours, radius * 0.04, radius * 0.5);
//minute hand
minutes = (minutes * Math.PI/30) + (seconds * Math.PI/1800);
hands(minutes, radius * 0.03, radius * 0.65);
//second hand
seconds = (seconds * Math.PI/30);
hands(seconds, radius * 0.01, radius * 0.68);
}
function hands(ang, width, length){
cx.beginPath();
cx.lineWidth = width;
cx.lineJoin = "round";
cx.lineCap = "round";
cx.moveTo(0, 0);
cx.rotate(ang);
cx.lineTo(0, -length);
cx.stroke();
cx.rotate(-ang);
}
我在 W3Schools 学习 HTML5 canvas,教程教如何制作工作时钟。
1.我只是不明白额外的旋转在函数中是如何工作的。
2. 应用旋转函数时,是否总是从canvas的原点(0, 0)开始旋转?
当您调用 rotate
函数时,它会旋转整个 canvas,想象一下拿着一幅画然后倾斜它。它总是发生在原点附近。围绕不同点旋转的方法是先translate
整个canvas,然后rotate
它。
回到绘画类比,如果我们旋转了我们的绘画,一旦我们画好了线,我们就需要将绘画恢复到直立状态。因此我们rotate(-ang)
。如果我们已经翻译,我们也必须以类似的方式撤消我们的翻译。
旋转以及我们撤消旋转的原因
在下面的代码中,您可以看到我正在绘制一个基本的黑色矩形,然后调用一个函数将 canvas 旋转 0.5 弧度并绘制另一个矩形两次。我没有撤消我的旋转,所以第三个矩形实际上以 1 弧度旋转。
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
function drawRotatedRectangle() {
ctx.rotate(0.5);
ctx.fillRect(0, 0, 60, 50);
}
// Draw base rectangle
ctx.fillRect(0, 0, 60, 50);
// Rotate and draw second rectangle
ctx.fillStyle = "#FF0000";
drawRotatedRectangle();
// rotate and draw third rectangle
ctx.fillStyle = "#00FF00";
drawRotatedRectangle();
<canvas id="canvas"></canvas>
为了解决这个问题,我们修改了 drawRotatedRectangle()
函数以撤消它所做的所有平移和旋转:
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
function drawRotatedRectangle() {
ctx.rotate(0.5);
ctx.fillRect(0, 0, 60, 50);
ctx.rotate(-0.5);
}
// Draw base rectangle
ctx.fillRect(0, 0, 60, 50);
// Rotate and draw second rectangle
ctx.fillStyle = "#FF0000";
drawRotatedRectangle();
// rotate and draw third rectangle
ctx.fillStyle = "#00FF00";
drawRotatedRectangle();
<canvas id="canvas"></canvas>
现在我们看到红色(隐藏)矩形和绿色矩形处于同一角度。
绕原点不同的点旋转
为了演示我们如何围绕原点的不同位置旋转,我们可以先平移我们的上下文原点所在的位置,然后旋转我们的 canvas。下面我将原点移动到基本矩形的中心,旋转 canvas 并在基本矩形的顶部绘制一个旋转的矩形。平移和旋转再次按最近应用的顺序恢复。
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
function drawRotatedRectangle() {
// Move origin to center of rectangle
ctx.translate(30, 25);
// Rotate 0.5 radians
ctx.rotate(0.5);
// Draw rectangle where the center of the rectangle is the origin
ctx.fillRect(-30, -25, 60, 50);
// Undo our rotate
ctx.rotate(-0.5);
// Undo our translate
ctx.translate(-30, -25);
}
// Draw base rectangle
ctx.fillRect(0, 0, 60, 50);
// Rotate and draw second rectangle
ctx.fillStyle = "#FF0000";
drawRotatedRectangle();
// rotate and draw third rectangle
ctx.fillStyle = "#00FF00";
drawRotatedRectangle();
<canvas id="canvas"></canvas>
编辑 - 处理舍入错误
正如 Kaiido 在评论中提到的那样,rotate(a)
函数会舍入给定的输入,因此简单地执行反向 rotate(-a)
函数不会 return 您到原始转换。
他们建议的解决方案是使用 setTransform()
将转换矩阵设置到所需的位置,在这些示例中我们仅 returning 到 canvas 的原始转换所以我们可以使用单位矩阵:
ctx.setTransform(1,0,0,1,0,0)
或者,您也可以使用 save()
和 restore()
方法。这些就像将 canvas 上下文的当前状态推送到堆栈,当您 restore()
时,它将从堆栈中弹出最新状态 return 将您带到上一个转换。 This Jakob Jenkov 的文章通过一些例子进一步解释了这种方法。
function drawNumbers(){
var rad, num;
cx.font= "30px Arial";
cx.textAlign = "center";
cx.textBaseline = "middle";
//numbers around the inner circumference
for(num=1; num < 13; num++){
rad = num * Math.PI/6; //angle for every number
cx.rotate(rad);
cx.translate(0, -175);
cx.rotate(-rad);
cx.fillText(num.toString(),0,0);
cx.rotate(rad);
cx.translate(0, 175);
cx.rotate(-rad);
}
}
function drawHands(){
//getting the time
var time = new Date();
var hours = time.getHours();
var minutes = time.getMinutes();
var seconds = time.getSeconds();
//setting the radians based on the time
//hour hand
hours %= 12;
hours = (hours * Math.PI/6) + (minutes * Math.PI/360) + (seconds * Math.PI/21600);
hands(hours, radius * 0.04, radius * 0.5);
//minute hand
minutes = (minutes * Math.PI/30) + (seconds * Math.PI/1800);
hands(minutes, radius * 0.03, radius * 0.65);
//second hand
seconds = (seconds * Math.PI/30);
hands(seconds, radius * 0.01, radius * 0.68);
}
function hands(ang, width, length){
cx.beginPath();
cx.lineWidth = width;
cx.lineJoin = "round";
cx.lineCap = "round";
cx.moveTo(0, 0);
cx.rotate(ang);
cx.lineTo(0, -length);
cx.stroke();
cx.rotate(-ang);
}
我在 W3Schools 学习 HTML5 canvas,教程教如何制作工作时钟。 1.我只是不明白额外的旋转在函数中是如何工作的。 2. 应用旋转函数时,是否总是从canvas的原点(0, 0)开始旋转?
当您调用 rotate
函数时,它会旋转整个 canvas,想象一下拿着一幅画然后倾斜它。它总是发生在原点附近。围绕不同点旋转的方法是先translate
整个canvas,然后rotate
它。
回到绘画类比,如果我们旋转了我们的绘画,一旦我们画好了线,我们就需要将绘画恢复到直立状态。因此我们rotate(-ang)
。如果我们已经翻译,我们也必须以类似的方式撤消我们的翻译。
旋转以及我们撤消旋转的原因
在下面的代码中,您可以看到我正在绘制一个基本的黑色矩形,然后调用一个函数将 canvas 旋转 0.5 弧度并绘制另一个矩形两次。我没有撤消我的旋转,所以第三个矩形实际上以 1 弧度旋转。
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
function drawRotatedRectangle() {
ctx.rotate(0.5);
ctx.fillRect(0, 0, 60, 50);
}
// Draw base rectangle
ctx.fillRect(0, 0, 60, 50);
// Rotate and draw second rectangle
ctx.fillStyle = "#FF0000";
drawRotatedRectangle();
// rotate and draw third rectangle
ctx.fillStyle = "#00FF00";
drawRotatedRectangle();
<canvas id="canvas"></canvas>
为了解决这个问题,我们修改了 drawRotatedRectangle()
函数以撤消它所做的所有平移和旋转:
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
function drawRotatedRectangle() {
ctx.rotate(0.5);
ctx.fillRect(0, 0, 60, 50);
ctx.rotate(-0.5);
}
// Draw base rectangle
ctx.fillRect(0, 0, 60, 50);
// Rotate and draw second rectangle
ctx.fillStyle = "#FF0000";
drawRotatedRectangle();
// rotate and draw third rectangle
ctx.fillStyle = "#00FF00";
drawRotatedRectangle();
<canvas id="canvas"></canvas>
现在我们看到红色(隐藏)矩形和绿色矩形处于同一角度。
绕原点不同的点旋转
为了演示我们如何围绕原点的不同位置旋转,我们可以先平移我们的上下文原点所在的位置,然后旋转我们的 canvas。下面我将原点移动到基本矩形的中心,旋转 canvas 并在基本矩形的顶部绘制一个旋转的矩形。平移和旋转再次按最近应用的顺序恢复。
let canvas = document.getElementById("canvas");
let ctx = canvas.getContext("2d");
function drawRotatedRectangle() {
// Move origin to center of rectangle
ctx.translate(30, 25);
// Rotate 0.5 radians
ctx.rotate(0.5);
// Draw rectangle where the center of the rectangle is the origin
ctx.fillRect(-30, -25, 60, 50);
// Undo our rotate
ctx.rotate(-0.5);
// Undo our translate
ctx.translate(-30, -25);
}
// Draw base rectangle
ctx.fillRect(0, 0, 60, 50);
// Rotate and draw second rectangle
ctx.fillStyle = "#FF0000";
drawRotatedRectangle();
// rotate and draw third rectangle
ctx.fillStyle = "#00FF00";
drawRotatedRectangle();
<canvas id="canvas"></canvas>
编辑 - 处理舍入错误
正如 Kaiido 在评论中提到的那样,rotate(a)
函数会舍入给定的输入,因此简单地执行反向 rotate(-a)
函数不会 return 您到原始转换。
他们建议的解决方案是使用 setTransform()
将转换矩阵设置到所需的位置,在这些示例中我们仅 returning 到 canvas 的原始转换所以我们可以使用单位矩阵:
ctx.setTransform(1,0,0,1,0,0)
或者,您也可以使用 save()
和 restore()
方法。这些就像将 canvas 上下文的当前状态推送到堆栈,当您 restore()
时,它将从堆栈中弹出最新状态 return 将您带到上一个转换。 This Jakob Jenkov 的文章通过一些例子进一步解释了这种方法。