It’s not new and it was done many, many times with Java Applets: the Water Ripple effect! Yeay! I created one some years ago since I just like to play with it so much. Nowadays we have the HTML5 canvas but also fast javascript engines . I still wanted to experiment with the HTML5 canvas anyway so I decided to port my applet to a canvas.
Check the Water Ripple Effect here!
In this article I will show the effect, explain how the effect works and also how you can reuse the highly configurable javascript classes. You could use it for nice cheesy banner effects or just to impress your site visitors
. Anyway… lets check it out!
The water ripple canvas
It’s best to check this canvas effect on a browser that supports HTML5 canvas (like Google Chrome, Safari, Firefox or IE9)! I recommend to view it on Firefox 4. At time of writing it’s by far the best performing browser for this algorithm. For you people that found this blog with another browser, here’s a screen shot image:
The water ripple effect mimics a top view on water with water rippling and refraction of light through the water. On my implementation you can use your mouse like it’s your finger that touches the water. Pressing the mouse button gives you a bigger ‘finger’. And… there’s no need for performing your rain dance anymore. Just adjust the “Raindrops per second” slider to make raindrops fall on the canvas. If you’re like me, you can spend hours moving your mouse around on the canvas with big eyes and a big smile on your face
.
Update (March 8th, 2011): I implemented the use of requestAnimationFrame (Read more about it in this article by Paul Irish). It triggers a callback function just like setTimeout would. But now it’s not the time but your browser telling the best time to render the water pixels on the canvas. Also note the ‘FPS Canvas’ for going up after you switched to another tab and back to the water canvas. The browser knows it’s no use redrawing the canvas when no-one is watching it and so preventing your CPU/GPU fans from going mental for nothing
.
Pimp my site… (with a swimming pool)
How should you add the effect to your site? First of all, the code and the best/preferred way to implement it described here may be updated at any time in the future. So check back this section when you decide to use the effect in the future. Next, the code will be officially open sourced and will be put on Github when I have time to do this. It’s best to use that code from then on.
To use the code you should put just one javascript file on your web server: watercanvas.js. Then you should include this script in your HTML file’s <head> code:
<script src="watercanvas.js"></script>
Now you need to create some location (a <div>) where the WaterCanvas can insert it’s to be created canvas element. Place this div at the location between the <body> tags where you want the canvas to show up.
... <div id="waterHolder"></div> ...
Give it an ID so we are able to point to it in javascript in the following step. We are now ready to create and init the necessary objects. In the <head> you should now add a <script> section. Add the following javascript code in it:
<script>
var width = 350;
var width = 275;
function init(){
var waterModel = new WaterModel(width, height, {
resolution:2.0,
interpolate:false,
damping:0.985,
clipping:5,
evolveThreshold:0.05,
maxFps:30,
showStats:true
});
var waterCanvas = new WaterCanvas(width, height,
"waterHolder", waterModel, {
backgroundImageUrl:"images/yourimage.jpg",
lightRefraction:9.0,
lightReflection:0.1,
maxFps:20,
showStats:true
});
}
</script>
We created an init function which we will soon call at the document loaded event. When the init function is called, two javascript objects will be created:
- A WaterModel object: A model object which is responsible for holding, manipulating and evolving the water ripple data. The model does not need to use the same amount of pixels as the canvas. You should use the same width and hight as for the WaterCanvas but you can set a resolution and use bilinear interpolation.
- A WaterCanvas object: A view object which is responsible for applying the water ripple data state to an image and therefor is also responsible for the reflection and refraction effects.
See the javascript jsdoc comments in the javascript files for descriptions of all parameters and some more explanation. In the example you can use the sliders to update settings in the models and experiment with it. It’s a great way to find the settings you want to use.
To finish it we need to call the init method when the DOM is loaded so we are sure the div we created before is available (If you know how to work with javascript and DOM loading timings, you can do this in better/faster ways. For the sake of simplicity I’m using the plain old body onload here.):
<body onload="init()">
Now upload all files to your server and open the HTML file in your browser… Wait, nothing is happening!? Of course, we need to “touch” the WaterModel to see the effect in action:
<scrip> ... var finger = [ [0.5, 1.0, 0.5], [1.0, 1.0, 1.0], [0.5, 1.0, 0.5] ]; waterModel.touchWater(100, 100, 1.5, finger); </scrip>
The touchWater function needs an X and Y position, a pressure multiplier and a 2D array pattern which represents a “finger” or “raindrop”. This is actually the basis of how to use the Water Canvas… Ok, a little more insight in the code above:
You need to create a 2D array which the touchWater function is using to apply to the WaterModel. This is powerful since you can apply pressure to the WaterModel in any shape you like! See my example for how I use a util function which is also in watercanvas.js (util functions are at the bottom of the file). You can use it to create a 2D array from a (small) canvas which you can draw to in gray scale values to create your own custom shapes.
You can also make your mouse pointer touch the WaterModel. You need to use mouse EventListeners to track your mouse. Again, I created an out-of-the-box util function for you. Check the code of my example to find out how to do this.
The water ripple FX algorithm and javascript
So what’s the trick? What does make this water effect work?
There’s actually a very good tutorial by Hugo Elias about the functionality of the WaterModel which I used when I create my first implementation in a Java Applet. So I won’t go to deep into that. In short; for every position in a 2D array the algorithm looks in the surrounding 2D array positions for the float values, then applies some devisions, et voila, there’s a new value for the current position. You need to use two 2D arrays. One for the current state and one for the new state to calculate. All newly calculated positions will be put in a second 2D array buffer. After all positions are rendered the buffers will be swapped before the next calculation round starts.
The WaterCanvas uses the state of the data in the WaterModel at a frame render moment. It reads the positions of the WaterModel’s 2D array buffer and uses each value to manipulate the pixels of the WaterCanvas’s canvas pixels. There are two different things I applied to these pixels;
- reflection of light on the water
- refraction of light through the water
For reflection, for every pixel of the canvas we get a value from the WaterModel. When the WaterModel returns a positive value, we’ll make the pixel color a little lighter by the amount of the value, when negative, a little darker by the amount of the value. Refraction is done in almost the same way. When the value is positive get the pixel of the current position with the positive amount added. For a negative value automatically the current position minus the absolute value is used. This is in short how it works. Wanna know more? Check out the code!
Splish splash… The conclusion
So far this canvas experiment on realtime pixel manipulation works. But, when compared to some Java Applets I should conclude Javascript is just not as fast. On the other hand, canvas’s start faster then Java Applets without Java splash screens (what’s in a word
). When you use the Water Canvas you should keep the canvas as small as possible to be sure it performs. Set the max FPS’s to the minimum you find to be OK.
There are some enhancements I may try at some time like using an HTML5 WebWorker for the WaterModel and/or using some WebGL hardware performance optimizations. At this point I really don’t know if WebGL can be used at all for this effect.
I should also take some time to make the Water Canvas degrade gracefuly on old browsers. Currently you will get bothered with an anoying javascript alert when the browser doesn’t support HTML5 canvas. Also, it should be possible to point this script to an <img> tag or another <canvas> tag, where the WaterCanvas class constructor will convert it to a Water Canvas for you.
Let me know what you think of the Water Ripple Canvas or how I can improve the performance of it. OK, I’m off for a swim…

