【问题标题】:Drawing a spiral on an HTML canvas using JavaScript使用 JavaScript 在 HTML 画布上绘制螺旋
【发布时间】:2011-10-13 01:20:02
【问题描述】:

我已经搜索并没有找到关于如何使用 JavaScript 在画布中绘制螺旋的任何内容。

我认为使用贝塞尔曲线可以做到这一点,如果这不起作用,请使用lineTo(),但这似乎要困难得多。

另外,要做到这一点,我猜我必须使用三角学和极坐标绘图,而且我已经有一段时间没有这样做了。如果是这样的话,你能指出我在数学上的正确方向吗?

【问题讨论】:

  • 什么样的螺旋?:en.wikipedia.org/wiki/Spiral
  • 你有什么特别的螺旋吗?
  • 我在想类似阿基米德螺旋的东西。最好我可以调整一些参数以获得一系列不同的螺旋。

标签: javascript html math canvas


【解决方案1】:

如果你有插画师,有一个很好的免费工具会有所帮助 ai2canvas

它将为您在 html canvas 标签中创建所有的 javascript 曲线!

(如果您正在寻找 archmedes 螺旋,那么您首先必须从 coreldraw 获取它并将其复制到 illustrator,因为默认的螺旋工具会扩大每个点的角度)

【讨论】:

    【解决方案2】:

    阿基米德螺线表示为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/

    【讨论】:

    • 这行得通,除了要获得螺旋,您需要将增量设置为i+=.1 之类的东西,它看起来像多边形。
    • 这把小提琴jsfiddle.net/pTymD 的轻微变化与速度的可变角度增量:var incr = angle ? 1/(a + b*angle) : 0.1;。这通过瞄准 1px 线长避免了低角度的过采样和高角度的欠采样。
    • 你能展示一个修改过的jsfiddle吗?我无法执行您的建议。
    • @geoidesic 你的意思是什么修改?
    • 抱歉,我的评论是@Phil H.
    【解决方案3】:

    这是我曾经从 here 借来的 Java 螺旋的略微改动的 javascript 化版本

    它使用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】:

      这是我为绘图Archimedean spirals写的一个函数:

      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();
              }
      

      【讨论】:

        【解决方案5】:

        这是使用以下函数绘制螺旋的示例:

        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();
        };
        

        【讨论】:

          【解决方案6】:

          以下代码将螺旋近似为四分之一圆的集合,每个圆的半径稍大。对于小转数,它可能看起来比阿基米德螺旋线更糟糕,但它应该运行得更快。

          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();
          }
          

          结果:

          【讨论】:

            猜你喜欢
            • 2013-03-08
            • 2023-03-28
            • 1970-01-01
            • 1970-01-01
            • 2015-11-03
            • 1970-01-01
            • 2019-11-20
            • 2018-06-02
            • 1970-01-01
            相关资源
            最近更新 更多