我有一个代码可以绘制带点的螺旋线
var c = document.getElementById("myCanvas");
var cxt = c.getContext("2d");
var centerX = 400;
var centerY = 400;
cxt.moveTo(centerX, centerY);
var count = 0;
var increment = 3/32;
var distance = 10;
for (theta = 0; theta < 50; theta++) {
var newX = centerX + distance * Math.cos((theta) * 4 * Math.PI * increment );
var newY = centerY + distance * Math.sin(((theta)) * 4 * Math.PI * increment );
cxt.fillText("o", newX, newY);
count++;
if (count % 4 === 0) {
distance = distance + 10;
}
}
cxt.stroke();
<canvas id="myCanvas" width="800" height="800" style="border:1px solid #c3c3c3;"></canvas>
请注意我更改了增量值多少次,总会有一条线比其他线具有更多或更少的点
increment = 5/32;
这是否有可能画出一条完美的螺旋线,并且所有线的长度都相同?
这里有很多问题。就像@Anytech所说的那样,您首先需要确定想要多少个手臂(点的字符串)。在屏幕快照中,您似乎有5臂,但您可能是偶然得到的。我用距离替换了“ o”以帮助可视化问题:
var c = document.getElementById("myCanvas");
var cxt = c.getContext("2d");
var centerX = 200;
var centerY = 200;
cxt.moveTo(centerX, centerY);
var count = 0;
var increment = 3/32;
var distance = 10;
for (theta = 0; theta < 50; theta++) {
var newX = centerX + distance * Math.cos((theta) * 4 * Math.PI * increment );
var newY = centerY + distance * Math.sin(((theta)) * 4 * Math.PI * increment );
cxt.fillText(distance, newX, newY);
count++;
if (count % 4 === 0) {
distance = distance + 10;
}
}
cxt.stroke();
<canvas id="myCanvas" width="400" height="400" style="border:1px solid #c3c3c3;"></canvas>
您可以看到,前四个点的距离为10,第五个点的距离为20,从那里,您已经打破了节奏。
[假设您仍需要5个臂,请通过检查count % 5 === 0
而不是count % 4 === 0
每5个点增加距离。
var c = document.getElementById("myCanvas");
var cxt = c.getContext("2d");
var centerX = 200;
var centerY = 200;
cxt.moveTo(centerX, centerY);
var count = 0;
var increment = 3/32;
var distance = 10;
for (theta = 0; theta < 50; theta++) {
var newX = centerX + distance * Math.cos((theta) * 4 * Math.PI * increment );
var newY = centerY + distance * Math.sin(((theta)) * 4 * Math.PI * increment );
cxt.fillText(distance, newX, newY);
count++;
if (count % 5 === 0) {
distance = distance + 10;
}
}
cxt.stroke();
<canvas id="myCanvas" width="400" height="400" style="border:1px solid #c3c3c3;"></canvas>
此外,一个完整的圆圈是2 * Math.PI
。如果可以使用Math.cos((theta) * 2 * Math.PI * increment)
,则增量将成为每次绘制后点将移动的弧线。如果增量为1/5
,则将获得5条直线。如果增量比1/5
多一点,您将获得所需的曲线效果。
还有一个最后的细节,我们通常将上下文称为ctx
,而不是cxt
。结合以上所有内容,输出看起来像这样
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var centerX = 200;
var centerY = 200;
ctx.moveTo(centerX, centerY);
var count = 0;
var increment = 1.02/5;
var distance = 10;
for (theta = 0; theta < 50; theta++) {
var newX = centerX + distance * Math.cos((theta) * 2 * Math.PI * increment );
var newY = centerY + distance * Math.sin(((theta)) * 2 * Math.PI * increment );
ctx.fillText('o', newX, newY);
count++;
if (count % 5 === 0) {
distance = distance + 10;
}
}
ctx.stroke();
<canvas id="myCanvas" width="400" height="400" style="border:1px solid #c3c3c3;"></canvas>
编辑
[与提问者聊天后,我意识到问题也必须与fillText
一起使用,即使用字符串的左下角作为绘画的起点。为了解决这个问题,我们必须绘制实际的圆圈,而不是字母“ o”。
这是最终结果(添加了同心圆以显示出完美的对称性)
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var centerX = 200;
var centerY = 200;
ctx.moveTo(centerX, centerY);
var count = 0;
var increment = 1.05/5;
var distance = 10;
for (theta = 0; theta < 50; theta++) {
var newX = centerX + distance * Math.cos((theta) * 2 * Math.PI * increment );
var newY = centerY + distance * Math.sin(((theta)) * 2 * Math.PI * increment );
ctx.textAlign = "center";
//ctx.fillText('o', newX, newY); <== this will be off-center
ctx.beginPath();
ctx.strokeStyle = "#000";
ctx.arc(newX, newY, 2, 0, Math.PI * 2, true)
ctx.stroke();
count++;
if (count % 5 === 0) {
ctx.strokeStyle = "#cccccc";
ctx.beginPath();
ctx.arc(200, 200, distance, 0, Math.PI * 2, true)
ctx.stroke();
distance = distance + 10;
}
}
ctx.stroke();
<canvas id="myCanvas" width="400" height="400" style="border:1px solid #c3c3c3;"></canvas>
将代码更改为以数字形式递增后,您可以看到预期行中未生成“螺旋”。
您将需要计算出想要的螺旋臂数量,并使用Stoplimit进行计算。
也从未使用过增量值。
// var increment = 6/45;
var stoplimit = 51;
圆的周长为2 * PI * radius
。
我们可以使用它来确定要覆盖圆周上一定距离的角度步长。因此,沿曲线扫过给定距离的角度为distance / radius
(请注意,这不是直线距离,而是沿曲线的距离)
尽管您正在创建螺旋,并且角度步长的距离稍长一些(当线向外移动时,近似值足以满足人眼的需求。
因此,请按照以下步骤更改代码
increment
distance
更改为radius
maxRadius = 350
以适合画布lineLength
以设置每个点之间的近似距离,以像素为单位。theta
重命名为angle
(我们是程序员而不是数学家)radiusMin
定义最小半径(起始半径)radiusScale
定义螺旋移出的每匝像素的速率。count
,将其删除radiusScale / (Math.PI * 2)
除以,因此半径为radius = angle * (radiusScale / (Math.PI * 2)) + radiusMin;
angle += lineLength / radius;
,该距离是从圆周公式得出的(以及为什么对角度使用弧度)cxt
更改为更惯用的ctx
moveTo
移至每个圆的起点。ctx.arc
定义圆ctx.stroke()
绘制路径下面的代码。由于我只是近似于您的螺旋,因此您可以使用常数以使其适合您的需求。另请注意,对于内部螺旋线,较长的线距也不会起作用。
const ctx = myCanvas.getContext("2d");
const centerX = 400;
const centerY = 400;
const markRadius = 2; // radius of each circle mark in pixels
const maxRadius = 350; // 50 pixel boarder
const lineLength = 20; // distance between points in pixels
const radiusScale = 80; // how fast the spiral moves outward per turn
const radiusMin = 10; // start radius
var angle = 0, radius = 0;
ctx.lineWidth = 1;
ctx.strokeStye = "black";
ctx.beginPath();
while (radius < maxRadius) {
radius = angle * (radiusScale / (Math.PI * 2)) + radiusMin;
angle += lineLength / radius;
const x = centerX + radius * Math.cos(angle);
const y = centerY + radius * Math.sin(angle);
ctx.moveTo(x + markRadius, y);
ctx.arc(x, y, markRadius, 0, Math.PI * 2);
}
ctx.stroke();
<canvas id="myCanvas" width="800" height="800" style="border:1px solid #c3c3c3;"></canvas>
如果您想要单独的螺旋线,那么这是对上述内容的较小修改
armCount
中的臂数spiralRate
requestAnimationFrame(mainLoop);
const ctx = myCanvas.getContext("2d");
const centerX = 200;
const centerY = 200;
const markRadius = 2; // radius of each circle mark in pixels
const maxRadius = 190; // 50 pixel boarder
const armCount = 8; // Number of arms
const radiusScale = 8; // how fast the spiral moves outward per turn
const radiusMin = 10; // start radius
function drawSpiral(spiralRate) { // spiralRate in pixels per point per turn
var angle = 0, radius = radiusMin;
ctx.lineWidth = 1;
ctx.strokeStye = "black";
ctx.beginPath();
while (radius < maxRadius) {
angle += (Math.PI * 2) / armCount + (spiralRate/ radius);
radius = angle * (radiusScale / (Math.PI * 2)) + radiusMin;
const x = centerX + radius * Math.cos(angle);
const y = centerY + radius * Math.sin(angle);
ctx.moveTo(x + markRadius, y);
ctx.arc(x, y, markRadius, 0, Math.PI * 2);
}
ctx.stroke();
}
function mainLoop(time) {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
drawSpiral(Math.sin(time / 4000) * 2); // occilate spiral rate every ~ 24 seconds
requestAnimationFrame(mainLoop);
}
<canvas id="myCanvas" width="400" height="400" style="border:1px solid #c3c3c3;"></canvas>