使用JavaScript在HTML画布上绘制螺旋形图案。

31

我搜索了一下,没有找到如何使用JavaScript在canvas中画出螺旋形的具体方法。

我认为可能可以使用bezier曲线实现,如果这种方式不行,就只能使用lineTo()了,但那看起来更加困难。

此外,如果要这样做,我想必须要使用三角函数和极坐标图形,而这已经有一段时间没碰过了。如果是这种情况,您能否指导我一下这方面的数学知识。


什么样的螺旋?:http://zh.wikipedia.org/wiki/螺旋 - Mitch Wheat
你有特定类型的螺旋想法吗? - Gabe
我在考虑像阿基米德螺旋那样的东西。最好能够调整一些参数以获得不同螺旋的范围。 - qw3n
6个回答

55

阿基米德螺线表达式为r=a+b(angle)。将其转换为x、y坐标,可表示为x=(a+b*angle)*cos(angle)y=(a+b*angle)*sin(angle)。接下来你可以在for循环中使用角度,并像这样执行:

for (i=0; i< 720; i++) {
  angle = 0.1 * i;
  x=(1+angle)*Math.cos(angle);
  y=(1+angle)*Math.sin(angle);
  context.lineTo(x, y);
}

注意上面的内容假设a = 1且b = 1。

这里是一个jsfiddle链接: http://jsfiddle.net/jingshaochen/xJc7M/


3
如果想要得到螺旋图案,需要将增量设置为类似于 i+=.1 的值,否则它看起来像是多边形。 - qw3n
1
在这个fiddle http://jsfiddle.net/pTymD/中进行轻微变化,使用可变角度增量来控制速度:`var incr = angle ? 1/(a + b*angle) : 0.1;`。这样可以避免在低角度处过采样,在高角度处欠采样,从而实现1像素线长的目标。 - Phil H
你能展示一下修改后的 jsfiddle 吗?我无法实现你的建议。 - geoidesic
抱歉,我之前的评论是针对@Phil H.的。 - geoidesic
显示剩余5条评论

4

这是一个稍作改动、转变成javascript的Java螺旋图,我曾经从这里借鉴。

它使用lineTo()函数,不是很难。

<!DOCTYPE HTML>
<html><body>
<canvas id="myCanvas" width="300" height="300" style="border:1px solid #c3c3c3;"></canvas>
<script type="text/javascript">
    var c=document.getElementById("myCanvas");
    var cxt=c.getContext("2d");
    var centerX = 150;
    var centerY = 150;
    cxt.moveTo(centerX, centerY);

    var STEPS_PER_ROTATION = 60;
    var increment = 2*Math.PI/STEPS_PER_ROTATION;       
    var theta = increment;

    while( theta < 40*Math.PI) {
      var newX = centerX + theta * Math.cos(theta); 
      var newY = centerY + theta * Math.sin(theta); 
      cxt.lineTo(newX, newY);
      theta = theta + increment;
    }
    cxt.stroke();
</script></body></html>

4
这是我写的一个用于绘制阿基米德螺线的函数:

阿基米德螺线是一种数学曲线。

CanvasRenderingContext2D.prototype.drawArchimedeanSpiral =
    CanvasRenderingContext2D.prototype.drawArchimedeanSpiral ||
        function(centerX, centerY, stepCount, loopCount,
                 innerDistance, loopSpacing, rotation)
        {
            this.beginPath();

            var stepSize = 2 * Math.PI / stepCount,
                endAngle = 2 * Math.PI * loopCount,
                finished = false;

            for (var angle = 0; !finished; angle += stepSize) {
                // Ensure that the spiral finishes at the correct place,
                // avoiding any drift introduced by cumulative errors from
                // repeatedly adding floating point numbers.
                if (angle > endAngle) {
                    angle = endAngle;
                    finished = true;
                }

                var scalar = innerDistance + loopSpacing * angle,
                    rotatedAngle = angle + rotation,
                    x = centerX + scalar * Math.cos(rotatedAngle),
                    y = centerY + scalar * Math.sin(rotatedAngle);

                this.lineTo(x, y);
            }

            this.stroke();
        }

1

如果你有Illustrator,那么有一个非常好用的免费工具可以帮助你,它就是ai2canvas

它可以为你创建所有曲线的JavaScript和HTML画布标签!

(如果你正在寻找阿基米德螺旋线,那么你首先需要从CorelDRAW中获取它并将其复制到Illustrator中,因为默认的螺旋线工具会随着每个点而扩大角度。)


1
这是使用以下函数绘制螺旋线的示例:
spiral(ctx, {
  start: {//starting point of spiral
    x: 200, 
    y: 200
  },
  angle: 30 * (Math.PI / 180), //angle from starting point
  direction: false,
  radius: 100, //radius from starting point in direction of angle
  number: 3 // number of circles
});

螺旋绘图代码:

spiral = function(ctx,obj) {
  var center, eAngle, increment, newX, newY, progress, sAngle, tempTheta, theta;
  sAngle = Math.PI + obj.angle;
  eAngle = sAngle + Math.PI * 2 * obj.number;
  center = {
    x: obj.start.x + Math.cos(obj.angle) * obj.radius,
    y: obj.start.y + Math.sin(obj.angle) * obj.radius
  };
  increment = 2 * Math.PI / 60/*steps per rotation*/;
  theta = sAngle;
  ctx.beginPath();
  ctx.moveTo(center.x, center.y);
  while (theta <= eAngle + increment) {
    progress = (theta - sAngle) / (eAngle - sAngle);
    tempTheta = obj.direction ? theta : -1 * (theta - 2 * obj.angle);
    newX = obj.radius * Math.cos(tempTheta) * progress;
    newY = obj.radius * Math.sin(tempTheta) * progress;
    theta += increment;
    ctx.lineTo(center.x + newX, center.y + newY);
  }
  ctx.stroke();
};

0
以下代码将螺旋近似为一组四分之一圆,每个圆的半径略大。对于小转向数,它可能看起来比阿基米德螺旋更糟糕,但它应该运行得更快。
function drawSpiral(ctx, centerx, centery, innerRadius, outerRadius, turns=2, startAngle=0){
    ctx.save();
    ctx.translate(centerx, centery);
    ctx.rotate(startAngle);
    let r = innerRadius;
    let turns_ = Math.floor(turns*4)/4;
    let dr = (outerRadius - innerRadius)/turns_/4;
    let cx = 0, cy = 0; 
    let directionx = 0, directiony = -1;
    
    ctx.beginPath();
    let angle=0;
    for(; angle < turns_*2*Math.PI; angle += Math.PI/2){
        //draw a quarter arc around the center point (x, cy)
        ctx.arc( cx, cy, r, angle, angle + Math.PI/2);
        
        //move the center point and increase the radius so we can draw a bigger arc
        cx += directionx*dr;
        cy += directiony*dr;
        r+= dr;
        
        //rotate direction vector by 90 degrees
        [directionx, directiony] = [ - directiony, directionx ];
    }
    //draw the remainder of the last quarter turn
    ctx.arc( cx, cy, r, angle, angle + 2*Math.PI*( turns - turns_ ))
    ctx.stroke();
    ctx.restore();
}

结果:

enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接