14 Comments
Interesting, but your ripple simulation runs very slow even in a browser with a fast JavaScript engine, like Chrome or Opera. Check out this HTML5 Dynamic Water Effect, which runs significantly faster, even using the same water model method.
Hi Nicolas, I agree (although the implementation you mention has probably been updated since I’ve seen this one being slower before). The problem with my implementation is probably due to implementing this effect in an Object Oriented (almost MVC) way. I’ve seen an online presentation from Thomas Fuchs recently on high performance Javascript. He has many tips on improving speed which I might one day use to increese the speed. A key for speed is to keep all processing in one loop as much as possible. I will make the code less readable but probably faster.
Hi Almeros,
The implementation I pointed to was not updated since its original. I think this was the first HTML5 water ripple effect created. That aside, my only point is that this problem only becomes interesting once you consider the efficiency aspect, even if that means you have to forgo a “perfect” design pattern.
My point exactly Nicholas! Congratulations on creating the first HTML5 water ripple ;P
I also found this implementation from chikuyonok. I personally think it’s the best one out there right now!
Hi Almer ..
Nice thing, my CPU gets stuck on 12.5% (1/8cores). But is see you are already thinking of a more subtle solution
Hi Wouter, thanks for your comment. Nice observation of the CPU core usage!
Now there’s a problem in that you can’t really tell Javascript how and which cores to use, neither ask how many cores there are available on a client. That’s something the browser’s Javascript engine decides/implements. To solve this I might try to use multiple HTML5′s Web workers (but this effect won’t be working in the upcoming IE9 when using WebWorkers, but then again, the Canvas in IE9 preview shows bugs with this effect anyway
).
What browser did you use? I might try to use multiple cores next time I’m working on this effect!
Just wanted to mention that, when using small dimensions your app is quite fast and useful. I knoow its not optimal (like using in a giant and beautyful background or something) and probably not the usage you expected but its a good start.
Maybe if disabling some features (like clicking on it) it will make it faster a bit? I am having a similar problem with a jquery app I’m using for 3d effects, but its eating my pc quite a bit, so I’m considering purchasing one of those Thomas Fuch’s books because it seem to be very handy.
Thank you for all the work you had.
Hi Diego Crusius, thanks for your comment and sorry for replying just now.
If you’re creating 3D effects, be sure to also check out Web-GL for creating 3D effects via your graphics card’s GPU. Nothing will beat that in performance!
I personally could also try and use Web-GL for this 2D effect also. But there’s a lot for me to check out (learn how shaders work) and I should probably refactor the current code in total.
Is it possible to get the ripple’s only in a circle?
i have a image of a cup of coffee.. like to ripple the coffee only.
thnx!
Hi Veen00,
I quess there’s two ways doing that, an easy way and a hard way (which will be more realistic).
For the hard way you should alter my algorithm code and create a circular 2d buffer some way. The water waves will bounce of the sides more realisticly. The easy way (go for this one if you want to use it for fun) should be achieved by using the coffee background in the canvas. Now add a transparent .PNG image with the cup and a transparent cutout of the coffee content on top over the canvas. Make the canvas with ripple effect as small as possible arround the circle. That should do it!
If you created this, please send me a link to your creation!
Hello, this is a very great program:)
I have a little question. Is it possible to make the rain drop effect for only a second or two? With a smooth fade out.
Thank you!
Best regards,
tim
Hi Tim, thanks,
Sure, actually, when you setup a WaterModel and a WaterCanvas just DON’T add a mouse event listener and DON’T add the rain generator. Only create a ‘finger’ in a 2D array like the code above and perform a touchWater on the WaterModel object on the location where you want the ripple to start. Change the settings to let the ripple fade out in about 2 seconds and you’re done (you can use my example’s sliders to figure out what are the best settings for you).
Nice to know; when your single ripple is done rippling, the WaterModel and Canvas will stop taking resources on your website, keeping the performance for other javascripts optimal.
Let me know when you have something online! Have fun!
I want to use this effect on my website but I am only an artist and the instructions overwhelm me. Is there a simpler step by step available? A lot of the terms make no sense to me. I don’t code my sites but use a program that generates the code (OK stop hissing and booing
and I can insert code and don’t know where I would insert this stuff.
Thanks
Hi Luke,
First of all, thanks for your interest. I think you’re right that the story above is a bit nerdy
. There isn’t really a simpler step by step unfortunately. What I can give you is the code for the simplest working html with a water canvas.
Put it all on a webserver (unzipped ofcourse) and check it out via your webserver’s URL…
You can fiddle with the settings in index.html now and/or change the background image, until you like it!
Also, please understand that this effect is taking quite a lot of browser resources. Don’t expect it to perform full screen (or even half) on your webpage or something! Putting it on a site’s logo should however work fine on modern browsers.
2 Trackbacks
[...] Water ripple FX with Canvas and Javascript course, the processing will probably kill you on an entire background __________________ [...]
[...] it’s not cubes then it’s ripple effects! Almer’s is pretty good though and he’s made it into a library you can use on your own site. An interesting factoid from his blog post: Firefox 4 runs it best, even better than [...]