What is wrong with the phase control of my sine wave code?

Viewed 61

I have created a sine wave drawing web app. Here is my code:

const canvas = document.getElementById("canvas"),
  amplitude_slider = document.getElementById("amplitude_control"),
  wavelength_slider = document.getElementById("wavelength_control"),
  phase_slider = document.getElementById("phase_control"),
  amplitude_output = document.getElementById("amplitude_value"),
  wavelength_output = document.getElementById("wavelength_value"),
  phase_output = document.getElementById("phase_value"),
  radian_factor = Math.PI / 180;

var width,
  height,
  canvas_middle,
  context,
  amplitude = 20,
  wavelength = 0,
  phase = 0;

function init() {
  width = window.innerWidth - 4; //exclude 4 pixels for the border
  height = window.innerHeight - 4;
  canvas.width = width;
  canvas.height = height / 2;
  canvas_middle = height / 4;
  context = canvas.getContext("2d");
}

function draw() {
  context.clearRect(0, 0, width, height);
  context.beginPath();
  var ampl = amplitude / 100 * canvas_middle;
  context.moveTo(0, canvas_middle + ampl * Math.sin(radian_factor * phase * Math.pow(2, wavelength)));
  for (i = 1; i < width; i++) {
    context.lineTo(i, canvas_middle + ampl * Math.sin(radian_factor * (i + phase) * Math.pow(2, wavelength)));
  }
  context.stroke();
}
init();
draw();
window.addEventListener("resize", () => {
  init();
  draw();
});

amplitude_slider.addEventListener("input", () => {
  amplitude = amplitude_slider.value;
  amplitude_output.innerHTML = amplitude;
  draw();
});
wavelength_slider.addEventListener("input", () => {
  wavelength = wavelength_slider.value;
  wavelength_output.innerHTML = Math.pow(2, wavelength).toFixed(2);
  draw();
});
phase_slider.addEventListener("input", () => {
  phase = phase_slider.value;
  phase_output.innerHTML = phase + "&deg; (" + (radian_factor * phase).toFixed(3) + "rad)";
  draw();
});
* {
  box-sizing: border-box;
}

html,
body {
  height: 100%;
  padding: 0;
  margin: 0;
}

canvas {
  border: 2px solid green;
  width: 100%;
  height: 50%;
}

input {
  width: 100%;
  margin-top: 2em;
  padding: 0 10px 0 10px;
}
<canvas id="canvas"></canvas>
<input type="range" id="amplitude_control" value="20" min="0" max="100" step="0.1"> Amplitude <span id="amplitude_value">20</span><br>
<input type="range" id="wavelength_control" value="0" min="-5" max="5" step="0.01"> Wavelength <span id="wavelength_value">4.00</span><br>
<input type="range" id="phase_control" value="0" min="0" max="360" step="0.1"> Phase <span id="phase_value">0&deg; (0.000 rad)</span>

The Amplitude control and Wavelength control works fine, but the Phase control. I want it to be like this:
enter image description here Phase 180 degree
enter image description here Phase 90 degree

But, it is behaving very weirdly, you can see it for yourself by using the Phase slider. What mistake have I done?

1 Answers

With the help of Temmu's comment, I was able to solve my problem. In my code, the problem was that the phase_slider.value was returning a value of string type. Using that string type value for calculations was causing the problem.

I just needed to convert the phase_slider.value to a number by using parseInt() method or by putting a + sign before the variable.

Here is the corrected version of my code:

const canvas = document.getElementById("canvas"),
  amplitude_slider = document.getElementById("amplitude_control"),
  wavelength_slider = document.getElementById("wavelength_control"),
  phase_slider = document.getElementById("phase_control"),
  amplitude_output = document.getElementById("amplitude_value"),
  wavelength_output = document.getElementById("wavelength_value"),
  phase_output = document.getElementById("phase_value"),
  radian_factor = Math.PI / 180;

var width,
  height,
  canvas_middle,
  context,
  amplitude = 20,
  wavelength = 0,
  phase = 0;

function init() {
  width = window.innerWidth - 4; //exclude 4 pixels for the border
  height = window.innerHeight - 4;
  canvas.width = width;
  canvas.height = height / 2;
  canvas_middle = height / 4;
  context = canvas.getContext("2d");
}

function draw() {
  context.clearRect(0, 0, width, height);
  context.beginPath();
  var ampl = amplitude / 100 * canvas_middle;
  context.moveTo(0, canvas_middle + ampl * Math.sin(radian_factor * phase * Math.pow(2, wavelength)));
  for (i = 1; i < width; i++) {
    context.lineTo(i, canvas_middle + ampl * Math.sin(radian_factor * (i + phase) * Math.pow(2, wavelength)));
  }
  context.stroke();
}
init();
draw();
window.addEventListener("resize", () => {
  init();
  draw();
});

amplitude_slider.addEventListener("input", () => {
  amplitude = amplitude_slider.value;
  amplitude_output.innerHTML = amplitude;
  draw();
});
wavelength_slider.addEventListener("input", () => {
  wavelength = wavelength_slider.value;
  wavelength_output.innerHTML = Math.pow(2, wavelength).toFixed(2);
  draw();
});
phase_slider.addEventListener("input", () => {
  phase = parseInt(phase_slider.value); //This is the corrected line
  phase_output.innerHTML = phase + "&deg; (" + (radian_factor * phase).toFixed(3) + "rad)";
  draw();
});
* {
  box-sizing: border-box;
}

html,
body {
  height: 100%;
  padding: 0;
  margin: 0;
}

canvas {
  border: 2px solid green;
  width: 100%;
  height: 50%;
}

input {
  width: 100%;
  margin-top: 2em;
  padding: 0 10px 0 10px;
}
<canvas id="canvas"></canvas>
<input type="range" id="amplitude_control" value="20" min="0" max="100" step="0.1"> Amplitude <span id="amplitude_value">20</span><br>
<input type="range" id="wavelength_control" value="0" min="-5" max="5" step="0.01"> Wavelength <span id="wavelength_value">4.00</span><br>
<input type="range" id="phase_control" value="0" min="0" max="360" step="0.1"> Phase <span id="phase_value">0&deg; (0.000 rad)</span>

Related