简介

在codepen上看到一个Canvas做的下雨效果动画,感觉蛮有意思的。就研究了下,这里来分享下,实现技巧。效果可以见下面的链接。

霓虹雨: http://codepen.io/natewiley/full/NNgqVJ/

效果截图:

Canvas动画基础

大家都知道,Canvas其实只是一个画板。我们可以应用canvas的api在上面绘制各种图形。
Canvas 2D 的API:
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D

那么Canvas绘制动画的步骤就是:

  1. 绘制第一帧图形(利用API绘图)
  2. 清空画板(应用clearRect()或fillRect())
  3. 绘制下一帧动画

用什么来控制动画每一帧的绘制时间呢?大家很容易想到 window.setInterval()和window.setTimeout()。没错用这两个也可以。除此之外,后来又出现一个新的方法:window.requestAnimationFrame(callback)。

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~~。

转载出处:Web前端开发 » Canvas制作的下雨动画

Canvas制作的下雨动画的更多相关文章

  1. 用Canvas制作loading动画

    上一篇讲到用SVG制作loading动画,其中提到了线性渐变在扇形区域中的问题,并且用SVG SIML语法制作的loading动画并不是所有浏览器都兼容,所以现在用Canvas重新实现了一遍. 这里与 ...

  2. 使用Canvas制作时钟动画

    复习Javascript到Canvas的知识点,看到一个使用Canvas绘制的静态时钟例子,便想将其变成动态显示系统时间的时钟动画.另外再配上数字显示的时钟,一个小的时钟模块的诞生了!目前的界面还比较 ...

  3. 酷!使用 jQuery & Canvas 制作相机快门效果

    在今天的教程中,我们将使用 HTML5 的 Canvas 元素来创建一个简单的摄影作品集,它显示了一组精选照片与相机快门的效果.此功能会以一个简单的 jQuery 插件形式使用,你可以很容易地整合到任 ...

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

    今天,我们继续分享 JavaScript 实现的效果例子,这篇文章会介绍使用 JavaScript 实现水波纹效果.水波效果以图片为背景,点击图片任意位置都会触发.有时候,我们使用普通的 Javasc ...

  5. 怎样用HTML5 Canvas制作一个简单的游戏

    原文连接: How To Make A Simple HTML5 Canvas Game 自从我制作了一些HTML5游戏(例如Crypt Run)后,我收到了很多建议,要求我写一篇关于怎样利用HTML ...

  6. canvas制作原生的百分比圆形比例等

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...

  7. [译]怎样用HTML5 Canvas制作一个简单的游戏

    这是我翻译自LostDecadeGames主页的一篇文章,原文地址:How To Make A Simple HTML5 Canvas Game. 下面是正文: 自从我制作了一些HTML5游戏(例如C ...

  8. HTML5 Canvas核心技术:图形、动画与游戏开发 PDF扫描版​

    HTML5 Canvas核心技术:图形.动画与游戏开发 内容简介: <HTML5 Canvas核心技术:图形.动画与游戏开发>中,畅销书作家David Geary(基瑞)先生以实用的范例程 ...

  9. Canvas制作动态进度加载水球

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

随机推荐

  1. Spring和Hibernate结合的一个小例子

    1.新建一个SpringHibernate的maven项目 2.pom文件的依赖为 <dependency> <groupId>junit</groupId> &l ...

  2. javaweb servlet jsp简单笔记

    第二章: 1: web 俗称 : 万维网  www 2: web开发 的三大核心: HTML(网页) ,URL(定位),HTTP:(协议) 页面的分类: 静态页面: html+css 动态页面:jsp ...

  3. JavaScript有限状态机实现方式

    阮一峰博客 http://www.ruanyifeng.com/blog/2013/09/finite-state_machine_for_javascript.html 开源实现库(javascri ...

  4. 合并excel的多个sheet

    '合并excel的多个sheetSub 合并当前工作簿下的所有工作表()Application.ScreenUpdating = FalseFor j = 1 To Sheets.Count If S ...

  5. Web前端面试指导(二十):JavaScript中如何翻转一个字符串?

    题目点评 字符串作在程序中是非常常见的,因为程序中绝大部分的数据都可以当作字符串来处理.需要对字符的处理方法比较熟悉,在回答的时候尽量能够说出多种解决方法更好! 字符串翻转的方法 1)使用字符串函数 ...

  6. js修改日期

    需求说明: (1)首先是input显示年月日时分格式时间,其中年月日实在本地时间基础上,加上后面联动值.小时默认08:00不变 (2)后面input内显示天数,右侧加减按钮,控制天数,天数确定后,前面 ...

  7. 解决方案看起来是受源代码管理,但无法找到它的绑定信息。保存解决方案的源代码管理设置的MSSCCPRJ.SCC文件或其他项可能己被删除。

    Visual Studio 2015 + SVN 开发环境,今天打开项目,就报了下面这个错误,先前是好好的! 解决方案看起来是受源代码管理,但无法找到它的绑定信息.保存解决方案的源代码管理设置的MSS ...

  8. Ta们,用云计算改变着更多普通人的生活,所以,我们1218

    维族音乐的传承者:为家园建设生态农业:为50万货运司机谋福利:电视游戏行业复兴的倡导者:......还有很多平凡普通的人,不同的主角.不同的情节,用自己的云上轨迹在点滴改变着我们的周遭世界.所以,我们 ...

  9. 使用github参与到开源项目的维护

    参与到开源项目的维护工作一般分两种,一种是由项目建立者拉入到贡献者列表中,拥有对项目的读写权限,而普通用户对项目仅有读取权限,另一种是fork项目到自己仓库,然后把修改后的内容发送给项目管理者者请求合 ...

  10. Oracle案例04——ORA-39700: database must be opened with UPGRADE option

    Oracle11.2.0.3数据库通过rman备份到Oracle11.2.0.4上做还原,报需要升级的错误,具体处理步骤如下: 一.错误信息 SQL> alter database open r ...