春天,陪你一起去赏雨——HTML5下雨效果

http://blog.csdn.net/qingfeilee/article/details/7394735

 不知从什么时候我们已经没有了淋雨的勇气、不知从什么时候我们已经不敢享受雨水的甘甜、不知从什么时候我们感受不到那雨声的清脆。桃花已开但我们却嗅不到他的清香、春雨已来但我们却想方设法将其遮挡、湖水已涨但我们却失去了赏鱼的闲情雅致。时光让我们学到了很多、时光也让我们失去了很多。成天奔波的我们从来不舍得停下脚步,因为今天的我们已经意识到了一寸光阴一寸金的真正内涵。为了冰箱里的那块面包,我们每天就这样奔波着、忙碌着......

    停止牢骚,言归正题。

    这篇blog描写的是一个动态水波的效果,主要是通过HTML5里面的canvas来实现。整片文章属于原创若有相同纯属有缘,但是里面的核心水波原理并非本人原创是参考网上很多关于水波原理进行综合而成,所以在这里要谢谢网上那些贡献知识的人。闲话少说,先看实现的效果如图一:


图一

       考虑到性能问题,建议图片不要太大,本例子用400*300的图片在chrome和firefox下还算流畅,但是safari相对较卡。把图片扩大2倍至800*600就比较卡,效果不是很好。下面将代码贴出共大家一起交流学习。

