Zrafi Ahmed
Zrafi Ahmed

Reputation: 7

angled direction sine wave

I have been able to draw the sin wave in horizontal direction as shows the image(image link: https://i.sstatic.net/RTpDY.png) and in the vertical direction.

now I need to draw it in an angled 45° direction could any one help me pleese!

the script code:

	var c =document.getElementById("c");
	var ctx=c.getContext('2d');
	var x=0,y=250,vx=0.05,vy=0.05,a=1;
for(var i=0; i<501;i++){
    x += a;
    y = Math.floor(500 * (0.5 - 0.15 * Math.sin(vy)));
    vy += vx;
	   // this.ctx.clearRect(0, 0, 500,500);
    this.ctx.beginPath();
    this.ctx.arc(x, y, 2, 0, Math.PI * 2, true);
    this.ctx.closePath();
    this.ctx.fillStyle = 'red';
    this.ctx.fill();
    console.log("x:"+x+"y:"+y+"vy:"+vy);
}

Upvotes: 0

Views: 524

Answers (2)

Blindman67
Blindman67

Reputation: 54041

Draw a sin wave along a line

The following will draw a sin wave aligned to a line. The line can be in any direction.

The standard settings

The wave length will be in pixels. For a sin wave to make a complete cycle you need to rotate its input angle by Math.PI * 2 so you will need to convert it to value matching pixel wavelength.

const waveLen = 400; // pixels

The phase of the sin wave is at what part of the wave it starts at, as the wave length is in pixels, the phase is also in pixels, and represents the distance along the wave that denotes the starting angle.

const phase = 200; // mid way

The amplitude of the wave is how far above and below the center line the wave max and min points are. This is again in pixels

const amplitude = 100;

A wave also has an offset, though in this case not really important I will added it as well. In pixels as well

const offset = 0;

The line that marks the center of the wave has a start and end coordinate

const x1 = 20;
const y1 = 20;
const x2 = 400;
const y2 = 400;

And some context settings

const lineWidth = 3;
const lineCap = "round";
const lineJoin = "round";
const strokeStyle = "blue";

Example code

And so to the code that does the rendering, I have expanded the code with comments so you can read what is going on. Below that is a more useable version.

const ctx = canvas.getContext("2d");
canvas.width = innerWidth;
canvas.height = innerHeight;

window.addEventListener("resize", () => {
  canvas.width = innerWidth;
  canvas.height = innerHeight;
  y2 = x2 = innerWidth; // at 45 deg
  drawSinWave();
})

const waveLen = 120; // pixels
const phase = 50; // mid way
const amplitude = 25;
const offset = 0;
const x1 = 20;
const y1 = 20;
var x2 = 400; // as vars to let it change to fit resize
var y2 = 400;



function drawSinWave() {

  ctx.lineWidth = 3;
  ctx.lineCap = "round";
  ctx.lineJoin = "round";
  ctx.strokeStyle = "blue";

  // get the vector form of the line
  const vx = x2 - x1;
  const vy = y2 - y1;

  // Get the length of the line in pixels
  const dist = Math.sqrt(vx * vx + vy * vy);

  // Make the vector one pixel long to move along the line
  const px = vx / dist;
  const py = vy / dist;

  // We also need a vector to move out from the line (at 90 deg to the ine)
  // So rotate the pixel vector 90deg CW
  const ax = -py; // a for amplitude vector
  const ay = px;


  // Begin the path
  ctx.beginPath();

  // Now loop along every pixel in the line
  // We go past the end a bit as floating point errors can cause it to end
  // a pixels too early
  for (var i = 0; i <= dist + 0.5; i++) {
    // fix i if past end
    if (i > dist) {
      i = dist
    } // Carefull dont mess with this ot it will block the page

    // Use the distance to get the current angle of the wave
    // based on the wave length and phase
    const ang = ((i + phase) / waveLen) * Math.PI * 2;

    // and at this position get sin
    const val = Math.sin(ang);

    // Scale to match the amplitude and move to offset
    // as the distance from the center of the line
    const amp = val * amplitude + offset;

    // Get line ceneter at distance i using the pixel vector
    var x = x1 + px * i;
    var y = y1 + py * i;

    // Use the amp vector to move away from the line at 90 degree
    x += ax * amp;
    y += ay * amp;

    // Now add the point 
    ctx.lineTo(x, y);
  }
  ctx.stroke();
}

drawSinWave();
canvas {
  position: absolute;
  top: 0px;
  left: 0px;
}
<canvas id=canvas width=4 00 height=4 00></canvas>

As a more useable function with a few shortcuts

const ctx = canvas.getContext("2d");
canvas.width = innerWidth;
canvas.height = innerHeight;

window.addEventListener("resize", () => {
  canvas.width = innerWidth;
  canvas.height = innerHeight;
  waveExample.y2 = waveExample.x2 = innerWidth; // at 45 deg
  drawSinWave(waveExample);
})

const waveExample = {
  waveLen: 100, // pixels
  phase: 50, // mid way
  amplitude: 35,
  offset: 0,
  x1: 20,
  y1: 20,
  x2: 400, // as vars to let it change to fit resize
  y2: 400,
  lineWidth : 5,
  lineCap : "round",
  lineJoin : "round",
  strokeStyle : "Red",
}



function drawSinWave(wave) {

  ctx.lineWidth = wave.lineWidth;
  ctx.lineCap = wave.lineCap;
  ctx.lineJoin = wave.lineJoin;
  ctx.strokeStyle = wave.strokeStyle;
  var vx = wave.x2 - wave.x1;
  var vy = wave.y2 - wave.y1;
  const dist = Math.sqrt(vx * vx + vy * vy);
  vx /= dist;
  vy /= dist;
  ctx.beginPath();
  for (var i = 0; i <= dist + 0.5; i++) {
    if (i > dist) { i = dist } 
    const pos = Math.sin(((i + wave.phase) / wave.waveLen) * Math.PI * 2) * wave.amplitude + wave.offset;
    ctx.lineTo(
      wave.x1 + vx * i - vy * pos,
      wave.y1 + vy * i + vx * pos
    );

  }
  ctx.stroke();
}


drawSinWave(waveExample);
canvas {
  position: absolute;
  top: 0px;
  left: 0px;
}
<canvas id=canvas width=4 00 height=4 00></canvas>

Upvotes: 1

James Collier
James Collier

Reputation: 157

The easiest solution is rotating the canvas:

ctx.rotate(45*Math.PI/180);  

Although I'm presuming you need the canvas orientation fixed and you need to mathematically alter the way you draw? In which case here's a whole bunch of math about how to plot sine waves at a rotated counterclockwise:

http://mathman.biz/html/rotatingsine.html

Upvotes: 0

Related Questions