为什么需要多个 rotate() 来将每个数字放在正确的位置? - Canvas 时钟编号
Why are multiple rotate() needed to place every number on the right spot? - Canvas Clock Numbers
关注this tutorial which shows how to make an analog clock using HTML canvas, I've had a hard time understanding what is going on when placing numbers on the clock face.
代码为here,以下是我想请教的部分
function drawNumbers(ctx, radius) {
var ang;
var num;
ctx.font = radius * 0.15 + "px arial";
ctx.textBaseline = "middle";
ctx.textAlign = "center";
for(num = 1; num < 13; num++){
ang = num * Math.PI / 6;
ctx.rotate(ang);
ctx.translate(0, -radius * 0.85);
ctx.rotate(-ang);
ctx.fillText(num.toString(), 0, 0);
ctx.rotate(ang);
ctx.translate(0, radius * 0.85);
ctx.rotate(-ang);
}
}
在 for 循环中,第一个 ctx.rotate(ang)
将数字设置在它应该位于的位置。
下一次旋转 ctx.rotate(-ang)
会使数字恢复直立状态,因为它是倾斜的。 (虽然我不知道为什么它会这样而不把数字放回第一位。)
然后,ctx.fillText(…)
显示数字后,它似乎又做了同样的事情。
为什么需要这两个rotate()
?它们的工作方式与上层的不同吗?如果做,怎么做?
这段代码试图做的是回到它之前的位置,即 canvas 的中心。
将上下文想象成一张 sheet 可以旋转和移动的纸 (translate
),上面有固定的笔。
- 首先,他们确实旋转了那张 sheet 纸,以便沿着所需的方向描绘一条垂直线。
- 然后他们将纸的sheet垂直移动,使笔处于正确的位置。不过这里的纸sheet还是旋转的,所以如果从这里横着画,画出来的会是斜的。
- 所以它们确实以另一种方式再次旋转以使文本处于正确的角度。
- 他们绘制文本。
- 现在他们想回到点 1 以便能够绘制下一个刻度。为此,他们采用相同的路线,但采用另一种方式:将纸 sheet 旋转回所需的角度,以便它们可以垂直移动到中心。
- 垂直移动到中心
- 最后向后旋转,使纸的 sheet 处于下一个刻度的原始方向。
但是你不应该这样做。 rotate()
可能最终会出现舍入问题,所以rotate(angle); rotate(-angle)
不能回到初始方向,但是对于一些轻微旋转的状态,这对您的应用程序来说可能是灾难性的,因为现在当您尝试绘制像素完美的线条时,您将无法并且会破坏应用程序的整体性能。
而是使用绝对setTransform
方法回到原来的位置:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var radius = canvas.height / 2;
radius = radius * 0.90
drawNumbers(ctx, radius);
function drawNumbers(ctx, radius) {
var ang;
var num;
ctx.font = radius * 0.15 + "px arial";
ctx.textBaseline = "middle";
ctx.textAlign = "center";
for(num = 1; num < 13; num++){
ang = num * Math.PI / 6;
// go (back) to center
ctx.setTransform(1, 0, 0, 1, radius, radius);
ctx.rotate(ang);
ctx.translate(0, -radius * 0.85);
ctx.rotate(-ang);
ctx.fillText(num.toString(), 0, 0);
}
// reset to identity matrix;
ctx.setTransform(1, 0, 0, 1, 0, 0);
}
canvas {
background-color: white;
}
<canvas id="canvas" width="400" height="400">
</canvas>
这是另一个不使用旋转的实现。
相反,我用一点三角函数计算 x, y
。
起始角度为var ang = Math.PI;
然后在循环中我们减少它 ang -= Math.PI / 6;
一旦知道公式,计算位置就很容易了:
let x = radius * Math.sin(ang)
let y = radius * Math.cos(ang)
下面是一个功能齐全的示例
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.translate(canvas.width / 2, canvas.height / 2);
ctx.font = "16px arial";
ctx.textAlign = "center";
var radius = 60
var ang = Math.PI;
for (let num = 1; num < 13; num++) {
ang -= Math.PI / 6;
let x = radius * Math.sin(ang)
let y = radius * Math.cos(ang)
ctx.fillText(num.toString(), x, y);
ctx.beginPath()
ctx.arc(x, y - 6, 12, 0, 2 * Math.PI);
ctx.stroke();
ctx.beginPath()
ctx.arc(x, y - 6, 45, -ang-2,-ang);
ctx.stroke();
}
<canvas id="canvas" width="160" height="160"></canvas>
我个人从来不喜欢使用旋转,因为小的静态 canvas 图像可能没问题,但是当我们转向具有多个对象的更复杂的动画时,当我必须调试多次旋转时很快就会变得很痛苦,很难跟上。
关注this tutorial which shows how to make an analog clock using HTML canvas, I've had a hard time understanding what is going on when placing numbers on the clock face.
代码为here,以下是我想请教的部分
function drawNumbers(ctx, radius) {
var ang;
var num;
ctx.font = radius * 0.15 + "px arial";
ctx.textBaseline = "middle";
ctx.textAlign = "center";
for(num = 1; num < 13; num++){
ang = num * Math.PI / 6;
ctx.rotate(ang);
ctx.translate(0, -radius * 0.85);
ctx.rotate(-ang);
ctx.fillText(num.toString(), 0, 0);
ctx.rotate(ang);
ctx.translate(0, radius * 0.85);
ctx.rotate(-ang);
}
}
在 for 循环中,第一个 ctx.rotate(ang)
将数字设置在它应该位于的位置。
下一次旋转 ctx.rotate(-ang)
会使数字恢复直立状态,因为它是倾斜的。 (虽然我不知道为什么它会这样而不把数字放回第一位。)
然后,ctx.fillText(…)
显示数字后,它似乎又做了同样的事情。
为什么需要这两个rotate()
?它们的工作方式与上层的不同吗?如果做,怎么做?
这段代码试图做的是回到它之前的位置,即 canvas 的中心。
将上下文想象成一张 sheet 可以旋转和移动的纸 (translate
),上面有固定的笔。
- 首先,他们确实旋转了那张 sheet 纸,以便沿着所需的方向描绘一条垂直线。
- 然后他们将纸的sheet垂直移动,使笔处于正确的位置。不过这里的纸sheet还是旋转的,所以如果从这里横着画,画出来的会是斜的。
- 所以它们确实以另一种方式再次旋转以使文本处于正确的角度。
- 他们绘制文本。
- 现在他们想回到点 1 以便能够绘制下一个刻度。为此,他们采用相同的路线,但采用另一种方式:将纸 sheet 旋转回所需的角度,以便它们可以垂直移动到中心。
- 垂直移动到中心
- 最后向后旋转,使纸的 sheet 处于下一个刻度的原始方向。
但是你不应该这样做。 rotate()
可能最终会出现舍入问题,所以rotate(angle); rotate(-angle)
不能回到初始方向,但是对于一些轻微旋转的状态,这对您的应用程序来说可能是灾难性的,因为现在当您尝试绘制像素完美的线条时,您将无法并且会破坏应用程序的整体性能。
而是使用绝对setTransform
方法回到原来的位置:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var radius = canvas.height / 2;
radius = radius * 0.90
drawNumbers(ctx, radius);
function drawNumbers(ctx, radius) {
var ang;
var num;
ctx.font = radius * 0.15 + "px arial";
ctx.textBaseline = "middle";
ctx.textAlign = "center";
for(num = 1; num < 13; num++){
ang = num * Math.PI / 6;
// go (back) to center
ctx.setTransform(1, 0, 0, 1, radius, radius);
ctx.rotate(ang);
ctx.translate(0, -radius * 0.85);
ctx.rotate(-ang);
ctx.fillText(num.toString(), 0, 0);
}
// reset to identity matrix;
ctx.setTransform(1, 0, 0, 1, 0, 0);
}
canvas {
background-color: white;
}
<canvas id="canvas" width="400" height="400">
</canvas>
这是另一个不使用旋转的实现。
相反,我用一点三角函数计算 x, y
。
起始角度为var ang = Math.PI;
然后在循环中我们减少它 ang -= Math.PI / 6;
一旦知道公式,计算位置就很容易了:
let x = radius * Math.sin(ang)
let y = radius * Math.cos(ang)
下面是一个功能齐全的示例
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.translate(canvas.width / 2, canvas.height / 2);
ctx.font = "16px arial";
ctx.textAlign = "center";
var radius = 60
var ang = Math.PI;
for (let num = 1; num < 13; num++) {
ang -= Math.PI / 6;
let x = radius * Math.sin(ang)
let y = radius * Math.cos(ang)
ctx.fillText(num.toString(), x, y);
ctx.beginPath()
ctx.arc(x, y - 6, 12, 0, 2 * Math.PI);
ctx.stroke();
ctx.beginPath()
ctx.arc(x, y - 6, 45, -ang-2,-ang);
ctx.stroke();
}
<canvas id="canvas" width="160" height="160"></canvas>
我个人从来不喜欢使用旋转,因为小的静态 canvas 图像可能没问题,但是当我们转向具有多个对象的更复杂的动画时,当我必须调试多次旋转时很快就会变得很痛苦,很难跟上。