Skip to content

Instantly share code, notes, and snippets.

@gkhays
Last active March 9, 2024 19:05
Show Gist options
  • Save gkhays/e264009c0832c73d5345847e673a64ab to your computer and use it in GitHub Desktop.
Save gkhays/e264009c0832c73d5345847e673a64ab to your computer and use it in GitHub Desktop.
Oscillating sine wave, including the steps to figuring out how to plot a sine wave

Draw a Sine Wave in JavaScript

To Do

I am revisiting the Fourier transform so I thought it might be nice to come up with some visualizations. My first stop was to plot a sine wave in JavaScript, then to animate it. I am using the window.requestAnimationFrame() method. I've documented the steps in reverse order.

Simple Animation

The end result is an oscillating sine wave. Nothing ground-breaking but it looks pretty cool to me.

Animated Sine Wave

The JavaScript function to plot the sine wave uses the Math.sin() function, which is called repeatedly given a different starting point on the y-axis. See the simple plot below. In this case, the draw() function makes the repeat calls via window.requestAnimationFrame(draw).

function draw() {
    var canvas = document.getElementById("canvas");
    var context = canvas.getContext("2d");

    context.clearRect(0, 0, 500, 500);
    showAxes(context);
    context.save();            
    
    plotSine(context, step, 50);
    context.restore();
    
    step += 4;
    window.requestAnimationFrame(draw);
}

Note: The astute observer may observe the animation above isn't actually JavaScript but is instead an animated gif. I did this since it is currently not possible to run JavaScript from a gist although it is possible using bl.ocks.org.

Superimposed Sine Waves

After I learned to plot a sine wave, I visualized how to draw multiple sine waves in order to achieve the oscillation effect in the animation. It looked pretty cool, so I kept it around. It reminds me of Spirograph. 😄

Superimposed

The step advances the starting point along the y-axis.

var step = 4;
for (var i = -4; i < canvas.height; i += step) {
    plotSine(context, i, 54 + i);
}

Simple Plot

My initial attempt to draw a sine wave on an HTML5 canvas.

Sine Wave

<body onload="init()">
    <h3>Oscillating Sine Wave</h3>
    <canvas id="canvas" width="500" height="100"></canvas>
</body>
function plotSine(ctx) {
    var width = ctx.canvas.width;
    var height = ctx.canvas.height;
    var scale = 20;

    ctx.beginPath();
    ctx.lineWidth = 2;
    ctx.strokeStyle = "rgb(66,44,255)";
    
    var x = 0;
    var y = 0;
    var amplitude = 40;
    var frequency = 20;
    //ctx.moveTo(x, y);
    while (x < width) {
        y = height/2 + amplitude * Math.sin(x/frequency);
        ctx.lineTo(x, y);
        x = x + 1;
    }
    ctx.stroke();
}

Interesting tidbit: If we uncomment ctx.moveTo(x, y) just before the loop we get a vertical line.

References

I found this animated gif in Reddit.

Trigonometry

See This should be the first thing shown in any Trigonometry class.

From the Fourier series definition in Wikipedia.

Approximation of a square wave.

<!DOCTYPE html>
<html>
<head>
<title>Sine Wave</title>
<script type="text/javascript">
function showAxes(ctx,axes) {
var width = ctx.canvas.width;
var height = ctx.canvas.height;
var xMin = 0;
ctx.beginPath();
ctx.strokeStyle = "rgb(128,128,128)";
// X-Axis
ctx.moveTo(xMin, height/2);
ctx.lineTo(width, height/2);
// Y-Axis
ctx.moveTo(width/2, 0);
ctx.lineTo(width/2, height);
// Starting line
ctx.moveTo(0, 0);
ctx.lineTo(0, height);
ctx.stroke();
}
function drawPoint(ctx, y) {
var radius = 3;
ctx.beginPath();
// Hold x constant at 4 so the point only moves up and down.
ctx.arc(4, y, radius, 0, 2 * Math.PI, false);
ctx.fillStyle = 'red';
ctx.fill();
ctx.lineWidth = 1;
ctx.stroke();
}
function plotSine(ctx, xOffset, yOffset) {
var width = ctx.canvas.width;
var height = ctx.canvas.height;
var scale = 20;
ctx.beginPath();
ctx.lineWidth = 2;
ctx.strokeStyle = "rgb(66,44,255)";
// console.log("Drawing point...");
// drawPoint(ctx, yOffset+step);
var x = 4;
var y = 0;
var amplitude = 40;
var frequency = 20;
//ctx.moveTo(x, y);
ctx.moveTo(x, 50);
while (x < width) {
y = height/2 + amplitude * Math.sin((x+xOffset)/frequency);
ctx.lineTo(x, y);
x++;
// console.log("x="+x+" y="+y);
}
ctx.stroke();
ctx.save();
console.log("Drawing point at y=" + y);
drawPoint(ctx, y);
ctx.stroke();
ctx.restore();
}
function draw() {
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
context.clearRect(0, 0, 500, 500);
showAxes(context);
context.save();
plotSine(context, step, 50);
context.restore();
step += 4;
window.requestAnimationFrame(draw);
}
function spirograph() {
var canvas2 = document.getElementById("canvas2");
var context = canvas2.getContext("2d");
showAxes(context);
context.save();
// var imageData = context.getImageData(0, 0, canvas.width, canvas.height);
var step = 4;
for (var i = -4; i < canvas.height; i += step) {
// context.putImageData(imageData, 0, 0);
plotSine(context, i, 54 + i);
}
}
function init() {
window.requestAnimationFrame(draw);
spirograph();
}
var step = -4;
</script>
</head>
<body onload="init()">
<h3>Oscillating Sine Wave</h3>
<canvas id="canvas" width="500" height="100"></canvas>
<p/>
<h3>Multiple Sine Waves</h3>
<canvas id="canvas2" width="500" height="100"/>
</body>
</html>
@vincent64
Copy link

vincent64 commented May 30, 2018

Very nice and interesting !

Just a question, how can I make this with Hz mesure ?

@cmsnerd
Copy link

cmsnerd commented Aug 29, 2018

Hi,how can i make trig-aha.gif works with pure js on canvas? Here is the very similar jsfiddle:
https://jsfiddle.net/2L4ubgpx/85/

@kamyfakhr
Copy link

Hi,
Amazing job!
I just wonder how we can make it interactive? Like touching the waves by hand and set the frequency?
Thanks,

@Sanjeev-kumaar008
Copy link

it is not working for high order frequencies ...how can i tackle that problem ??

@sbezugliy
Copy link

Greate! Nice applied representation of Fourier series.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment