var ctx = document.querySelector("canvas").getContext("2d"),
rng = document.querySelector("input"),
val = document.querySelector("span"),
data = [], scale = 30;
// generate sinus wave with noise jitters
for(var i = 0; i < ctx.canvas.width; i += 2)
data.push(Math.sin(i*0.1) * Math.random() + Math.random())
// draw initial smoothed curve (length=1, no smoothing)
drawWMA();
// calculate moving average
function drawWMA() {
var len = +rng.value, // get smoothing length (number of previous points)
dataa = [], datab = [], // pass A and B arrays
weight = 0; // calc weight based on length
val.innerHTML = len;
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.beginPath();
// calc weight
for(var i = 1; i <= len; i++) weight += i; // add range together [1, length]
// plot original data at top of canvas
plot(data, 30);
// PASS 1: Calc new smoothed array
dataa = calcWMA(data, len, weight);
// plot smoothed curve
ctx.fillText("FIRST PASS:", 0, 100);
plot(dataa, 120);
// PASS 2 (optional)
datab = calcWMA(dataa, len, weight);
ctx.fillText("SECOND PASS:", 0, 190);
plot(datab, 210);
ctx.stroke(); // render plots
}
function calcWMA(data, len, weight) {
var i, t, datao = [];
// calc new smoothed array
for(i = 0; i < data.length; i++) { // iterate from length to end of data
var v = 0; // calc average value for this position
for(t = 0; t < len; t++) { // [1, len]
if (i-t >= 0)
v += data[i-t] * ((t+1) / weight); // weight previous values based on -delta
}
datao.push(v); // store new value
}
return datao
}
function plot(data, y) {
ctx.moveTo(0, y + data[0]*scale);
for(i = 1; i < data.length; i++) ctx.lineTo(i * 2, y + data[i]*scale);
}
rng.onchange = rng.oninput = drawWMA;
<label>Points to consider: <input type="range" min=1 max=50 value=1></label><span>1</span><br>
<canvas width=600 height=300></canvas>