В документе может быть только один id со значением output.
Можно попробовать поменять на класс и getElementsByClassName. Проблема в том, что getElementsByClassName работает с массивами и тут нельзя вызвать getContext напрямую, нужна обёртка forEach.
<div id="wrap">
<canvas class="output"></canvas>
<canvas class="output"></canvas>
<canvas class="output"></canvas>
<canvas class="output"></canvas>
</div>
Вот как-то так...
var img = document.getElementById('input');
var c = document.getElementsByClassName('output');
c = Array.prototype.slice.call(c);
c.forEach(function (c) {
var ctx = c.getContext('2d');
c.width = img.width;
c.height = img.height;
var tic, sine, sineNormalized,
start = Date.now();
var params = {
AMP: 20,
FREQ: 0.03,
SPEED: 4,
VERTICAL: true
};
function update() {
tic = (Date.now() - start) * 0.001;
}
function render() {
ctx.clearRect(0, 0, c.width, c.height);
for(var i = 0; i < img.height; i++) {
if(params.VERTICAL) {
var ofs = params.AMP * (0.5 + (Math.sin(tic * params.SPEED + (i * params.FREQ)) * 0.5));
ctx.drawImage(img,
0, i, img.width, 1,
0, i - (ofs * 0.5), img.width, 1 + ofs);
} else {
var ofs = params.AMP * Math.sin(tic * params.SPEED + (i * params.FREQ));
ctx.drawImage(img,
0, i, img.width, 1,
0 + ofs, i, img.width, 1);
}
}
}
function loop() {
requestAnimationFrame(loop);
update();
render();
}
$('nav input').on('input change', function() {
var t = $(this).attr('data-param');
if(t == 'VERTICAL') {
params.VERTICAL = $(this).is(':checked');
} else {
params[t] = $(this).val();
}
});
loop();
});