javascripthtml5-canvassine-wave

Animate sine wave, fixed start and end points


I have a sine wave in my canvas that is animated, swaying left and right. What I am trying to achieve is that the start and end points stay fixed. How to achieve that?

Here is the Code Pen

function start() {
  var canvas = document.getElementById("canvas");
  var context = canvas.getContext("2d");
  context.clearRect(0, 0, canvas.width, canvas.height);
  drawCurves(context, step);

  step += 5;
  window.requestAnimationFrame(start);
}

var step = -4;

function drawCurves(ctx, step) {
  var width = ctx.canvas.width;
  var height = ctx.canvas.height;
  ctx.beginPath();
  ctx.lineWidth = 2;
  ctx.strokeStyle = "rgb(66,44,255)";

  var x = 4;
  var y = 0;
  var amplitude = 20;
  var frequency = 90;
  while (y < height) {
    x = width / 2 + amplitude * Math.sin((y + step) / frequency);
    ctx.lineTo(x, y);
    y++;
  }
  ctx.stroke();
}
canvas {
  background-color: wheat;
}
<!DOCTYPE html>
<html>

<head>
</head>

<body onload="start()">

  <canvas id="canvas" width="500" height="2000"></canvas>

</body>

</html>


Solution

  • I've changed the size of your canvas because I wanted to be able to see it. You can change it back to what you need.

    I've done 2 things:

    1. The frequency has to be var frequency = height / (2 * Math.PI); or var frequency = height / (4 * Math.PI);. The divider has to be a multiple of 2 * Math.PI

    2. I translate the context the opposite direction the same amount: ctx.translate(-amplitude * Math.sin(step / frequency), 0);

    If you need a more subtile oscillation play with the amplitude.

    In my code there is a commented out ctx.closePath() Please uncomment this line to see clearly that the sine-wave stay fixed in the center. I hope this is what you were asking.

    var canvas = document.getElementById("canvas");
    var context = canvas.getContext("2d");
    
    
    function start() {
    
      context.clearRect(0, 0, canvas.width, canvas.height);
      drawCurves(context, step);
    
      step += 5;
      window.requestAnimationFrame(start);
    }
    
    var step = -4;
    
    function drawCurves(ctx, step) {
      var width = ctx.canvas.width;
      var height = ctx.canvas.height;
      ctx.beginPath();
      ctx.lineWidth = 2;
      ctx.strokeStyle = "rgb(66,44,255)";
    
      var x = 0;
      var y = 0;
      var amplitude = 10;
      var frequency = height / (2 * Math.PI);
      ctx.save();
      ctx.translate(-amplitude * Math.sin(step / frequency), 0);
      while (y < height) {
        x = width / 2 + amplitude * Math.sin((y + step) / frequency);
        ctx.lineTo(x, y);
        y++;
      }
      //ctx.closePath();
      ctx.stroke();
      ctx.restore();
    }
    
    start();
    canvas {
      background-color: wheat;
    }
    
    div {
      width: 100px;
      height: 400px;
      border: solid;
    }
    <div class="box">
    <canvas id="canvas" width="100" height="400"></canvas>
    </div>

    UPDATE

    In the case you need to use several curves you can do it like this:

    I'm putting all the functionality for drawing the wave in a function drawWave that takes the amplitude and the trigonometric function to be used (sin or cos) as arguments:

    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext("2d");
    var width = ctx.canvas.width;
    var height = ctx.canvas.height;
    var step = -4;
    
    function start() {
      window.requestAnimationFrame(start);
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      
      drawWave(10,"sin");
      drawWave(10,"cos");
      drawWave(5,"sin");
      
      step += 5; 
    }
    
    
      
    function drawWave(amplitude,trig){
      // trig is the trigonometric function to be used: sin or cos
      ctx.beginPath();
      ctx.lineWidth = 2;
      ctx.strokeStyle = "rgb(66,44,255)";
    
      var x = 0;
      var y = 0;
      //var amplitude = 10;
      var frequency = height / (2 * Math.PI);
      ctx.save();
      ctx.translate(-amplitude * Math[trig](step / frequency), 0);
      while (y < height) {
        x = width / 2 + amplitude * Math[trig]((y + step) / frequency);
        ctx.lineTo(x, y);
        y++;
      }
    
      ctx.stroke();
      ctx.restore();
    }
    
    start();
    canvas {
      background-color: wheat;
    }
    
    div {
      width: 100px;
      height: 400px;
      border: solid;
    }
    <div class="box">
    <canvas id="canvas" width="100" height="400"></canvas>
    </div>