某人用Java搞了一个流体力学的演示:http://grantkot.com/MPM/Liquid.html。

下面是 HTML 5版的流体力学演示(推荐使用Chrome浏览器浏览):

效果演示

<canvas width="400" height="400" id="liquid"></canvas><script>
/**
* This version:
* Copyright Stephen Sinclair (radarsat1) ( http://www.music.mcgill.ca/~sinclair )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://www.music.mcgill.ca/~sinclair/blog
*/

/**
* Flash version:
* Copyright iunpin ( http://wonderfl.net/user/iunpin )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/6eu4
*/

/**
* Original Java version:
* http://grantkot.com/MPM/Liquid.html
*/

var canvas;
var context;
var running = false;
var width = 0;
var height = 0;
var liquidTest;
var step = 0;

function LiquidTest(gsizeX, gsizeY, particlesX, particlesY)
{
this.particles = [];

this.gsizeX = gsizeX;
this.gsizeY = gsizeY;

this.grid = [[]]; //Nodes
this.active = []; //Nodes
this.water = new Material(1.0, 1.0, 1.0, 1.0, 1.0, 1.0);
this.pressed = false;
this.pressedprev = false;

this.mx = 0;
this.my = 0;
this.mxprev = 0;
this.myprev = 0;

this.init = function()
{
var i = 0, j = 0;
this.grid = [];
for (i = 0; i < this.gsizeX; i++)
{
this.grid.push([]);
for (j = 0; j < this.gsizeY; j++)
{
this.grid[i].push(new Node());
}
}

var p;
for (i = 0; i < particlesX; i++)
for (j = 0; j < particlesY; j++)
{
p = new Particle(this.water, i + 4, j + 4, 0.0, 0.0);
this.particles.push(p);
}
}

this.paint = function()
{
context.clearRect(0, 0, width, height);

context.beginPath();
for (var pi in this.particles)
{
var p = this.particles[pi];
line(4.0 * p.x, 4.0 * p.y,
4.0 * (p.x - p.u), 4.0 * (p.y - p.v));
}

context.stroke();
}

this.simulate = function()
{
var drag = false;
var mdx = 0.0, mdy = 0.0;

if (this.pressed && this.pressedprev)
{
drag = true;
mdx = 0.25 * (this.mx - this.mxprev);
mdy = 0.25 * (this.my - this.myprev);
}

this.pressedprev = this.pressed;
this.mxprev = this.mx;
this.myprev = this.my;

for (var n in this.active)
this.active[n].clear();
this.active.length = 0;

var i, j;
var x, y, phi;
var fx = 0.0, fy = 0.0;
for (var pi in this.particles)
{
var p = this.particles[pi];
p.cx = parseInt(p.x - 0.5);
p.cy = parseInt(p.y - 0.5);

x = p.cx - p.x;
p.px[0] = (0.5 * x * x + 1.5 * x + 1.125);
p.gx[0] = (x + 1.5);
x += 1.0;
p.px[1] = (-x * x + 0.75);
p.gx[1] = (-2.0 * x);
x += 1.0;
p.px[2] = (0.5 * x * x - 1.5 * x + 1.125);
p.gx[2] = (x - 1.5);

y = p.cy - p.y;
p.py[0] = (0.5 * y * y + 1.5 * y + 1.125);
p.gy[0] = (y + 1.5);
y += 1.0;
p.py[1] = (-y * y + 0.75);
p.gy[1] = (-2.0 * y);
y += 1.0;
p.py[2] = (0.5 * y * y - 1.5 * y + 1.125);
p.gy[2] = (y - 1.5);

for (var i = 0; i < 3; i++)
{
for (var j = 0; j < 3; j++)
{
var n = this.grid[p.cx + i][p.cy + j];
if (!n.active)
{
this.active.push(n);
n.active = true;
}
phi = p.px[i] * p.py[j];
n.m += phi * p.mat.m;
n.d += phi;
n.gx += p.gx[i] * p.py[j];
n.gy += p.px[i] * p.gy[j];
}
}
}

var density, pressure, weight;
var n01, n02;
var n11, n12;
var cx, cy;
var cxi, cyi;

var pdx, pdy;
var C20, C02, C30, C03;
var csum1, csum2;
var C21, C31, C12, C13, C11;

var u, u2, u3;
var v, v2, v3;

for (var pi in this.particles)
{
var p = this.particles[pi];

cx = parseInt(p.x);
cy = parseInt(p.y);
cxi = cx + 1;
cyi = cy + 1;

n01 = this.grid[cx][cy];
n02 = this.grid[cx][cyi];
n11 = this.grid[cxi][cy];
n12 = this.grid[cxi][cyi];

pdx = n11.d - n01.d;
pdy = n02.d - n01.d;
C20 = 3.0 * pdx - n11.gx - 2.0 * n01.gx;
C02 = 3.0 * pdy - n02.gy - 2.0 * n01.gy;
C30 = -2.0 * pdx + n11.gx + n01.gx;
C03 = -2.0 * pdy + n02.gy + n01.gy;
csum1 = n01.d + n01.gy + C02 + C03;
csum2 = n01.d + n01.gx + C20 + C30;
C21 = 3.0 * n12.d - 2.0 * n02.gx - n12.gx - 3.0 * csum1 - C20;
C31 = -2.0 * n12.d + n02.gx + n12.gx + 2.0 * csum1 - C30;
C12 = 3.0 * n12.d - 2.0 * n11.gy - n12.gy - 3.0 * csum2 - C02;
C13 = -2.0 * n12.d + n11.gy + n12.gy + 2.0 * csum2 - C03;
C11 = n02.gx - C13 - C12 - n01.gx;

u = p.x - cx;
u2 = u * u;
u3 = u * u2;
v = p.y - cy;
v2 = v * v;
v3 = v * v2;
density = n01.d + n01.gx * u + n01.gy * v + C20 * u2 + C02 * v2 + C30 * u3 + C03 * v3 + C21 * u2 * v + C31 * u3 * v + C12 * u * v2 + C13 * u * v3 + C11 * u * v;

pressure = density - 1.0;
if (pressure > 2.0)
pressure = 2.0;

fx = 0.0;
fy = 0.0;

if (p.x < 4.0)
fx += p.mat.m * (4.0 - p.x);
else if (p.x > this.gsizeX - 5)
fx += p.mat.m * (this.gsizeX - 5 - p.x);

if (p.y < 4.0)
fy += p.mat.m * (4.0 - p.y);
else if (p.y > this.gsizeY - 5)
fy += p.mat.m * (this.gsizeY - 5 - p.y);

if (drag)
{
var vx = Math.abs(p.x - 0.25 * this.mx);
var vy = Math.abs(p.y - 0.25 * this.my);
if ((vx < 10.0) && (vy < 10.0))
{
weight = p.mat.m * (1.0 - vx * 0.10) * (1.0 - vy * 0.10);
fx += weight * (mdx - p.u);
fy += weight * (mdy - p.v);
}
}

for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
n = this.grid[(p.cx + i)][(p.cy + j)];
phi = p.px[i] * p.py[j];
n.ax += -((p.gx[i] * p.py[j]) * pressure) + fx * phi;
n.ay += -((p.px[i] * p.gy[j]) * pressure) + fy * phi;
}
}
}

for (var ni in this.active)
{
var n = this.active[ni];
if (n.m > 0.0)
{
n.ax /= n.m;
n.ay /= n.m;
n.ay += 0.03;
}
}

var mu, mv;
for (var pi in this.particles)
{
var p = this.particles[pi];
for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
n = this.grid[(p.cx + i)][(p.cy + j)];
phi = p.px[i] * p.py[j];
p.u += phi * n.ax;
p.v += phi * n.ay;
}
}
mu = p.mat.m * p.u;
mv = p.mat.m * p.v;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
n = this.grid[(p.cx + i)][(p.cy + j)];
phi = p.px[i] * p.py[j];
n.u += phi * mu;
n.v += phi * mv;
}
}
}

for (var ni in this.active)
{
var n = this.active[ni];
if (n.m > 0.0)
{
n.u /= n.m;
n.v /= n.m;
}
}

var gu, gv;
for (var pi in this.particles)
{
var p = this.particles[pi];
gu = 0.0;
gv = 0.0;
for (var i = 0; i < 3; i++)
{
for (var j = 0; j < 3; j++)
{
var n = this.grid[(p.cx + i)][(p.cy + j)];
phi = p.px[i] * p.py[j];
gu += phi * n.u;
gv += phi * n.v;
}
}
p.x += gu;
p.y += gv;
p.u += 1.0 * (gu - p.u);
p.v += 1.0 * (gv - p.v);
if (p.x < 1.0)
{
p.x = (1.0 + Math.random() * 0.01);
p.u = 0.0;
}
else if (p.x > this.gsizeX - 2)
{
p.x = (this.gsizeX - 2 - Math.random() * 0.01);
p.u = 0.0;
}
if (p.y < 1.0)
{
p.y = (1.0 + Math.random() * 0.01);
p.v = 0.0;
}
else if (p.y > this.gsizeY - 2)
{
p.y = (this.gsizeY - 2 - Math.random() * 0.01);
p.v = 0.0;
}
}
}

this.init();
}

function Node()
{
this.m = 0;
this.d = 0;
this.gx = 0;
this.gy = 0;
this.u = 0;
this.v = 0;
this.ax = 0;
this.ay = 0;
this.active = false;

this.clear = function()
{
this.m = this.d = this.gx = this.gy = this.u = this.v = this.ax = this.ay = 0.0;
this.active = false;
}
}

function Particle(mat, x, y, u, v)
{
this.mat = mat;
this.x = x;
this.y = y;
this.u = u;
this.v = v;

this.dudx = 0;
this.dudy = 0;
this.dvdx = 0;
this.dvdy = 0;
this.cx = 0;
this.cy = 0;

this.px = [0,0,0];
this.py = [0,0,0];
this.gx = [0,0,0];
this.gy = [0,0,0];
}

function Material(m, rd, k, v, d, g)
{
this.m = m;
this.rd = rd;
this.k = k;
this.v = v;
this.d = d;
this.g = g;
}

function line(x1,y1,x2,y2) {
context.moveTo(x1,y1);
context.lineTo(x2,y2);
}

function getPosition(obj) {
var p = obj.offsetParent;
var left = obj.offsetLeft;
var top = obj.offsetTop;
if (p) {
var pos = getPosition(p);
left += pos[0];
top += pos[1];
}
return [left, top];
}

function mouseMoved(event)
{
var pos = getPosition(canvas);
liquidTest.mx = event.pageX - pos[0];
liquidTest.my = event.pageY - pos[1];
}

function mousePressed(event)
{
liquidTest.pressed = true;
}

function mouseReleased(event)
{
liquidTest.pressed = false;
}

function stop()
{
running = false;
}

function start()
{
running = true;
draw();
}

function restart(gsizeX, gsizeY, particlesX, particlesY)
{
liquidTest = new LiquidTest(gsizeX, gsizeY, particlesX, particlesY);
running = true;
draw();
}

function draw()
{
// clear

// advance simulation
liquidTest.simulate();

step ++;
}

function init() {
canvas = document.getElementById('liquid');
width = canvas.width;
height = canvas.height;
context = canvas.getContext('2d');
context.strokeStyle = "#0000FF";

canvas.onmousedown = mousePressed;
canvas.onmouseup = mouseReleased;
canvas.onmousemove = mouseMoved;

liquidTest = new LiquidTest(100, 100, 50, 50);

start();
}

setInterval(draw, 33);
setInterval("liquidTest.paint()", 33);

init();
</script>

不过,这仅仅是个开始。某同学将其发布上了reddit.com,于是,全世界的同学们开始给力了。

Flash的开发者首先不服,搞了个 flash版(带源码):http://wonderfl.net/c/yxe9

看到了Flash版,Javascript+HTML5的同学们也不干了,于是出现HTML5版(带源码):http://www.music.mcgill.ca/~sinclair/content/blog/liquid_simulator_ported_to_canvas

不过性能慢了很多,所以,又有人优化了一下HTML5版的程序:http://jsbin.com/unovo4

SVG的同学们也不甘寂寞,不过,那真叫一个慢啊:http://ulo.pe/js-liquid-svg/

这个时候,C/C++同学出来了,使用SDL库也搞了一个:http://q3k.org/fluidsim.zip

短短几天里,被人重写成各种语言。

下面看看在HTML 5里面的实现:

001 <canvas width="400" height="400" id="liquid"></canvas><script>
002 /**
003 * This version:
004 * Copyright Stephen Sinclair (radarsat1) ( http://www.music.mcgill.ca/~sinclair )
006 * Downloaded from: http://www.music.mcgill.ca/~sinclair/blog
007 */
008  
009 /**
010 * Flash version:
011 * Copyright iunpin ( http://wonderfl.net/user/iunpin )
013 * Downloaded from: http://wonderfl.net/c/6eu4
014 */
015  
016 /**
017 * Original Java version:
019 */
020  
021 var canvas;
022 var context;
023 var running = false;
024 var width = 0;
025 var height = 0;
026 var liquidTest;
027 var step = 0;
028  
029 function LiquidTest(gsizeX, gsizeY, particlesX, particlesY)
030 {
031     this.particles = [];
032  
033     this.gsizeX = gsizeX;
034     this.gsizeY = gsizeY;
035  
036     this.grid = [[]]; //Nodes
037     this.active = []; //Nodes
038     this.water = new Material(1.0, 1.0, 1.0, 1.0, 1.0, 1.0);
039     this.pressed = false;
040     this.pressedprev = false;
041  
042     this.mx = 0;
043     this.my = 0;
044     this.mxprev = 0;
045     this.myprev = 0;
046  
047     this.init = function()
048     {
049         var i = 0, j = 0;
050         this.grid = [];
051         for (i = 0; i < this.gsizeX; i++)
052         {
053             this.grid.push([]);
054             for (j = 0; j < this.gsizeY; j++)
055             {
056                 this.grid[i].push(new Node());
057             }
058         }
059  
060         var p;
061         for (i = 0; i < particlesX; i++)
062             for (j = 0; j < particlesY; j++)
063             {
064                 p = new Particle(this.water, i + 4, j + 4, 0.0, 0.0);
065                 this.particles.push(p);
066             }
067     }
068  
069     this.paint = function()
070     {
071       context.clearRect(0, 0, width, height);
072  
073     context.beginPath();
074         for (var pi in this.particles)
075         {
076             var p = this.particles[pi];
077             line(4.0 * p.x,         4.0 * p.y,
078                  4.0 * (p.x - p.u), 4.0 * (p.y - p.v));
079         }
080  
081     context.stroke();
082     }
083  
084     this.simulate = function()
085     {
086         var drag = false;
087         var mdx = 0.0, mdy = 0.0;
088  
089         if (this.pressed && this.pressedprev)
090         {
091             drag = true;
092             mdx = 0.25 * (this.mx - this.mxprev);
093             mdy = 0.25 * (this.my - this.myprev);
094         }
095  
096         this.pressedprev = this.pressed;
097         this.mxprev = this.mx;
098         this.myprev = this.my;
099  
100         for (var n in this.active)
101             this.active[n].clear();
102         this.active.length = 0;
103  
104         var i, j;
105         var x, y, phi;
106         var fx = 0.0, fy = 0.0;
107         for (var pi in this.particles)
108         {
109             var p = this.particles[pi];
110             p.cx = parseInt(p.x - 0.5);
111             p.cy = parseInt(p.y - 0.5);
112  
113             x = p.cx - p.x;
114             p.px[0] = (0.5 * x * x + 1.5 * x + 1.125);
115             p.gx[0] = (x + 1.5);
116             x += 1.0;
117             p.px[1] = (-x * x + 0.75);
118             p.gx[1] = (-2.0 * x);
119             x += 1.0;
120             p.px[2] = (0.5 * x * x - 1.5 * x + 1.125);
121             p.gx[2] = (x - 1.5);
122  
123             y = p.cy - p.y;
124             p.py[0] = (0.5 * y * y + 1.5 * y + 1.125);
125             p.gy[0] = (y + 1.5);
126             y += 1.0;
127             p.py[1] = (-y * y + 0.75);
128             p.gy[1] = (-2.0 * y);
129             y += 1.0;
130             p.py[2] = (0.5 * y * y - 1.5 * y + 1.125);
131             p.gy[2] = (y - 1.5);
132  
133             for (var i = 0; i < 3; i++)
134             {
135                 for (var j = 0; j < 3; j++)
136                 {
137                     var n = this.grid[p.cx + i][p.cy + j];
138                     if (!n.active)
139                     {
140                         this.active.push(n);
141                         n.active = true;
142                     }
143                     phi = p.px[i] * p.py[j];
144                     n.m += phi * p.mat.m;
145                     n.d += phi;
146                     n.gx += p.gx[i] * p.py[j];
147                     n.gy += p.px[i] * p.gy[j];
148                 }
149             }
150         }
151  
152         var density, pressure, weight;
153         var n01, n02;
154         var n11, n12;
155         var cx, cy;
156         var cxi, cyi;
157  
158         var pdx, pdy;
159         var C20, C02, C30, C03;
160         var csum1, csum2;
161         var C21, C31, C12, C13, C11;
162  
163         var u, u2, u3;
164         var v, v2, v3;
165  
166         for (var pi in this.particles)
167         {
168             var p = this.particles[pi];
169  
170             cx = parseInt(p.x);
171             cy = parseInt(p.y);
172             cxi = cx + 1;
173             cyi = cy + 1;
174  
175             n01 = this.grid[cx][cy];
176             n02 = this.grid[cx][cyi];
177             n11 = this.grid[cxi][cy];
178             n12 = this.grid[cxi][cyi];
179  
180             pdx = n11.d - n01.d;
181             pdy = n02.d - n01.d;
182             C20 = 3.0 * pdx - n11.gx - 2.0 * n01.gx;
183             C02 = 3.0 * pdy - n02.gy - 2.0 * n01.gy;
184             C30 = -2.0 * pdx + n11.gx + n01.gx;
185             C03 = -2.0 * pdy + n02.gy + n01.gy;
186             csum1 = n01.d + n01.gy + C02 + C03;
187             csum2 = n01.d + n01.gx + C20 + C30;
188             C21 = 3.0 * n12.d - 2.0 * n02.gx - n12.gx - 3.0 * csum1 - C20;
189             C31 = -2.0 * n12.d + n02.gx + n12.gx + 2.0 * csum1 - C30;
190             C12 = 3.0 * n12.d - 2.0 * n11.gy - n12.gy - 3.0 * csum2 - C02;
191             C13 = -2.0 * n12.d + n11.gy + n12.gy + 2.0 * csum2 - C03;
192             C11 = n02.gx - C13 - C12 - n01.gx;
193  
194             u = p.x - cx;
195             u2 = u * u;
196             u3 = u * u2;
197             v = p.y - cy;
198             v2 = v * v;
199             v3 = v * v2;
200             density = n01.d + n01.gx * u + n01.gy * v + C20 * u2 + C02 * v2 + C30 * u3 + C03 * v3 + C21 * u2 * v + C31 * u3 * v + C12 * u * v2 + C13 * u * v3 + C11 * u * v;
201  
202             pressure = density - 1.0;
203             if (pressure > 2.0)
204                 pressure = 2.0;
205  
206             fx = 0.0;
207             fy = 0.0;
208  
209             if (p.x < 4.0)
210                 fx += p.mat.m * (4.0 - p.x);
211             else if (p.x > this.gsizeX - 5)
212                 fx += p.mat.m * (this.gsizeX - 5 - p.x);
213  
214             if (p.y < 4.0)
215                 fy += p.mat.m * (4.0 - p.y);
216             else if (p.y > this.gsizeY - 5)
217                 fy += p.mat.m * (this.gsizeY - 5 - p.y);
218  
219             if (drag)
220             {
221                 var vx = Math.abs(p.x - 0.25 * this.mx);
222                 var vy = Math.abs(p.y - 0.25 * this.my);
223                 if ((vx < 10.0) && (vy < 10.0))
224                 {
225                     weight = p.mat.m * (1.0 - vx * 0.10) * (1.0 - vy * 0.10);
226                     fx += weight * (mdx - p.u);
227                     fy += weight * (mdy - p.v);
228                 }
229             }
230  
231             for (i = 0; i < 3; i++)
232             {
233                 for (j = 0; j < 3; j++)
234                 {
235                     n = this.grid[(p.cx + i)][(p.cy + j)];
236                     phi = p.px[i] * p.py[j];
237                     n.ax += -((p.gx[i] * p.py[j]) * pressure) + fx * phi;
238                     n.ay += -((p.px[i] * p.gy[j]) * pressure) + fy * phi;
239                 }
240             }
241         }
242  
243         for (var ni in this.active)
244         {
245             var n = this.active[ni];
246             if (n.m > 0.0)
247             {
248                 n.ax /= n.m;
249                 n.ay /= n.m;
250                 n.ay += 0.03;
251             }
252         }
253  
254         var mu, mv;
255         for (var pi in this.particles)
256         {
257             var p = this.particles[pi];
258             for (i = 0; i < 3; i++)
259             {
260                 for (j = 0; j < 3; j++)
261                 {
262                     n = this.grid[(p.cx + i)][(p.cy + j)];
263                     phi = p.px[i] * p.py[j];
264                     p.u += phi * n.ax;
265                     p.v += phi * n.ay;
266                 }
267             }
268             mu = p.mat.m * p.u;
269             mv = p.mat.m * p.v;
270             for (i = 0; i < 3; i++)
271             {
272                 for (j = 0; j < 3; j++)
273                 {
274                     n = this.grid[(p.cx + i)][(p.cy + j)];
275                     phi = p.px[i] * p.py[j];
276                     n.u += phi * mu;
277                     n.v += phi * mv;
278                 }
279             }
280         }
281  
282         for (var ni in this.active)
283         {
284             var n = this.active[ni];
285             if (n.m > 0.0)
286             {
287                 n.u /= n.m;
288                 n.v /= n.m;
289             }
290         }
291  
292         var gu, gv;
293         for (var pi in this.particles)
294         {
295             var p = this.particles[pi];
296             gu = 0.0;
297             gv = 0.0;
298             for (var i = 0; i < 3; i++)
299             {
300                 for (var j = 0; j < 3; j++)
301                 {
302                     var n = this.grid[(p.cx + i)][(p.cy + j)];
303                     phi = p.px[i] * p.py[j];
304                     gu += phi * n.u;
305                     gv += phi * n.v;
306                 }
307             }
308             p.x += gu;
309             p.y += gv;
310             p.u += 1.0 * (gu - p.u);
311             p.v += 1.0 * (gv - p.v);
312             if (p.x < 1.0)
313             {
314                 p.x = (1.0 + Math.random() * 0.01);
315                 p.u = 0.0;
316             }
317             else if (p.x > this.gsizeX - 2)
318             {
319                 p.x = (this.gsizeX - 2 - Math.random() * 0.01);
320                 p.u = 0.0;
321             }
322             if (p.y < 1.0)
323             {
324                 p.y = (1.0 + Math.random() * 0.01);
325                 p.v = 0.0;
326             }
327             else if (p.y > this.gsizeY - 2)
328             {
329                 p.y = (this.gsizeY - 2 - Math.random() * 0.01);
330                 p.v = 0.0;
331             }
332         }
333     }
334  
335     this.init();
336 }
337  
338 function Node()
339 {
340     this.m = 0;
341     this.d = 0;
342     this.gx = 0;
343     this.gy = 0;
344     this.u = 0;
345     this.v = 0;
346     this.ax = 0;
347     this.ay = 0;
348     this.active = false;
349    
350     this.clear = function()
351     {
352         this.m = this.d = this.gx = this.gy = this.u = this.v = this.ax = this.ay = 0.0;
353         this.active = false;
354     }
355 }
356  
357 function Particle(mat, x, y, u, v)
358 {
359     this.mat = mat;
360     this.x = x;
361     this.y = y;
362     this.u = u;
363     this.v = v;
364  
365     this.dudx = 0;
366     this.dudy = 0;
367     this.dvdx = 0;
368     this.dvdy = 0;
369     this.cx = 0;
370     this.cy = 0;
371  
372     this.px = [0,0,0];
373     this.py = [0,0,0];
374     this.gx = [0,0,0];
375     this.gy = [0,0,0];
376 }
377  
378 function Material(m, rd, k, v, d, g)
379 {
380     this.m = m;
381     this.rd = rd;
382     this.k = k;
383     this.v = v;
384     this.d = d;
385     this.g = g;
386 }
387  
388 function line(x1,y1,x2,y2) {
389     context.moveTo(x1,y1);
390     context.lineTo(x2,y2);
391 }
392  
393 function getPosition(obj) {
394     var p = obj.offsetParent;
395     var left = obj.offsetLeft;
396     var top = obj.offsetTop;
397     if (p) {
398         var pos = getPosition(p);
399         left += pos[0];
400         top += pos[1];
401     }
402     return [left, top];
403 }
404  
405 function mouseMoved(event)
406 {
407     var pos = getPosition(canvas);
408     liquidTest.mx = event.pageX - pos[0];
409     liquidTest.my = event.pageY - pos[1];
410 }
411  
412 function mousePressed(event)
413 {
414     liquidTest.pressed = true;
415 }
416  
417 function mouseReleased(event)
418 {
419     liquidTest.pressed = false;
420 }
421  
422 function stop()
423 {
424     running = false;
425 }
426  
427 function start()
428 {
429     running = true;
430     draw();
431 }
432  
433 function restart(gsizeX, gsizeY, particlesX, particlesY)
434 {
435     liquidTest = new LiquidTest(gsizeX, gsizeY, particlesX, particlesY);
436     running = true;
437     draw();
438 }
439  
440 function draw()
441 {
442     // clear
443  
444     // advance simulation
445     liquidTest.simulate();
446  
447     step ++;
448 }
449  
450 function init() {
451     canvas = document.getElementById('liquid');
452     width = canvas.width;
453     height = canvas.height;
454     context = canvas.getContext('2d');
455     context.strokeStyle = "#0000FF";
456  
457     canvas.onmousedown = mousePressed;
458     canvas.onmouseup = mouseReleased;
459     canvas.onmousemove = mouseMoved;
460  
461     liquidTest = new LiquidTest(100, 100, 50, 50);
462  
463     start();
464 }
465  
466 setInterval(draw, 33);
467 setInterval("liquidTest.paint()", 33);
468  
469 init();
470 </script>

HTML5 canvas流体力学效果的更多相关文章

  1. HTML5 Canvas动画效果演示

    HTML5 Canvas动画效果演示 主要思想: 首先要准备一张有连续帧的图片,然后利用HTML5 Canvas的draw方法在不同的时间 间隔绘制不同的帧,这样看起来就像动画在播放. 关键技术点: ...

  2. HTML5 Canvas动画效果演示 - 流浪的鱼 - 博客频道 - CSDN.NET

    HTML5 Canvas动画效果演示 - 流浪的鱼 - 博客频道 - CSDN.NET HTML5 Canvas动画效果演示

  3. HTML5 Canvas动画效果实现原理

    在线演示 使用HTML5画布可以帮助我们高速实现简单的动画效果.基本原理例如以下: 每隔一定时间绘制图形而且清除图形,用来模拟出一个动画过程,能够使用context.clearRect(0, 0, x ...

  4. 7个惊艳的HTML5 Canvas动画效果及源码

    HTML5非常强大,尤其是现在大部分浏览器都支持HTML5和CSS3,用HTML5制作的动画也多了起来.另外,Canvas上绘制图形非常简单,本文就分享了一些强大的HTML5 Cnavas动画,一起来 ...

  5. 基于HTML5 Canvas粒子效果文字动画特效

    之前我们分享过很多超酷的文字特效,其中也有利用HTML5和CSS3的.今天我们要来分享一款基于HTML5 Canvas的文字特效,输入框中输入想要展示的文字,回车后即可在canvas上绘制出粒子效果的 ...

  6. HTML5 Canvas时间效果

    Canvas 时间效果: function clockTest() { var canvas = document.getElementById('canvas'); if (!(canvas &am ...

  7. HTML5 Canvas 超炫酷烟花绽放动画教程

    这是一个很酷的HTML5 Canvas动画,它将模拟的是我们现实生活中烟花绽放的动画特效,效果非常逼真,但是毕竟是电脑模拟,带女朋友看就算了,效果还是差了点,呵呵.这个HTML5 Canvas动画有一 ...

  8. html5 canvas首屏自适应背景动画循环效果代码

    模板描述:html5 canvas首屏自适应背景动画循环效果代码 由于动态图太大,怕以后服务器受不了,所以现在都改为静态图了,大家点击演示地址一样的,希望大家喜欢,你们的支持就是小海的动力!! 欢迎大 ...

  9. HTML5 Canvas 实现的9个 Loading 效果

    Sonic.js 是一个很小的 JavaScript 类,用于创建基于 HTML5 画布的加载图像.更强大的是 Sonic.js 还提供了基于现成的例子的创建工具,可以帮助你实现更多自定义的(Load ...

随机推荐

  1. Phpstudy2018 集成环境配置虚拟域名访问到Index Of 下

    (1)    Phpstudy是一款php集成开发环境 可随意切换Php的版本以及服务器. Phpstudy的网站根目录默认为WWW目录,那么如果我们想通过虚拟域名访问到Index Of目录来便于查看 ...

  2. Python的scrapy之爬取妹子图片

    闲来无事,做的一个小爬虫项目 爬虫主程序: import scrapy from ..items import MeiziItem class MztSpider(scrapy.Spider): na ...

  3. mysql日志管理#慢日志详解

    MySQL的慢查询日志是MySQL提供的一种日志记录,它用来记录在MySQL中响应时间超过阀值的语句,具体指运行时间超过long_query_time值的SQL,则会被记录到慢查询日志中 long_q ...

  4. PHP中的面向对象魔术方法大全

    1.__construct  构造方法 2.__destruct  析构方法 3.__get 获取成员值 4.__set 设定成员值 5.__isset 判断成员值 6.__unset unset成员 ...

  5. java 第五章 方法定义及调用

    1.方法的定义 什么是方法 方法是完成某个功能的一组语句,通常将常用的功能写成一个方法 方法的定义 [访问控制符] [修饰符] 返回值类型 方法名( (参数类型 形式参数, ,参数类型 形式参数, , ...

  6. Gradle 设置本地meaven

    repositories { maven { url uri("F:\\meaven")} }

  7. IAR工程名修改

    修改.dep..ewd..ewp..eww四个文件的文件名 删除.ewt文件(如果存在) 记事本打开.eww文件,修改<path></path>间的.ewp文件名 打开工程,打 ...

  8. Linux硬盘性能检测

    对于现在的计算机来讲,整个计算机的性能主要受磁盘IO速度的影响,内存.CPU包括主板总线的速度已经很快了. 基础检测方法 1.dd命令 dd命令功能很简单,就是从一个源读取数据以bit级的形式写到一个 ...

  9. 『MongoDB』集合更新操作

    参考 定义 db.collection.update(query, update, options) 改变一个在集合中已经存在的文档或文档数组.默认的,update()方法更新一个独立的文档.如果mu ...

  10. OpenCV入门:(三:图片Mask operations)

    Mask operations 翻译为中文应该是掩模操作,具体操作步骤就是根据一个操作矩阵(又名kernel)处理图片中的每一个像素点,操作矩阵会根据当前像素点的周围像素来调整当前像素值. 1.示例 ...