WaveGrapher

by Santiago J

HTML

<canvas id="stage"></canvas>

CSS

#stage {
    background-color: #eee;
}

JavaScript

var W = 720, H = 720;
var canvas = document.querySelector("#stage");
canvas.width = W;
canvas.height = H;
var ctx = canvas.getContext("2d");

var Wave = (function() {

    var Wave = function(freqs, amps) {
        this.freqs = freqs;
        this.amps = amps;

        this.w = this.h = 1;
        this.backCanvas = document.createElement("canvas");
        this.bctx = this.backCanvas.getContext("2d");
        this.backOffset = 0;
        
        // Normalize amplitudes
        var sumAmps = 0;
        for (var i = 0; i < amps.length; i++) {
            sumAmps += amps[i];
        }
        for (var i = 0; i < amps.length; i++) {
            amps[i] /= sumAmps;
        }
    };
    
    Wave.prototype.setBox = function(w, h) {
        this.w = w;
        this.h = h;
        this.backCanvas.width = 2*w;
        this.backCanvas.height = h;
        this.backDraw(this.backOffset);
    };
    
    Wave.prototype.backDraw = function(offset) {
    
        var ctx = this.bctx;
        var amp = this.h / 2;
        var yc = amp;
        var radPerPx = 2 * Math.PI / this.w;
        var freqs = this.freqs;
        var amps = this.amps;
        var n = Math.min(freqs.length, amps.length);
        var xEnd = 2 * this.w;
        
        this.backOffset = offset;
        
        ctx.clearRect(0, 0, xEnd, this.h);
        ctx.beginPath();
        for (var i = 0; i <= xEnd; i++) {

            var val = 0;
            for (var j = 0; j < n; j++) {
                val += amps[j] * Math.sin((i+offset) * freqs[j] * radPerPx);
            }
            ctx.lineTo(i, yc - amp * val);
        }
        ctx.stroke();
    };
    
    Wave.prototype.quickDraw = function(ctx, x, y, w, h, offset) {
        if (offset < this.backOffset || offset > this.backOffset + this.w) {
            this.backDraw(offset);
        }
        ctx.drawImage(this.backCanvas,
            offset - this.backOffset, 0, this.w, this.h,
            x, y, w, h);
    };
    
    Wave.prototype.drawInBox =...