(function(){function o(){g.clearRect(0,0,a,a);var b=g.createRadialGradient(0,0,0,0,0,a),c=[e(i),e(i),e(i)];b.addColorStop(0,"rgb("+c.join(",")+")");c=[e(i),e(i),e(i)];b.addColorStop(1,"rgb("+c.join(",")+")");g.fillStyle=b;g.fillRect(0,0,a,a);l=g.getImageData(0,0,a,a).data;m=g.getImageData(0,0,a,a)}function e(b){return Math.round(Math.random()*b)}var a=200,i=255,h=[],k=[],f,g,l,m,n;f=document.body.children[0];f.width=f.height=a;f.onclick=function(b){if(b.shiftKey)o();else h[b.clientY*a+b.clientX]=
-900};g=f.getContext("2d");o();f=l.length/4;do{h[f]=0;k[f]=0}while(--f);n=h.length-a;setInterval(function(){var b=k,c=h,d=n;do{if(d==a)break;var j=d%a;if(!(!j||j==199)){c[d]=(b[d-1]+b[d+1]+b[d-a]+b[d+a]>>1)-c[d];c[d]-=c[d]>>5}}while(--d);b=h;h=k;k=b;b=h;c=n;do{if(c==a)break;d=c%a;if(!(!d||d==199)){d=c+(b[c-1]-b[c+1])+(b[c-a]-b[c+a])*a;if(d>0&&d<b.length){j=4;do m.data[c*4+j]=l[d*4+j];while(--j)}}}while(--c);try{g.putImageData(m,0,0)}catch(p){}},80);setInterval(function(){h[e(a)*a+e(a)]+=e(-900)},
600)})();
/**
Generates procedural water ripple effects on top of a randomly generated gradient background.
Click on the canvas to generate a new wave, hold Shift + Click to change the gradient background.
There is an issue with the Firefox canvas implementation that is a known bug (https://bugzilla.mozilla.org/show_bug.cgi?id=498826)
There is no way around this issue at this time, with a test case to confirm this:
http://philip.html5.org/tests/canvas/suite/tests/index.2d.imageData.put.dirty.html
1.0
* Original Release
1.1
* Fix for Firefox
1.2
* Further exception catch for Firefox canvas bug (https://bugzilla.mozilla.org/show_bug.cgi?id=498826)
* Added onclick to canvas to randomly change gradient background
* Savage Optimisation
1.3
* Removed onready stuff
* Removed setter methods on canvas for size
* Added handler for click to create new ripple, Ctrl + Click to change background
* Fred Savage Optimisation
1.4
* Changed handler from Ctrl to Shift for better Mac support
1.5
* Savage Garden Optimisation, final version for submission
Some work based on the origional algorithim from http://bit.ly/bmDo1Q, optimised
for 1Kb
*/
(function() {
var size = 200,
check = 199,
color = 255,
wavemod = -900,
buffer1 = [],
buffer2 = [],
cvs,
ctx,
initData,
renderData,
j;
function genGradient() {
ctx.clearRect(0, 0, size, size);
var gradient = ctx.createRadialGradient(0, 0, 0, 0, 0, size);
var c1 = [mathRand(color), mathRand(color), mathRand(color)];
gradient.addColorStop(0, 'rgb(' + c1.join(',') + ')');
var c2 = [mathRand(color), mathRand(color), mathRand(color)];
gradient.addColorStop(1, 'rgb(' + c2.join(',') + ')');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, size, size);
initData = ctx.getImageData(0, 0, size, size).data;
renderData = ctx.getImageData(0, 0, size, size);
}
function processWater(source, dest) {
var i = j
do {
if (i == size) break;
var xi = i % size;
if (!xi || xi == check) continue;
dest[i] = (
((source[i - 1] +
source[i + 1] +
source[i - size] +
source[i + size]) >> 1)) - dest[i];
dest[i] -= (dest[i] >> 5);
}
while (--i);
}
function texture(buffer) {
var i = j
do {
if (i == size) break;
var xi = i % size;
if (!xi || xi == check) continue;
var offset = i + (buffer[i - 1] - buffer[i + 1]) + (buffer[i - size] - buffer[i + size]) * size;
if (offset > 0 && offset < buffer.length) {
var x = 4;
do {
renderData.data[i * 4 + x] = initData[offset * 4 + x];
}
while(--x);
}
}
while (--i);
try {
ctx.putImageData(renderData, 0, 0);
} catch(e) {
return;
// This is to catch the occasional error thrown up in Firefox
// Known Bug: https://bugzilla.mozilla.org/show_bug.cgi?id=498826
// Canvas test suite to confirm: http://philip.html5.org/tests/canvas/suite/tests/index.2d.imageData.put.dirty.html
}
}
function mathRand(modifier) {
return Math.round(Math.random() * modifier);
}
function clickHandler(e) {
(e.shiftKey) ? genGradient() : create(e);
}
function create(e) {
var eX = e.clientX;
var eY = e.clientY;
buffer1[eY * size + eX] = wavemod;
}
cvs = document.body.children[0];
cvs.width = cvs.height = size;
cvs.onclick = clickHandler;
ctx = cvs.getContext('2d');
genGradient();
var i = initData.length / 4;
do {
buffer1[i] = 0;
buffer2[i] = 0;
}
while (--i);
j = buffer1.length - size
setInterval(function() {
processWater(buffer2, buffer1);
var tmp = buffer1;
buffer1 = buffer2;
buffer2 = tmp;
texture(buffer1);
},
80);
setInterval(function() {
buffer1[mathRand(size) * size + mathRand(size)] += mathRand(wavemod);
},
600);
})();