Canvas制作的下雨动画的示例


Posted in HTML / CSS onMarch 06, 2018

简介

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

效果截图:

Canvas制作的下雨动画的示例

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

HTML / CSS 相关文章推荐
CSS3 Backgrounds属性相关介绍
May 11 HTML / CSS
CSS3结构性伪类选择器九种写法
Apr 18 HTML / CSS
CSS图片翻转动画技术详解(IE也实现了)
Apr 03 HTML / CSS
css3实现冲击波效果的示例代码
Jan 11 HTML / CSS
CSS3实现水平居中、垂直居中、水平垂直居中的实例代码
Feb 27 HTML / CSS
Bootstrap 学习分享
Nov 12 HTML / CSS
HTML5在a标签内放置块级元素示例代码
Aug 23 HTML / CSS
HTML5的自定义属性data-*详细介绍和JS操作实例
Apr 10 HTML / CSS
HTML5添加鼠标悬浮音响效果不使用FLASH
Apr 23 HTML / CSS
HTML5里的placeholder属性使用实例和美化显示效果的方法
Apr 23 HTML / CSS
HTML5 Canvas的事件处理介绍
Apr 24 HTML / CSS
HTML5不支持标签和新增标签详解
Jun 27 HTML / CSS
html2canvas把div保存图片高清图的方法示例
Mar 05 #HTML / CSS
HTML5页面直接调用百度地图API获取当前位置直接导航目的地的实现代码
Mar 02 #HTML / CSS
基于MUI框架使用HTML5实现的二维码扫描功能
Mar 01 #HTML / CSS
canvas裁剪clip()函数的具体使用
Mar 01 #HTML / CSS
html5.2 dialog简介详解
Feb 27 #HTML / CSS
Html5页面中的返回实现的方法
Feb 26 #HTML / CSS
简述Html5 IphoneX 适配方法
Feb 08 #HTML / CSS
You might like
Yii入门教程之Yii安装及hello world
2014/11/25 PHP
PHP命名空间和自动加载类
2016/04/03 PHP
Mac版PhpStorm之XAMPP整合apache服务器配置的图文教程详解
2016/10/13 PHP
php获取字符串前几位的实例(substr返回字符串的子串用法)
2017/03/08 PHP
jQuery Selector选择器小结
2010/05/06 Javascript
jquery下onpropertychange事件的绑定方法
2010/08/01 Javascript
js正则表达式匹配数字字母下划线等
2015/04/14 Javascript
JavaScript实现快速排序的方法
2015/07/31 Javascript
javascript:void(0)点击登录没反应怎么解决
2015/11/13 Javascript
jQuery 移动端artEditor富文本编辑器
2016/01/11 Javascript
jQuery在ie6下无法设置select选中的解决方法详解
2016/09/20 Javascript
EasyUI折叠表格层次显示detailview详解及实例
2016/12/28 Javascript
Angular.Js中过滤器filter与自定义过滤器filter实例详解
2017/05/08 Javascript
实现div滚动条默认最底部以及默认最右边的示例代码
2017/11/15 Javascript
webpack4打包vue前端多页面项目
2018/09/17 Javascript
利用d3.js制作连线动画图与编辑器的方法实例
2019/09/05 Javascript
JQuery中DOM节点的操作与访问方法实例分析
2019/12/23 jQuery
JS实现无限轮播无倒退效果
2020/09/21 Javascript
微信小程序实现可拖动悬浮图标(包括按钮角标的实现)
2020/12/29 Javascript
[01:52]PWL S2开团时刻第四期——DOTA2成语故事
2020/12/03 DOTA
详解Python中dict与set的使用
2015/08/10 Python
深入浅析python定时杀进程
2016/06/06 Python
python利用正则表达式排除集合中字符的功能示例
2017/10/10 Python
Tensorflow 查看变量的值方法
2018/06/14 Python
用python3 返回鼠标位置的实现方法(带界面)
2019/07/05 Python
python 解压、复制、删除 文件的实例代码
2020/02/26 Python
python实现横向拼接图片
2020/03/23 Python
用Python爬取LOL所有的英雄信息以及英雄皮肤的示例代码
2020/07/13 Python
使用pandas读取表格数据并进行单行数据拼接的详细教程
2021/03/03 Python
斯凯奇美国官网:SKECHERS美国
2016/08/20 全球购物
日本最大的药妆连锁店:Matsukiyo松本清药妆店
2017/11/23 全球购物
《我要的是葫芦》教学反思
2014/02/23 职场文书
关于感谢信的范文
2015/01/23 职场文书
2016中秋节广告语
2016/01/28 职场文书
教你如何使用Python Tkinter库制作记事本
2021/06/10 Python
python使用opencv对图像添加噪声(高斯/椒盐/泊松/斑点)
2022/04/06 Python