title: How to draw a curved spring in a HTML5 Canvas?
body: <p>I would like to draw a spring in a HTML5 canvas, and show if that spring is at its rest length or not.
  My spring is attached to a rectangular shape to some X-Y coordinates and defined as follows:</p>
  
  <pre><code>function Spring(restLenght, width, numRounds){
    this.x1 = 0;
    this.y1 = 0;
    this.x2 = 0;
    this.y2 = 0;
    this.restLenght = restLenght;
    this.width = width;
    this.numRounds = numRounds;
    this.color = "green";
    this.lineWidth = 6;
  }
  </code></pre>
  
  <p>The parameters are explained in the picture below:</p>
  
  <p><a href="https://i.stack.imgur.com/usT1k.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/usT1k.png" alt="enter image description here"></a></p>
  
  <p>When the spring is at its rest length, the lines shall be parallel to each other, otherwise this means the spring is stretched or compressed. Then it will be immediately clear what state the spring is.</p>
  
  <p>I'm stuck now with the bezierCurveTo() Method:</p>
  
  <p>Here is my Fiddle: <a href="https://jsfiddle.net/df3mm8kz/1/" rel="nofollow noreferrer">https://jsfiddle.net/df3mm8kz/1/</a></p>
  
  <p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
  <div class="snippet-code">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>var cv = document.getElementById('cv'),
    ctx = cv.getContext('2d'),
    mouse = capture(cv),
    box = new Box(120, 80, 0, 16),
    spring = new Spring(160, 20, 2, 0.03, 0.9),
    vx = 0,
    vy = 0;
  function Spring(restLenght, width, numRounds, k, f){
   this.x1 = 0;
    this.y1 = 0;
    this.x2 = 0;
    this.y2 = 0;
    this.restLenght = restLenght;
    this.width = width;
    this.numRounds = numRounds;
    this.k = k;
    this.f = f;
    this.color = "green";
    this.lineWidth = 6;
  }
  
  Spring.prototype.draw = function(ctx) {
   var sPX, sPY, cP1X, cP1Y, cP2X, cP2Y, ePX, ePY;
    ctx.save();
    ctx.translate(this.x, this.y);
    ctx.rotate(this.rotation);
    ctx.lineWidth = this.lineWidth;
    ctx.strokeStyle = this.color;
    ctx.fillStyle = this.color;
    ctx.beginPath();
    ctx.moveTo(this.x1, this.y1);
    // length of one spring's round
    var l = this.restLenght/(this.numRounds + 2);
    // Initial segment, from spring anchor point to the first round
    sPX = this.x1+l; sPY = this.y2;
    ctx.lineTo(sPX, sPY);
    // half width of spring's rounds
    var hw = 0.5*this.width;
    // half length of one spring's round
    var hl = 0.5*l;
    for(var i=0, n=this.numRounds; i&lt;n; i++) {
     cP1X = sPX + hl*i; cP1Y = sPY + hw;
      cP2X = sPX + l*i; cp2Y = sPY + hw;
      ePX = sPX + l*i; ePY = sPY;
     ctx.bezierCurveTo(cP1X,cP1Y,cP2X,cp2Y,ePX,ePY);
     cP1X = sPX + hl*i; cP1Y = sPY - hw;
      cP2X = sPX + l*i; cp2Y = sPY - hw;
      ePX = sPX + l*i; ePY = sPY;
     ctx.bezierCurveTo(cP1X,cP1Y,cP2X,cp2Y,ePX,ePY);
    }
    // Final segment, from last springs round to the center of mass
    ctx.lineTo(this.x2, this.y2);
    ctx.closePath();
    ctx.fill();
    ctx.stroke();
    ctx.restore();
  };
  
  function Box(w, h, mx, my) {
    this.x = 0;
    this.y = 0;
    this.w = w;
    this.h = h;
    this.mx = mx;
    this.my = my;
    this.vx = 0;
    this.vy = 0;
    this.rotation = 0;
    this.color = "red";
    this.lineWidth = 1;
  }
  
  Box.prototype.draw = function(ctx) {
    ctx.save();
    ctx.translate(this.x, this.y);
    ctx.rotate(this.rotation);
    ctx.lineWidth = this.lineWidth;
    ctx.strokeStyle = "black";
    ctx.fillStyle = this.color;
    ctx.beginPath();
    ctx.rect(-0.5*this.w, -0.5*this.h, this.w, this.h);
    ctx.closePath();
    ctx.fill();
    ctx.stroke();
    ctx.beginPath();
    ctx.strokeStyle = "yellow";
    ctx.fillStyle = "yellow";
    ctx.arc(this.mx, 0.5*this.h-this.my, 6, 0, 2 * Math.PI, false);
    ctx.stroke();
    ctx.closePath();
    ctx.fill();
    ctx.restore();
  };
  
  window.requestAnimFrame = (
    function(callback) {
      return window.setTimeout(callback, 1000/30);
    });
  
  (function drawFrame() {
    window.requestAnimFrame(drawFrame, cv);
    ctx.clearRect(0, 0, cv.width, cv.height);
  
    var dx = box.x - mouse.x,
      dy = box.y - mouse.y,
      angle = Math.atan2(dy, dx),
      boxAngle = angle + 0.5*Math.PI,
      targetX = mouse.x + Math.cos(angle) * spring.restLenght,
      targetY = mouse.y + Math.sin(angle) * spring.restLenght;
     
    vx += (targetX - box.x) * spring.k;
    vy += (targetY - box.y) * spring.k;
    vx *= spring.f;
    vy *= spring.f;
    box.rotation = boxAngle;
    box.x += vx;
    box.y += vy;
    box.draw(ctx);
    spring.x1 = mouse.x;
    spring.y1 = mouse.y;
    spring.x2 = box.x;
    spring.y2 = box.y;
    spring.draw(ctx);
  }());
  
  
  function capture(element) {
    var mouse = {
        x: 0,
        y: 0,
        event: null
      },
      body_scrollLeft = document.body.scrollLeft,
      element_scrollLeft = document.documentElement.scrollLeft,
      body_scrollTop = document.body.scrollTop,
      element_scrollTop = document.documentElement.scrollTop,
      offsetLeft = element.offsetLeft,
      offsetTop = element.offsetTop;
  
    element.addEventListener('mousemove', function(event) {
      var x, y;
      if (event.pageX || event.pageY) {
        x = event.pageX;
        y = event.pageY;
      } else {
        x = event.clientX + body_scrollLeft + element_scrollLeft;
        y = event.clientY + body_scrollTop + element_scrollTop;
      }
      x -= offsetLeft;
      y -= offsetTop;
      mouse.x = x;
      mouse.y = y;
      mouse.event = event;
    }, false);
  
    return mouse;
  }</code></pre>
  <pre class="snippet-code-html lang-html prettyprint-override"><code>&lt;canvas id="cv" width="600" height="400"&gt;&lt;/canvas&gt;</code></pre>
  </div>
  </div>
  </p>