Water ripple effect with HTML5. Today we continue JavaScript examples, and our article will about using javascript in modeling of water effects. This will emulation of water drops at images. We should click at image in desired place to see this effect. Sometimes we can create very interesting solutions using ordinary Javascript (of course for HTML) 🙂
Here are sample and downloadable package:
[sociallocker]
[/sociallocker]
Ok, download the example files and lets start coding !
Step 1. HTML
As usual, we start with the HTML.
This is our main page code with all samples.
index.html
04 |
< meta charset = utf -8 /> |
05 |
< title >Water drops effect</ title > |
06 |
< link rel = "stylesheet" href = "css/main.css" type = "text/css" /> |
07 |
< script src = "js/vector2d.js" type = "text/javascript" charset = "utf-8" ></ script > |
08 |
< script src = "js/waterfall.js" type = "text/javascript" charset = "utf-8" ></ script > |
12 |
< h3 >< a href = "#" >Water drops effect</ a ></ h3 > |
13 |
< canvas id = "water" >HTML5 compliant browser required</ canvas > |
15 |
< img onclick = 'watereff.changePicture(this.src);' src = "data_images/underwater1.jpg" /> |
16 |
< img onclick = 'watereff.changePicture(this.src);' src = "data_images/underwater2.jpg" /> |
Step 2. CSS
Here are used CSS styles.
css/main.css
01 |
body{ background : #eee ; margin : 0 ; padding : 0 } |
02 |
.example{ background : #FFF ; width : 600px ; border : 1px #000 solid ; margin : 20px auto ; padding : 15px ;-moz-border-radius: 3px ;-webkit-border-radius: 3px } |
Step 3. JS
Here are our main control JS file.
js/main.js
001 |
function drop(x, y, damping, shading, refraction, ctx, screenWidth, screenHeight){ |
004 |
this .shading = shading; |
005 |
this .refraction = refraction; |
006 |
this .bufferSize = this .x * this .y; |
007 |
this .damping = damping; |
008 |
this .background = ctx.getImageData(0, 0, screenWidth, screenHeight).data; |
009 |
this .imageData = ctx.getImageData(0, 0, screenWidth, screenHeight); |
012 |
for ( var i = 0; i < this .bufferSize; i++){ |
013 |
this .buffer1.push(0); |
014 |
this .buffer2.push(0); |
016 |
this .update = function (){ |
017 |
for ( var i = this .x + 1, x = 1; i < this .bufferSize - this .x; i++, x++){ |
019 |
this .buffer2[i] = (( this .buffer1[i - 1] + this .buffer1[i + 1] + this .buffer1[i - this .x] + this .buffer1[i + this .x]) / 2) - this .buffer2[i]; |
020 |
this .buffer2[i] *= this .damping; |
023 |
var temp = this .buffer1; |
024 |
this .buffer1 = this .buffer2; |
027 |
this .draw = function (ctx){ |
028 |
var imageDataArray = this .imageData.data; |
029 |
for ( var i = this .x + 1, index = ( this .x + 1) * 4; i < this .bufferSize - (1 + this .x); i++, index += 4){ |
030 |
var xOffset = ~~( this .buffer1[i - 1] - this .buffer1[i + 1]); |
031 |
var yOffset = ~~( this .buffer1[i - this .x] - this .buffer1[i + this .x]); |
032 |
var shade = xOffset * this .shading; |
033 |
var texture = index + (xOffset * this .refraction + yOffset * this .refraction * this .x) * 4; |
034 |
imageDataArray[index] = this .background[texture] + shade; |
035 |
imageDataArray[index + 1] = this .background[texture + 1] + shade; |
036 |
imageDataArray[index + 2] = 50 + this .background[texture + 2] + shade; |
038 |
ctx.putImageData( this .imageData, 0, 0); |
053 |
backgroundURL : 'data_images/underwater1.jpg' , |
056 |
var canvas = document.getElementById( 'water' ); |
057 |
if (canvas.getContext){ |
060 |
setInterval( function () { |
061 |
document.getElementById( 'fps' ).innerHTML = fps / 2 + ' FPS' ; |
064 |
canvas.onmousedown = function (e) { |
065 |
var mouse = watereff.getMousePosition(e).sub( new vector2d(canvas.offsetLeft, canvas.offsetTop)); |
066 |
watereff.pond.buffer1[mouse.y * watereff.pond.x + mouse.x ] += 200; |
068 |
canvas.onmouseup = function (e) { |
069 |
canvas.onmousemove = null ; |
071 |
canvas.width = this .screenWidth; |
072 |
canvas.height = this .screenHeight; |
073 |
this .textureImg = new Image(256, 256); |
074 |
this .textureImg.src = this .backgroundURL; |
075 |
canvas.getContext( '2d' ).drawImage( this .textureImg, 0, 0); |
076 |
this .pond = new drop( |
082 |
canvas.getContext( '2d' ), |
083 |
this .screenWidth, this .screenHeight |
085 |
if ( this .interval != null ){ |
086 |
clearInterval( this .interval); |
088 |
this .interval = setInterval(watereff.run, this .timeStep); |
092 |
changePicture : function (url){ |
093 |
this .backgroundURL = url; |
097 |
getMousePosition : function (e){ |
099 |
var e = window.event; |
101 |
if (e.pageX || e.pageY){ |
102 |
return new vector2d(e.pageX, e.pageY); |
103 |
} else if (e.clientX || e.clientY){ |
104 |
return new vector2d(e.clientX, e.clientY); |
109 |
var ctx = document.getElementById( 'water' ).getContext( '2d' ); |
110 |
watereff.pond.update(); |
111 |
watereff.pond.draw(ctx); |
115 |
window.onload = function (){ |
As you can see- I using vector2d function here. This function available in ‘vector2d.js’ (in our package). Another code – pretty difficult – pure mathematics. But you are welcome to make experiments here.
Conclusion
Hope that you was happy to play with it. I hope that water drops looks fine 🙂 If is you were wondering – do not forget to thank. I would be grateful for your interesting comments. Good luck!