JavaScript模拟流体效果

 把现实世界当中的物体模拟到计算机当中,一些简单的物理实验、碰撞旋转等等难度还是不算很大,难度较大的应当算流体模拟。

  本文将在Canvas当中模拟出一个2D平面内的水珠,涉及的知识点和技巧包括:Jscex基础知识,贝塞尔曲线的绘制,合理利用CanvasRenderingContext2D的translate和rotate等API。

  绘制椭圆

  在模拟水滴之前,我们先思考一下怎么在canvas当中绘制一个椭圆。

  大家可以很容易想到 下面几种方案:

  1.根据椭圆笛卡尔坐标系方程绘制

  2.根据椭圆极坐标方程绘制

  3.根据椭圆曲率变化绘制

  4.利用四条贝塞尔曲线绘制

  第四中,也是性能最好的一种,这样可以避免复杂的计算,充分利用CanvasRenderingContext2D的API(API的性能是通过严格测试,一般情况下比较靠谱).

  所以我们采用第四种方式来绘制椭圆。

var canvas;
         var ctx;
         canvas = document.getElementById("myCanvas1");
         ctx = canvas.getContext("2d");
         ctx.strokeStyle = "#fff";
         function drawEllipse(x, y, w, h) {
             var k = 0.5522848;
             var ox = (w / 2) * k;
             var oy = (h / 2) * k;
             var xe = x + w;
             var ye = y + h;
             var xm = x + w / 2;
             var ym = y + h / 2;
             ctx.beginPath();
             ctx.moveTo(x, ym);
             ctx.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);
             ctx.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);
             ctx.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);
             ctx.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);
             ctx.stroke();
         }
         ctx.clearRect(0,0,canvas.width,canvas.height);
         drawEllipse(10, 10, 40, 82);

  (改变drawEllipse的四个参数试试)

  旋转椭圆

  这里的旋转不是绕上面的drawEllipse的前两个参数x,y旋转,二是绕椭圆的中心旋转。所以仅仅CanvasRenderingContext2D.rotate是不够的,因为CanvasRenderingContext2D.rotate是绕画布的左上角(0,0)旋转。所以我们先要把(0,0)通过CanvasRenderingContext2D.translate到椭圆的中心,然后再drawEllipse(-a/2, –b/2, a, b).

  上面这句话,就是绕中心旋转的核心。这里还可以推广到任意图形或者图片(假设有约定的中心)。如图:

  然后我们就可以先绘制一个鸟巢出来:

<html>
<head>
     <script src="http://files.cnblogs.com/iamzhanglei/jscex.jscexRequire.min.js" type="text/javascript"></script>
</head>
<body>

<style type="text/css">

    input.css3btn

    {

        background: -moz-linear-gradient(270deg, #d2ebf8, #0c8ab5);

        background: -webkit-linear-gradient(top, #d2ebf8, #0c8ab5);

        background: -o-linear-gradient(top, #d2ebf8, #0c8ab5);

        filter: progid:DXImageTransform.Microsoft.Gradient(GradientType=0, StartColorStr='#000099CC', EndColorStr='#FF0087B4');

        border-top: 1px solid #38538c;

        border-right: 1px solid #1f2d4d;

        border-bottom: 1px solid #151e33;

        border-left: 1px solid #1f2d4d;

        border-radius: 4px;

        box-shadow: inset 0 1px 10px 1px #5c8bee, 0px 1px 0 #1d2c4d, 0 2px 0px #1f3053, 0 4px 4px 1px #111111;

        color: #f0f0f0;

        font: bold 20px "helvetica neue" , helvetica, arial, sans-serif;

        padding: 10px 0 10px 0;

        text-align: center;

        text-shadow: 0px -1px 1px #1e2d4d;

        width: 150px;

        background-clip: padding-box;

    }

    input.css3btn:hover

    {

        box-shadow: inset 0 0px 20px 1px #87adff, 0px 1px 0 #1d2c4d, 0 3px 0px #1f3053, 0 4px 4px 1px #111111;

        cursor: pointer;

    }

    input.css3btn:active

    {

        box-shadow: inset 0 1px 10px 1px #5c8bee, 0 1px 0 #1d2c4d, 0 2px 0 #1f3053, 0 4px 3px 0 #111111;

        margin-top: 1px;

    }

</style>
     <canvas id="myCanvas2" width="350" height="350" style="border: solid 15px #222; background-color: #111;

        color: #CCC;">
Your browser does not support the canvas element.
</canvas>
     <script>

        var canvas;

        var ctx;

        var px = 0;

        var py = 0;

        function init() {

            canvas = document.getElementById("myCanvas2");

            ctx = canvas.getContext("2d");

            ctx.strokeStyle = "#fff";

            ctx.translate(70, 70);

        }

        init();

        var i = 0;

        function drawEllipse(x, y, w, h) {

            var k = 0.5522848;

            var ox = (w / 2) * k;

            var oy = (h / 2) * k;

            var xe = x + w;

            var ye = y + h;

            var xm = x + w / 2;

            var ym = y + h / 2;

            ctx.beginPath();

            ctx.moveTo(x, ym);

            ctx.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);

            ctx.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);

            ctx.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);

            ctx.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);

            ctx.stroke();

            ctx.translate(x + 70, y + 100);

            px = -70;

            py = -100;

            ctx.rotate(10 * Math.PI * 2 / 360);

        }

        var ct;

        var drawAsync = eval(Jscex.compile("async", function (ct) {

            while (true) {

                drawEllipse(px, py, 140, 200)

                $await(Jscex.Async.sleep(200, ct));

            }

        }))

        function Button1_onclick() {

            ct.cancel();

        }

        function Button2_onclick() {

            ct = new Jscex.Async.CancellationToken();

            drawAsync(ct).start();

        }

    </script>
     <br />
     <input id="Button2" class="css3btn" type="button" value="run" onclick="return Button2_onclick()" />
     <input id="Button1" class="css3btn" type="button" value="stop" onclick="return Button1_onclick()" />
