在codepen上看到一个Canvas作的下雨效果动画,感受蛮有意思的。就研究了下,这里来分享下,实现技巧。效果能够见下面的连接。javascript
霓虹雨: http://codepen.io/natewiley/full/NNgqVJ/css
效果截图:html
你们都知道,Canvas其实只是一个画板。咱们能够应用canvas的api在上面绘制各类图形。
Canvas 2D 的API:
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2Djava
那么Canvas绘制动画的步骤就是:web
绘制第一帧图形(利用API绘图)canvas
清空画板(应用clearRect()或fillRect())api
绘制下一帧动画浏览器
用什么来控制动画每一帧的绘制时间呢?你们很容易想到 window.setInterval()和window.setTimeout()。没错用这两个也能够。除此以外,后来又出现一个新的方法:window.requestAnimationFrame(callback)。dom
requestAnimationFrame会告诉浏览器你要绘制一个动画。让浏览器要重绘时调用你指定的方法(callback)来绘制你的动画。
使用方法以下:动画
function anim() { ctx.fillStyle = clearColor; ctx.fillRect(0,0,w,h); for(var i in drops){ drops[i].draw(); } requestAnimationFrame(anim); }
通常状况下优先使用requestAnimationFrame能保持动画绘制的频率和浏览器重绘的频率一致。不幸的是requestAnimationFrame的兼容性还不是很好。IE9如下和addroid 4.3如下好像不支持这个属性。不支持的浏览器要用setInterval或setTimeout作兼容。
首先来说讲雨滴下落的效果如何制做。雨滴实际上是一个长方形,而后加残影。残影的绘制能够说是雨滴下落的关键。残影是经过在前进的方向每一帧都绘制一个半透明的背景和一个长方形,而后前面绘制的图形叠加产生的效果。因为前进方向的图形最后绘制,因此显得明亮,后面的图形叠加的比较多,因此视觉上减弱。总体看起来后面的就像残影。这里绘制具备透明度背景是关键,不然产生不了叠加效果。
那么来绘制个雨滴看看。首先准备一个画板:
html代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>霓虹雨</title> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <style type="text/css"> .bg { background: #000; overflow: hidden; } </style> </head> <body class="bg"> <canvas id="canvas-club"></canvas> <script type="text/javascript" src="raindrop.js"></script> </body> </html>
我在js文件里绘制动画(raindrop.js),代码以下:
var c = document.getElementById("canvas-club"); var ctx = c.getContext("2d");//获取canvas上下文 var w = c.width = window.innerWidth; var h = c.height = window.innerHeight;//设置canvas宽、高 var clearColor = 'rgba(0, 0, 0, .1)';//画板背景,注意最后的透明度0.1 这是产生叠加效果的基础 function random(min, max) { return Math.random() * (max - min) + min; } function RainDrop(){} //雨滴对象 这是绘制雨滴动画的关键 RainDrop.prototype = { init:function(){ this.x = random(0, w);//雨滴的位置x this.y = 0;//雨滴的位置y this.color = 'hsl(180, 100%, 50%)';//雨滴颜色 长方形的填充色 this.vy = random(4, 5);//雨滴下落速度 this.hit = random(h * .8, h * .9);//下落的最大值 this.size = 2;//长方形宽度 }, draw:function(){ if (this.y < this.hit) { ctx.fillStyle = this.color; ctx.fillRect(this.x, this.y, this.size, this.size * 5);//绘制长方形,经过屡次叠加长方形,造成雨滴下落效果 } this.update();//更新位置 }, update:function(){ if(this.y < this.hit){ this.y += this.vy;//未达到底部,增长雨滴y坐标 }else{ this.init(); } } }; function resize(){ w = c.width = window.innerWidth; h = c.height = window.innerHeight; } //初始化一个雨滴 var r = new RainDrop(); r.init(); function anim() { ctx.fillStyle = clearColor;//每一帧都填充背景色 ctx.fillRect(0,0,w,h);//填充背景色,注意不要用clearRect,不然会清空前面的雨滴,致使不能产生叠加的效果 r.draw();//绘制雨滴 requestAnimationFrame(anim);//控制动画帧 } window.addEventListener("resize", resize); //启动动画 anim();
接着来绘制涟漪效果。与绘制雨滴的方式相似,也是经过具备透明度的背景来叠加前面的图像产生内阴影的效果。
代码以下(rippling.js):
var c = document.getElementById("canvas-club"); var ctx = c.getContext("2d");//获取canvas上下文 var w = c.width = window.innerWidth; var h = c.height = window.innerHeight;//设置canvas宽、高 var clearColor = 'rgba(0, 0, 0, .1)';//画板背景,注意最后的透明度0.1 这是产生叠加效果的基础 function random(min, max) { return Math.random() * (max - min) + min; } function Rippling(){} //涟漪对象 这是涟漪动画的主要部分 Rippling.prototype = { init:function(){ this.x = random(0,w);//涟漪x坐标 this.y = random(h * .8, h * .9);//涟漪y坐标 this.w = 2;//椭圆形涟漪宽 this.h = 1;//椭圆涟漪高 this.vw = 3;//宽度增加速度 this.vh = 1;//高度增加速度 this.a = 1;//透明度 this.va = .96;//涟漪消失的渐变速度 }, draw:function(){ ctx.beginPath(); ctx.moveTo(this.x, this.y - this.h / 2); //绘制右弧线 ctx.bezierCurveTo( this.x + this.w / 2, this.y - this.h / 2, this.x + this.w / 2, this.y + this.h / 2, this.x, this.y + this.h / 2); //绘制左弧线 ctx.bezierCurveTo( this.x - this.w / 2, this.y + this.h / 2, this.x - this.w / 2, this.y - this.h / 2, this.x, this.y - this.h / 2); ctx.strokeStyle = 'hsla(180, 100%, 50%, '+this.a+')'; ctx.stroke(); ctx.closePath(); this.update();//更新坐标 }, update:function(){ if(this.a > .03){ this.w += this.vw;//宽度增加 this.h += this.vh;//高度增加 if(this.w > 100){ this.a *= this.va;//当宽度超过100,涟漪逐渐变淡消失 this.vw *= .98;//宽度增加变缓慢 this.vh *= .98;//高度增加变缓慢 } } else { this.init(); } } }; function resize(){ w = c.width = window.innerWidth; h = c.height = window.innerHeight; } //初始化一个涟漪 var r = new Rippling(); r.init(); function anim() { ctx.fillStyle = clearColor; ctx.fillRect(0,0,w,h); r.draw(); requestAnimationFrame(anim); } window.addEventListener("resize", resize); //启动动画 anim();
这样你们对整个下雨效果的制做方法,应该有必定的了解了。Canvas用来绘制动画的效果确实能让人眼前一亮,让web的视觉效果提高一大截。发动本身的智慧,相信能作出更多奇妙的动画。这是我愈来愈喜欢web的缘由之一吧 O(∩_∩)O~~。