[javascript]  view plain copy
  1. <pre name="code" class="html"><!DOCTYPE html>  
  2. <html>  
  3.     <head>  
  4.         <meta charset="utf-8" />  
  5.         <title>春天,陪你一起去赏雨——HTML5下雨效果</title>  
  6.         <style type="text/css">  
  7.             #box{   
  8.                 border:2px solid #f60; margin:0 auto;  
  9.             }  
  10.         </style>  
  11.         <script>  
  12.             var floor = Math.floor;//向下取整  
  13.             var canvas;//画布  
  14.             var context;//画布上下文  
  15.             var width;//背景图片、画布宽  
  16.             var height;//背景图片、画布宽  
  17.             var size;//像素点个数、width*height  
  18.             var nextPoint = [];//下一振幅  
  19.             var prePoint = [];//上一振幅  
  20.             var tempPoint = [];//临时存储  
  21.             var imgData;//背景图片数据  
  22.             var speed = 100;//下雨大小,默认是一秒钟一个雨滴  
  23.             var weight = 1000;//雨滴的大小  
  24.             /** 
  25.                 author:qingfeilee 
  26.                 date:2012-03-24 
  27.                 description:开始启动程序 
  28.             **/  
  29.             function start() {  
  30.                 initImage("background.jpg");  
  31.             }  
  32.             /** 
  33.                 author:qingfeilee 
  34.                 date:2012-03-24 
  35.                 description:初始化图片信息 
  36.             **/  
  37.             function initImage(src) {  
  38.                 var img = new Image();  
  39.                 img.src = src;  
  40.                 img.onload = function() {  
  41.                     init(img);  
  42.                 };  
  43.             }  
  44.             /** 
  45.                 author:qingfeilee 
  46.                 date:2012-03-24 
  47.                 description:初始化系统函数 
  48.             **/  
  49.             function init(img){  
  50.                     initSize(img);  
  51.                     initPoint();  
  52.                     initCanvas();  
  53.                     loadImage(img);  
  54.             }  
  55.             /** 
  56.                 author:qingfeilee 
  57.                 date:2012-03-24 
  58.                 description:绘制图片函数 
  59.             **/  
  60.             function loadImage(img){  
  61.                 context.drawImage(img, 0, 0);  
  62.                 imgData = context.getImageData(0, 0, width, height);  
  63.                 setInterval(spread, 1000/60);  
  64.                 setInterval(rain, speed);  
  65.             }  
  66.             /** 
  67.                 author:qingfeilee 
  68.                 date:2012-03-24 
  69.                 description:初始化画布信息 
  70.             **/  
  71.             function initCanvas(){  
  72.                 canvas = document.getElementById('ripper');  
  73.                 context =canvas.getContext('2d');  
  74.                 canvas.width = width;  
  75.                 canvas.height = height;  
  76.                 canvas.onclick = function(e) {  
  77.                     setDropPoint(floor(e.clientX-(document.body.clientWidth  - width)/2), floor(e.clientY - (document.body.clientHeight  - height) / 2), 15000);  
  78.                 }  
  79.             }  
  80.             /** 
  81.                 author:qingfeilee 
  82.                 date:2012-03-24 
  83.                 description:设置画布宽高及画布像素数 
  84.             **/  
  85.             function initSize(img){  
  86.                 width = img.width;  
  87.                 height = img.height;  
  88.                 document.getElementById("box").style.width = width+"px";  
  89.                 document.getElementById("box").style.height = height+"px";  
  90.                 size = width*height;  
  91.             }  
  92.             /** 
  93.                 author:qingfeilee 
  94.                 date:2012-03-24 
  95.                 description:初始化存储图像前一个和后一个点的数组 
  96.             **/  
  97.             function initPoint(){  
  98.                 for (var i = 0; i < size; i++) {  
  99.                     nextPoint.push(0);  
  100.                     prePoint.push(0);  
  101.                 }                 
  102.             }  
  103.             /** 
  104.                 author:qingfeilee 
  105.                 date:2012-03-24 
  106.                 description:一石激起千层浪,设置波动点及注入的能量 
  107.                             其中x表示物体进入水面的X坐标,Y表示物体进入水面的Y坐标,power表示物体的能量大小 
  108.             **/  
  109.             function setDropPoint(x, y, power) {  
  110.                 if (x < 2 || x > width - 2 || y < 1 || y > height - 2) return;  
  111.                 var i = x + y * width;  
  112.                 nextPoint[i] += power;  
  113.                 nextPoint[i - 1] -= power;  
  114.             }  
  115.             /** 
  116.                 author:qingfeilee 
  117.                 date:2012-03-24 
  118.                 description:核心算法,处理像素的波动效果 
  119.                 PS:该算法非原创,借鉴网络上多个版本算法综合 
  120.             **/  
  121.             function spread() {  
  122.                 var img = context.getImageData(0, 0, width, height),  
  123.                 data = img.data;  
  124.                 //平均一下各个点的能量  
  125.                 for (var i = width + 1; i < size - width - 1; i += 2) {  
  126.                     for (var x = 1; x < width - 1; x++, i++) {  
  127.                         nextPoint[i] = (nextPoint[i] + nextPoint[i + 1] + nextPoint[i - 1] + nextPoint[i - width] + nextPoint[i + width]) / 5;  
  128.                     }  
  129.                 }  
  130.                 //渲染除了第一行、最后一行、第一列、最后一列外的所有点  
  131.                 for (var i = width + 1; i < size - width - 1; i += 2) {  
  132.                     for (var x = 1; x < width - 1; x++, i++) {  
  133.                         //水波振幅线性公式参考的是网络上的一些研究文献得出的  
  134.                         prePoint[i] = (nextPoint[i - 1] + nextPoint[i + 1] + nextPoint[i + width] + nextPoint[i - width])/2 - prePoint[i];  
  135.                         var ti = i + floor((prePoint[i - 2] - prePoint[i]) * 0.08) + floor((prePoint[i - width] - prePoint[i]) * 0.08) * width;  
  136.                         ti = ti < 0 ? 0 : ti > size ? size: ti;  
  137.                         var light = prePoint[i] * 2.0 - prePoint[i - 2] * 0.6;  
  138.                         light = light < -10 ? -10 : light > 100 ? 100 : light;  
  139.                         //之所以是i*4是因为canvas获取的data数据每四个值表示一个像素包括分别是红/绿/蓝/透明,要想了解更多关于canvas的请参看我的另一篇blog:http://blog.csdn.net/qingfeilee/article/details/7233683  
  140.                         data[i * 4] = imgData.data[ti * 4] + light;  
  141.                         data[i * 4 + 1] = imgData.data[ti * 4 + 1] + light;  
  142.                         data[i * 4 + 2] = imgData.data[ti * 4 + 2] + light;  
  143.                         //波能渐渐衰减  
  144.                         prePoint[i] -= prePoint[i]>>5;  
  145.                     }  
  146.                 }  
  147.                 tempPoint = nextPoint;  
  148.                 nextPoint = prePoint;  
  149.                 prePoint = tempPoint;  
  150.                 context.putImageData(img, 0, 0);  
  151.             }  
  152.               
  153.             function rain(){  
  154.                 setDropPoint(floor(Math.random()*width), floor(Math.random()*height), floor(Math.random()*weight));  
  155.             }  
  156.             function setWeight(weight){  
  157.                 this.weight = weight;  
  158.             }  
  159.               
  160.             window.addEventListener("load", start, true);  
  161.         </script>  
  162.           
  163.     </head>  
  164.       
  165.     <body>  
  166.         <div id="box">  
  167.             <canvas id="ripper" style="width:100%;height:100%; "></canvas>  
  168.             <div align="center">  
  169.             <button onclick = "setWeight('1000')">小雨</button>  
  170.             <button onclick = "setWeight('10000')">中雨</button>  
  171.             <button onclick = "setWeight('20000')">大雨</button>  
  172.               
  173.         </div>  
  174.         </div>  
  175.         <div><h5 style = "text-align:center"><a href = 'http://blog.csdn.net/qingfeilee/'>阿飞blog</a></h5></div>  
  176.         </div>  
  177.     </body>  
  178.   
  179. </html>  


 

       核心算法的解释,在我们利用这个水波原理解析图像的时候我们只需要获取除了第一行、最后一行、第一列、最后一列的像素点即可,如图二:

图二

本Demo中还需要一张背景图片,注:图片不能太大、否则画面将比较不流畅。本文的背景图片如图三:

图三

       由代码注释较详细,具体就不再赘述。倘若对Canvas不太了解希望我的另外一篇blog《通过小画板认识Canvas》能够帮助到你。哪位大牛有好的算法实现希望能够多多交流,共同学习,共同进步,欢迎拍砖哭
    本文乃原创Demo,转载请注明出处:http://blog.csdn.net/qingfeilee/article/details/7394735  使用代码请保留作者署名,O(∩_∩)O谢谢
     备注:本代码直接在chrome和firefox下面运行无法运行需要放到服务器里通过http://ip的形式来访问才行,safari可以直接访问但是运行效率较低。之所以前两者不能直接运行的,是因为chrome和firefox两家浏览器的安全策略所致getImageData()不能获取图片数据的原因,但是通过网络即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值