</body>
</html>
 

 

  绘制水滴

  旋转的椭圆和鸟巢神马的和水滴有什么关系呢?

  我们通过改变椭圆的长轴和短轴,令其非常接近圆形(只能接近,不能等于圆形),然后每次旋转擦除画布,就可以达你预想不到的效果!

  这里需要注意的是,擦除画布不再是一句CanvasRenderingContext2D.clearRect(0,0,canvas.width,canvas.height)就可以,因为画布已经旋转和画布原点已经translate,所以我们使用 ctx.clearRect(-canvas.width, -canvas.height, 2 * canvas.width, 2 * canvas.height)来擦除画布。

  我们画一个长轴42,短轴40的椭圆,旋转并擦除画布:

function drawEllipse(x, y, w, h) {

ctx.clearRect(-canvas.width, -canvas.height, 2 * canvas.width, 2 * canvas.height);

var k = 0.5522848;

var ox = (w / 2) * k;

var oy = (h / 2) * k;

var xe = x + w;

var ye = y + h;

var xm = x + w / 2;

var ym = y + h / 2;

ctx.beginPath();

ctx.moveTo(x, ym);

ctx.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);

ctx.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);

ctx.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);

ctx.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);

ctx.stroke();

ctx.translate(x + 20, y + 21);

px = -20;

py = -21;

ctx.rotate(10 * Math.PI * 2 / 360);

}

var ct;

var drawAsync = eval(Jscex.compile("async", function (ct) {

while (true) {

drawEllipse(px, py, 40, 42)

$await(Jscex.Async.sleep(10, ct));

}

}))

时间: 2024-08-31 03:29:50

JavaScript模拟流体效果的相关文章

HTML5实验:JavaScript模拟流体效果

第1页绘制椭圆 把现实世界当中的物体模拟到计算机当中,一些简单的物理实验.碰撞旋转等等难度还是不算很大,难度较大的应当算流体模拟. 本文将在Canvas当中模拟出一个2D平面内的水珠,涉及的知识点和技巧包括:Jscex基础知识,贝塞尔曲线的绘制,合理利用CanvasRenderingContext2D的translate和rotate等API. 绘制椭圆 在模拟水滴之前,我们先思考一下怎么在canvas当中绘制一个椭圆. 大家可以很容易想到 下面几种方案: 1.根据椭圆笛卡尔坐标系方程绘制 2.

javascript模拟病毒效果

问题描述 javascript模拟病毒效果 模拟病毒效果,当打开一个页面时,点击页面上有病毒按钮会不停地弹出窗口, 解决方案 javascript模拟marquee的效果JavaScript中通过鼠标事件实现模拟拖放效果 解决方案二: 用死循环不停的调用alert函数 解决方案三: 病毒效果就是打开一个页面时怎么也无法退出关闭.可以循环调用某个方法. 解决方案四: 写个递归别给出口就是了. function bingdu(){ alert("病毒攻击中!"); bingdu(); }

JavaScript模拟实现键盘打字效果

  这篇文章主要介绍了JavaScript模拟实现键盘打字效果,本文直接给出实例代码,需要的朋友可以参考下 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 $(function () {     var input_type = { init:function ($obj) { this.name = $obj.html().spl

JavaScript模拟实现键盘打字效果_javascript技巧

$(function () { var input_type = { init:function ($obj) { this.name = $obj.html().split("") this.length = this.name.length; this.i = 0; }, pri:function () { var $this = this //在此处只能使用闭包,因为windown.settimeout使函数的this指向object windown,而非原型链的this对象.而

JavaScript模拟鼠标右键菜单效果_javascript技巧

本文实例为大家分享了JavaScript模拟鼠标右键菜单的具体代码,供大家参考,具体代码如下 效果图: 具体代码: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>右键菜单</title> <style type="text/css"> *{ margin: 0; padd

javascript模拟评分控件实现方法

  本文实例讲述了javascript模拟评分控件实现方法.分享给大家供大家参考.具体实现方法如下: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 <html xmlns="http://www.w3.org/1999/xhtml">

JavaScript模拟重力状态下抛物运动的方法

 这篇文章主要介绍了JavaScript模拟重力状态下抛物运动的方法,实例分析了javascript操作dom元素模拟运动的方法,具有一定参考借鉴价值,需要的朋友可以参考下     本文实例讲述了JavaScript模拟重力状态下抛物运动的方法.分享给大家供大家参考.具体分析如下: 这段JavaScript代码模拟重力状态下的抛物运动,可设置以下参数:横向初速度.纵向初速度.重力加速度(如果这个加速度是一个随时间变化的值,就能达到其他非匀加速运动的效果了).动画间隔时间等,相对专业   代码如下

JavaScript 模拟用户单击事件_javascript技巧

一开始,我想到了用jQuery的click()事件来触发超链接的单击事件(与trigger("click")一样的效果).结果发现不如人意. 实例如下: 效果图 IE: FireFox:   复制代码 代码如下: <h3>请单击"Click Me".测试提交按钮与超链接是否也被单击了.</h3>     <button id="btn">Click Me</button>     <form

JavaScript实现打字效果的例子

网上有一个jQuery插件 Typed.js ,它可以实现模拟逐个字符输入的效果.本帖使用Js+css实现这个效果. 要输出的句子: <p id="my_string" hidden>HelloJavaScript.</p> 上面元素的属性为hidden. JavaScript: <script>     letcursor = "<span>|</span>";     letmy_str = my_st