简介

在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. 使用powershell 执行脚本,windows默认不允许任何脚本运行

    使用如下命令让PowerShell运行在无限制的环境之下: Set-ExecutionPolicy Unrestricted

  2. Java 监听器,国际化

    1. 监听器 1.1 概述 监听器: 主要是用来监听特定对象的创建或销毁.属性的变化的! 是一个实现特定接口的普通java类! 对象: 自己创建自己用 (不用监听) 别人创建自己用 (需要监听) Se ...

  3. Python基础-模块与包

    一.如何使用模块 上篇文章已经简单介绍了模块及模块的优点,这里着重整理一下模块的使用细节. 1. import 示例文件:spam.py,文件名spam.py,模块名spam #spam.py pri ...

  4. 基础架构之Redis

    项目开发过程中,有些信息的变动频率是很低但又经常访问到,这些信息我们往往放在缓存中,目前在缓存组件中,Redis绝对值得你列入使用计划.更多详细信息可以参考官网 https://redis.io/.这 ...

  5. maoaolianxi

    package dududu; public class maopao { public static void main(String[] args) { // TODO 自动生成的方法存根 ,,, ...

  6. Maven 安装与使用(一)

    1. 安装 参考:http://maven.apache.org/install.html A. win7环境下,官网下载maven安装文件 B. 解压缩maven文件 C. 确认已配置好JAVA环境 ...

  7. 求解2的N次幂的问题(多种方法)

    #include <iostream> using namespace std; //计算2的N次幂 //一般方法,时间复杂度为2^n __int64 pow2(int n) { __in ...

  8. 【转】iOS lame编译 arm64 armv7s armv7 x86_64 i386指令集

    原文出至 http://blog.csdn.net/vieri_ch/article/details/40650467 最近升级了系统到Mac OS X 10.10 并且更新了XCode6.1和iOS ...

  9. git rebase --onto详解

    https://blog.pivotal.io/labs/labs/git-rebase-onto http://www.cnblogs.com/rickyk/p/3848768.html

  10. onchange,onfocus ,oninput事件

    compositionstart 在输入一段需要确认的文本如拼音to汉字.语音时会触发 compositionend  在拼音选词完成.语音输入完毕时会触发 addEventListener() 方法 ...