Canvas製做的下雨動畫

簡介

在codepen上看到一個Canvas作的下雨效果動畫,感受蠻有意思的。就研究了下,這裏來分享下,實現技巧。效果能夠見下面的連接。javascript

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

效果截圖:
圖片描述html

Canvas動畫基礎

你們都知道,Canvas其實只是一個畫板。咱們能夠應用canvas的api在上面繪製各類圖形。
Canvas 2D 的API:
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2Djava

那麼Canvas繪製動畫的步驟就是:web

  1. 繪製第一幀圖形(利用API繪圖)canvas

  2. 清空畫板(應用clearRect()或fillRect())api

  3. 繪製下一幀動畫瀏覽器

用什麼來控制動畫每一幀的繪製時間呢?你們很容易想到 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~~。

相關文章
相關標籤/搜索