简介

在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. Maven 配置tomcat和findbug插件(在eclipse建立的项目中)

    tomcat插件 a)        tomcat的maven插件可以在tomcat的官网上寻找,这就是tomcat插件的plugin b)        将tomcat的plugin配置到项目的po ...

  2. JavaScript中按键事件的e.keyCode || e.which || e.charCode

    1.浏览器的按键事件 浏览器有3种按键事件——keydown,keypress和keyup,分别对应onkeydown.onkeypress和onkeyup3个事件句柄. 一个典型的按键会产生所有这三 ...

  3. JavaScript里面的居民们1-数据

    编码 首先练习数字相关的一些操作: <div> <label>Number A:<input id="radio-a" type="radi ...

  4. js小数转分数-近似递归

    精度为小数两位,提高精度可把 toFixed(2)和100同时修改: function decimalsToFractional(decimals){ const formatDecimals = d ...

  5. IE6 行内定义成块元素后高度失效

    问题描述: ie6下,空标签块元素height定义失效,表现为除设置的height值外还会显示N像素额外的高度. 实际运用中,若标签为空且定义了小于14px的高度,再加入一背景图的话,会发现该元素高度 ...

  6. css伪元素详解

    css的伪元素,之所以被称为伪元素,是因为他们不是真正的页面元素,html没有对应的元素,但是其所有用法和表现行为与真正的页面元素一样,可以对其使用诸如页面元素一样的css样式,表面上看上去貌似是页面 ...

  7. .NET开源工作流RoadFlow-流程运行-运行时监控

    流程实例参与者都可以随时查看流程实例的运行情况,如果是待办任务,则在待办事项列表的后面点查看,如果是已完成任务则可以在已办事项列表的后面点查看: 打开之后默认为列表方式显示流程的处理过程,还可以点图形 ...

  8. 消息循环中的TranslateMessage函数和DispatchMessage函数,特别注意WM_TIMER消息

    原文:http://www.cnblogs.com/xingrun/p/3583357.html TranslateMessage函数 函数功能描述:将虚拟键消息转换为字符消息.字符消息被送到调用线程 ...

  9. 命令解决500 Error: Cannot find module 'XXX'

    装express之后访问http://localhost:3000.会出现500 Error: Cannot find module 'xxx'错误 解决方案: 确定package.json里有添加相 ...

  10. Django_MTV模型

    创建DJango项目过程: 1:安装Django包 方式一:pip3 install django 方式二:pycharm-->file--->settings-->找到projec ...