Creating Animated Particles in Water Effect using JavaScript

Tutorials

Water simulation with javascript. Today we continue JavaScript lessons, and our article will about using js in modeling of water effects. Sometimes we can create very interesting solutions using ordinary Javascript.

Here are sample and downloadable package:

Live Demo

Step 1. HTML

As usual, we start with the HTML.

This is our main page code with all samples.

index.html

1 <link rel="stylesheet" href="css/main.css" type="text/css" media="all" />
2 <script src="js/main.js" type="text/javascript"></script>
3 <div class="example">
4     <img id="unit" src="unit.png" style="visibility:hidden" >
5     <div id="main"></div>
6     <div id="fps"></div>
7 </div>

Step 2. CSS

Here are used CSS styles.

css/main.css

1 body{background:#eee;font-family:VerdanaHelveticaArialsans-serif;margin:0;padding:0}
2 .example{position:relative;background:#FFF;width:600px;height:600px;border:1px #000 solid;margin:20px auto;padding:20px;-moz-border-radius:3px;-webkit-border-radius:3px}
3 #main{position:absolute;width:520px;height:520px;background:#000;outline:#f0f solid 3px;overflow:hidden;cursor:pointer}
4 #fps{position:absolute;right:20px;top:20px}

Step 3. JS

Here are our main control JS file.

js/main.js

001 var wp = function () {
002     // variables
003     var scr, grid, npart, diam, nx, ny, nw, nh, gw, gh;
004     var xm = 0;
005     var ym = 0;
006     var obj = new Array(npart);
007     var down = false;
008     var fps = 0;
009     // add listeners
010     var addEvent = function  (o, e, f) {
011         if (window.addEventListener) o.addEventListener(e, f, false);
012         else if (window.attachEvent) r = o.attachEvent('on' + e, f);
013     }
014     // resize function
015     var resize = function () {
016         nw = scr.offsetWidth;
017         nh = scr.offsetHeight;
018         var o = scr;
019         for (nx = 0, ny = 0; o != null; o = o.offsetParent) {
020             nx += o.offsetLeft;
021             ny += o.offsetTop;
022         }
023         gw = Math.round(nw / pdiam);
024         gh = Math.round(nh / pdiam);
025     }
026     // particle constructor
027     var Particle = function (img) {
028         this.x = Math.random() * nw;
029         this.y = Math.random() * nh;
030         this.vx = 0;
031         this.vy = 0;
032         this.dx = 0;
033         this.dy = 0;
034         this.wi = img.width * .5;
035         this.hi = img.height * .5;
036         // new html elements
037         var d = document.createElement('img');
038         d.style.position = "absolute";
039         d.style.left = "-1000px";
040         d.src = img.src;
041         scr.appendChild(d);
042         this.plo = d.style;
043     }
044     // move particle
045     Particle.prototype.move = function () {
046         this.x  += this.dx;
047         this.y  += this.dy;
048         this.vx += this.dx;
049         this.vy += this.dy;
050         this.dx  = 0;
051         this.dy  = 0;
052         // DOM
053         this.plo.left = Math.round(this.x - this.wi) + 'px';
054         this.plo.top  = Math.round(this.y - this.hi) + 'px';
055     }
056     // water simulation
057     Particle.prototype.physics = function () {
058         // mouse influence
059         if (down) {
060             var dx = this.x - xm;
061             var dy = this.y - ym;
062             var d = Math.sqrt(dx * dx + dy * dy);
063             if (d < pdiam * 2) {
064                 this.dx += dx / d;
065                 this.dy += dy / d;
066             }
067         }
068         // gravity and acceleration
069         this.vy += .2;
070         this.x += this.vx;
071         this.y += this.vy;
072         // screens limits
073         if (this.x < pdiam * .5) this.dx += (pdiam * .5 - this.x);
074         else if (this.x > nw - pdiam * .5) this.dx -= (this.x - nw + pdiam * .5);
075         if (this.y < pdiam * .5) this.dy += (pdiam * .5 - this.y);
076         else if (this.y > nh - pdiam * .5) this.dy -= (this.y - nh + pdiam * .5);
077         // grid coordinates
078         var gx = Math.round(this.x / pdiam);
079         var gy = Math.round(this.y / pdiam);
080         // neightbors constraints
081         for (var ix = gx - 1; ix <= gx + 1; ix++) {
082             for (var iy = gy - 1; iy <= gy + 1; iy++) {
083                 var g = grid[iy * gw + ix] || [];
084                 for (j = 0, l = g.length; j < l; j++) {
085                     var that = g[j];
086                     var dx = that.x - this.x;
087                     var dy = that.y - this.y;
088                     var d = Math.sqrt(dx * dx + dy * dy);
089                     if (d < pdiam && d > 0) {
090                         dx = (dx / d) * (pdiam - d) * .25;
091                         dy = (dy / d) * (pdiam - d) * .25;
092                         this.dx -= dx;
093                         this.dy -= dy;
094                         that.dx += dx;
095                         that.dy += dy;
096                     }
097                 }
098             }
099         }
100         // update neighbors array
101         if (!grid[gy * gw + gx]) grid[gy * gw + gx] = [this];
102         else grid[gy * gw + gx].push(this);
103     }
104     // loop
105     var run = function () {
106         fps++;
107         grid = new Array(gw * gh);
108         for(var i = 0; i < npart; i++) obj[i].physics();
109         for(var i = 0; i < npart; i++) obj[i].move();
110         setTimeout(run, 1);
111     }
112     return {
113         // initialization
114         init : function (n, d) {
115             scr = document.getElementById('main');
116             npart = n;
117             pdiam = d;
118             // subscribing to events
119             addEvent(document, 'mousemove'function (e) {
120                 if (window.event) e = window.event;
121                 xm = e.clientX - nx;
122                 ym = e.clientY - ny;
123             });
124             addEvent(window, 'resize', resize);
125             addEvent(document, 'mousedown'function(e) {if (e.preventDefault) e.preventDefault(); down = true;return false;});
126             addEvent(document, 'mouseup'function() { down = false;return false;});
127             document.onselectstart = function () { return false; }
128             scr.ondrag = function () { return false; }
129             // fps countrt
130             setInterval(function() {
131                 document.getElementById('fps').innerHTML = fps + ' FPS';
132                 fps = 0;
133             }, 1000);
134             // starting
135             resize();
136             for (var i = 0; i < npart; i++) obj[i] = new Particle(document.getElementById('unit'));
137             run();
138         }
139     }
140 }();
141 window.onload = function() {
142   wp.init(50, 45);
143 }

This is most interesting and important part of our article. Here we creating our main object – scene, and adding particle to it. Also added several events (mainly for mouse). All this looks like low level coding, but don`t worry – this is mainly mathematics.


Live Demo

[sociallocker]

download in package

[/sociallocker]


Conclusion

Hope that you was happy to play with thas robo-water 🙂 If is you were wondering – do not forget to thank. I would be grateful for your interesting comments. Good luck!

Rate article