HTML5實驗:JavaScript類比流體效果

來源:互聯網
上載者:User

         把現實世界當中的物體類比到電腦當中,一些簡單的物理實驗、碰撞旋轉等等難度還是不算很大,難度較大的應當算流體類比。

  本文將在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));

  }

  }))

  會是什麼效果呢?

  線上示範效果查看http://www.cnblogs.com/iamzhanglei/archive/2011/12/12/2284188.html

  現在大家可以看到一個晃動的水珠了,流體實驗剛剛開始,這篇只是一個起點····

文章轉載自it168

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.