使用Canvas实现下雪功能

示例代码:

<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title></title>
    <meta charset="utf-8" />
    <style>
        body {
            background:#333;
        }
    </style>
</head>
<body>
    <button id="start-snowFall">开始</button>
    <button id="stop-snowFall">停止</button>
    <button id="pause-snowFall">暂停</button>
    <button id="resume-snowFall">回复</button>
    <script>
        window.onload = function () {
            //绑定事件
            var snow = new snowFall({ maxFlake: 200 });
            var start = document.getElementById('start-snowFall'),
                stop = document.getElementById('stop-snowFall'),
                pause = document.getElementById('pause-snowFall'),
                resume = document.getElementById('resume-snowFall');
            //开始
            start.onclick = function () {
                snow.start();
            }
            //停止
            stop.onclick = function () {
                snow.stop();
            }
            //暂停
            pause.onclick = function () {
                snow.pause();
            }
            //回复
            resume.onclick = function () {
                snow.resume();
            }
        }
        //控制对象封装
        function snowFall(snow) {
            //可配置属性
            snow = snow || {};
            this.maxFlake = snow.maxFlake || 200; //最多骗术
            this.flakeSize = snow.flakeSize || 10;// 雪花形状
            this.fallSpeed = snow.fallSpeed || 2;//坠落速度
            this.status = 0; //0-初始化、1-开始下雪 、2--停止下雪 、3--暂停下雪、4--继续下雨
        }
        //兼容写法
        requestAnimationFrame = window.requestAnimationFrame ||
            window.mozRequestAnimationFrame ||
            window.webkitRequestAnimationFrame ||
            window.msRequestAnimationFrame ||
            window.oRequestAnimationFrame ||
            function (callback) { setTimeout(callback, 1000 / 60) };
        cancelAnimationFrame = window.cancelAnimationFrame ||
            window.mozCancelAnimationFrame ||
            window.webkitCancelAnimationFrame ||
            window.msCancelAnimationFrame ||
            window.oCancelAnimationFrame;

        //开始下雪
        snowFall.prototype.start = function () {
            if (this.status == 1 || this.status == 4)
                return false;
            this.status = 1;
            //创建画布
            snowCanvas.apply(this);
            //创建雪花形状
            createFlakes.apply(this);
            //画学
            drawSnow.apply(this);
        }
        //停止下雪
        snowFall.prototype.stop = function () {
            if (this.status == 2 || this.status == 0 || !this.canvas) {
                return false;
            }
            //定制动画循环
            this.pause();
            this.status = 2;
            //删除画布
            this.canvas.parentNode.removeChild(this.canvas);
            this.canvas = null;
        };
        //暂停下雪
        snowFall.prototype.pause = function () {
            if (this.status == 3) {
                return false;
            }
            this.status = 3;
            cancelAnimationFrame(this.loop);
        }
        //继续下雪
        snowFall.prototype.resume = function () {
            if (this.status == 3 && this.canvas) {
                this.status = 4;
                //动画的计时控制
                this.loop = requestAnimationFrame(function () {
                    drawSnow.apply(that);
                });
            }
        }
        //创建画布
        function snowCanvas() {
            //添加Dom节点
            var snowcanvas = document.createElement('canvas');
            snowcanvas.id = 'snowfall';
            snowcanvas.width = window.innerWidth;
            snowcanvas.height = window.innerHeight;
            snowcanvas.setAttribute('style', 'position:fixed;top:0;left:0;z-index:2999;pointer-events:none;');
            
            document.getElementsByTagName('body')[0].appendChild(snowcanvas);
            this.canvas = snowcanvas;
            this.ctx = snowcanvas.getContext('2d');
            //窗口大小改变处理
            window.onresize = function () {
                snowcanvas.width = window.innerWidth;
                snowcanvas.height = window.innerHeight;
            }
        }
        //创建雪花
        function createFlakes() {
            var maxFlake = this.maxFlake,
                flakes = this.flakes = [],
                canvas = this.canvas;
            for (var i = 0; i < maxFlake; i++) {
                flakes.push(new flakeMove(canvas.width, canvas.height, this.flakeSize, this.fallSpeed));
            }
        }
        //雪运动对象
        function flakeMove(canvasWidth, canvasHeight, flakeSize, fallSpeed) {
            this.x = Math.floor(Math.random() * canvasWidth);   //x坐标
            this.y = Math.floor(Math.random() * canvasHeight);  //y坐标
            this.size = Math.random() * flakeSize + 2;          //形状
            this.masSize = flakeSize;                           //最大形状
            this.speed = Math.random() * 1 + fallSpeed;         //坠落速度
            this.fallSpeed = fallSpeed;                         //坠落速度
            this.velY = this.speed;                             //y方向速度
            this.velX = 0;                                      //x方向速度
            this.stepSize = Math.random() / 30;                 //步长 
            this.step = 0;                                      //步数
        }
        //重置当前雪花的位置
        flakeMove.prototype.update = function () {
            var x = this.x,
                y = this.y;
            //左右摆动(余弦)
            this.velX *= 0.98;
            if (this.velY <= this.speed) {
                this.velY = this.speed;
            }
            this.velX += Math.cos(this.step += 0.05) * this.stepSize;

            this.y += this.velY;
            this.x += this.velX;
            //飞出边界处理
            if (this.x >= canvas.width || this.x <= 0 || this.y >=canvas.height || this.y <= 0) {
                this.reset(canvas.width,canvas.height);
            }
        }
        //飞出边界--放置最顶端继续坠落
        flakeMove.prototype.reset = function (width, height) {
            this.x = Math.floor(Math.random() * width);
            this.y = 0;
            this.size = Math.random() * this.masSize + 2;
            this.speed = Math.random() * 1 + this.fallSpeed;
            this.velY = this.speed;
            this.velX = 0;
        }
        //渲染雪花--随机形状
        flakeMove.prototype.render = function (ctx) {
            var snowFlake = ctx.createRadialGradient(this.x, this.y, 0, this.x, this.y, this.size);
            snowFlake.addColorStop(0, 'rgba(255,255,255,0.9)');
            snowFlake.addColorStop(0.5, 'rgba(255,255,255,0.5)');
            snowFlake.addColorStop(1, 'rgba(255,255,255,0)');
            ctx.save();
            ctx.fillStyle = snowFlake;
            ctx.beginPath();
            ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
            ctx.fill();
            ctx.restore();
        }
        //滑雪
        function drawSnow() {
            var maxFlake = this.maxFlake,
                flakes = this.flakes;
            ctx = this.ctx,
            canvas = this.canvas,
            that = this;
            //清空
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            for (var i = 0; i < maxFlake; i++) {
                flakes[i].update();
                flakes[i].render(ctx);
            }
            //一折一帧的画
            this.loop = requestAnimationFrame(function () {
                drawSnow.apply(that);
            });
        }
    </script>
</body>
</html>

显示结果:

1.主要代码

this.step = 0;
this.stepSize = Math.random() / 30;
this.velX += Math.cos(this.step += .05) * this.stepSize;
this.x += this.velX;

step从0开始,每一帧增加0.05,相当于上图的横轴(X坐标)随着时间向右走

Math.cos(this.step += .05)则为上图对应的数轴(Y坐标),会随着step的增加,呈现1到-1的抛物线变换,正负值使得velX有左右方向

stepSize为步长,因为一帧有几十毫秒,很快,所以这个值为小于1/30的一个随机数

x为雪花的X坐标位置,就会在界面左右摆动

 

posted @ 2016-02-05 15:28  天马3798  阅读(1057)  评论(0编辑  收藏  举报