如何使用 HTML5 Canvas 制作水波纹效果

今天,我们继续分享 JavaScript 实现的效果例子,这篇文章会介绍使用 JavaScript 实现水波纹效果。水波效果以图片为背景,点击图片任意位置都会触发。有时候,我们使用普通的 Javascript 就可以创建一个很有趣的解决功能。


171926575774208.jpg

源码下载        在线演示


Step 1. HTML


和以前一样,首先是 HTML 代码:



  1. <!DOCTYPE html>

  2. <html>

  3.     <head>

  4.         <meta charset=utf-8 />

  5.         <title>Water drops effect</title>

  6.         <link rel="stylesheet" href="css/main.css" type="text/css" />

  7.         <script src="js/vector2d.js" type="text/javascript" charset="utf-8"></script>

  8.         <script src="js/waterfall.js" type="text/javascript" charset="utf-8"></script>

  9.     </head>

  10.     <body>

  11.         <div class="example">

  12.             <h3><a href="#">Water drops effect</a></h3>



  13.             <canvas id="water">HTML5 compliant browser required</canvas>

  14.             <div id="switcher">

  15.                 <img οnclick='watereff.changePicture(this.src);' src="data_images/underwater1.jpg" />

  16.                 <img οnclick='watereff.changePicture(this.src);' src="data_images/underwater2.jpg" />

  17.             </div>

  18.             <div id="fps"></div>

  19.         </div>

  20.     </body>

  21. </html> 
复制代码

Step 2. CSS

这是用到的 CSS 代码:

  1. body{background:#eee;margin:0;padding:0}

  2. .example{background:#FFF;width:600px;border:1px #000 solid;margin:20px auto;padding:15px;-moz-border-radius: 3px;-webkit-border-radius: 3px}



  3. #water {

  4.     width:500px;

  5.     height:400px;

  6.     display: block;

  7.     margin:0px auto;

  8.     cursor:pointer;

  9. }

  10. #switcher {

  11.     text-align:center;

  12.     overflow:hidden;

  13.     margin:15px;

  14. }

  15. #switcher img {

  16.     width:160px;

  17.     height:120px;

  18. }
复制代码

Step 3. JS

下面是主要的 JavaScript 代码:

  1. function drop(x, y, damping, shading, refraction, ctx, screenWidth, screenHeight){

  2.     this.x = x;

  3.     this.y = y;

  4.     this.shading = shading;

  5.     this.refraction = refraction;

  6.     this.bufferSize = this.x * this.y;

  7.     this.damping = damping;

  8.     this.background = ctx.getImageData(0, 0, screenWidth, screenHeight).data;

  9.     this.imageData = ctx.getImageData(0, 0, screenWidth, screenHeight);



  10.     this.buffer1 = [];

  11.     this.buffer2 = [];

  12.     for (var i = 0; i < this.bufferSize; i++){

  13.         this.buffer1.push(0);

  14.         this.buffer2.push(0);

  15.     }



  16.     this.update = function(){

  17.         for (var i = this.x + 1, x = 1; i < this.bufferSize - this.x; i++, x++){

  18.             if ((x < this.x)){

  19.                 this.buffer2[i] = ((this.buffer1[i - 1] + this.buffer1[i + 1] + this.buffer1[i - this.x] + this.buffer1[i + this.x]) / 2) - this.buffer2[i];

  20.                 this.buffer2[i] *= this.damping;

  21.             } else x = 0;

  22.         }



  23.         var temp = this.buffer1;

  24.         this.buffer1 = this.buffer2;

  25.         this.buffer2 = temp;

  26.     }



  27.     this.draw = function(ctx){

  28.         var imageDataArray = this.imageData.data;

  29.         for (var i = this.x + 1, index = (this.x + 1) * 4; i < this.bufferSize - (1 + this.x); i++, index += 4){

  30.             var xOffset = ~~(this.buffer1[i - 1] - this.buffer1[i + 1]);

  31.             var yOffset = ~~(this.buffer1[i - this.x] - this.buffer1[i + this.x]);

  32.             var shade = xOffset * this.shading;

  33.             var texture = index + (xOffset * this.refraction  + yOffset * this.refraction * this.x) * 4;

  34.             imageDataArray[index] = this.background[texture] + shade; 

  35.             imageDataArray[index + 1] = this.background[texture + 1] + shade;

  36.             imageDataArray[index + 2] = 50 + this.background[texture + 2] + shade;

  37.         }

  38.         ctx.putImageData(this.imageData, 0, 0);

  39.     }

  40. }



  41. var fps = 0;



  42. var watereff = {

  43.     // variables

  44.     timeStep : 20,

  45.     refractions : 2,

  46.     shading : 3,

  47.     damping : 0.99,

  48.     screenWidth : 500,

  49.     screenHeight : 400,

  50.     pond : null,

  51.     textureImg : null,

  52.     interval : null,

  53.     backgroundURL : 'data_images/underwater1.jpg',



  54.     // initialization

  55.     init : function() {

  56.         var canvas = document.getElementById('water');

  57.         if (canvas.getContext){



  58.             // fps countrt

  59.             fps = 0;

  60.             setInterval(function() { 

  61.                 document.getElementById('fps').innerHTML = fps / 2 + ' FPS'; 

  62.                 fps = 0;

  63.             }, 2000);



  64.             canvas.onmousedown = function(e) {

  65.                 var mouse = watereff.getMousePosition(e).sub(new vector2d(canvas.offsetLeft, canvas.offsetTop));

  66.                 watereff.pond.buffer1[mouse.y * watereff.pond.x + mouse.x ] += 200;

  67.             }

  68.             canvas.onmouseup = function(e) {

  69.                 canvas.onmousemove = null;

  70.             }



  71.             canvas.width  = this.screenWidth;

  72.             canvas.height = this.screenHeight;

  73.             this.textureImg = new Image(256, 256);

  74.             this.textureImg.src = this.backgroundURL;

  75.             canvas.getContext('2d').drawImage(this.textureImg, 0, 0);

  76.             this.pond = new drop(

  77.                 this.screenWidth, 

  78.                 this.screenHeight, 

  79.                 this.damping,

  80.                 this.shading, 

  81.                 this.refractions,

  82.                 canvas.getContext('2d'),

  83.                 this.screenWidth, this.screenHeight

  84.             );

  85.             if (this.interval != null){

  86.                 clearInterval(this.interval);

  87.             }

  88.             this.interval = setInterval(watereff.run, this.timeStep);

  89.         }

  90.     },



  91.     // change image func

  92.     changePicture : function(url){

  93.         this.backgroundURL = url;

  94.         this.init();

  95.     },



  96.     // get mouse position func

  97.     getMousePosition : function(e){

  98.         if (!e){

  99.             var e = window.event;

  100.         } 

  101.         if (e.pageX || e.pageY){

  102.             return new vector2d(e.pageX, e.pageY);

  103.         } else if (e.clientX || e.clientY){

  104.             return new vector2d(e.clientX, e.clientY);

  105.         } 

  106.     },



  107.     // loop drawing

  108.     run : function(){

  109.         var ctx = document.getElementById('water').getContext('2d');

  110.         watereff.pond.update();

  111.         watereff.pond.draw(ctx);

  112.         fps++;

  113.     }

  114. }



  115. window.onload = function(){

  116.     watereff.init();

  117. }
复制代码

正如你所看到的,这里使用 Vector2D 函数,这个函数在 vector2d.js 里提供了。另一个很难的方法是使用纯数学实现,感兴趣的可以自己实验一下。


171926575774208.jpg
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值