Canvas –雪花图

昨天冬至,又到了白色相簿的季节了,︿( ̄︶ ̄)︿笑,后天就是圣诞了,安安心心做个剩蛋老人吧(ノへ ̄、)。
好了好了,重庆还是没下雪,冷着不下雪,感觉好亏。既然不下,那就只有自己写点雪花了。
canvas这个东西一直是想深入学习的,做出来的东西各种炫酷吊炸天,但是没啥时间,就只会点小东西,大家将就着看吧:
首先既然是用canvas,那么结构就非常简单啦,html什么都不用写,用js创建canvas。
我们把一张背景图放在body上,然后在canvas上进行雪花的绘制:

*{
    margin: 0;
    padding: 0;
}
html{
    width: 100%;
    height: 100%;
}
body{
    width: 100%;
    height: 100%;
    background: url("./xh.jpg") center no-repeat;
    overflow: hidden;
}

这次就不用es6的写法了,用prototype吧:
首先我们用requestAnimationFrame绘制动画的,先把兼容性搞一下,再创建函数snowFall,设置一下默认参数,maxFlake、flakeSize和fallSpeed,在进行初始化时,可以通过new snowFall()传入这三个参数改变雪花的样式。

//兼容写法
requestAnimationFrame = window.requestAnimationFrame ||
    window.mozRequestAnimationFrame ||
    window.webkitRequestAnimationFrame ||
    window.msRequestAnimationFrame ||
    window.oRequestAnimationFrame ||
    function(callback) { setTimeout(callback, 1000 / 60); };

function snowFall(snow) {
    snow = snow || {};
    this.maxFlake = snow.maxFlake || 500;   /* 最大片数 */
    this.flakeSize = snow.flakeSize || 10;  /* 雪花大小 */
    this.fallSpeed = snow.fallSpeed || 1;   /* 坠落速度 */
    this.flakes = [];                      /* 雪花集合 */
}

然后我们在这个函数上添加一个start方法,调用此方法开始创建画布绘制雪花,出现下雪效果:

// 开始绘制雪花
snowFall.prototype.start = function(){
    /* 创建画布 */
    snowCanvas.apply(this);
    /* 创建雪花形状 */
    createFlakes.apply(this);
    /* 画雪 */
    drawSnow.apply(this);
}

接下来开始创建画布了,建立一个canvas放入body中:

// 创建画布
function snowCanvas() {
    var snowcanvas = document.createElement("canvas");
    snowcanvas.id = "snowfall";
    snowcanvas.width = window.innerWidth;
    snowcanvas.height = document.body.clientHeight || document.documentElement.clientHeight;
    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() {
    for (var i = 0; i < this.maxFlake; i++) {
        this.flakes.push(new flakeMove(this.canvas.width, this.canvas.height, this.flakeSize, this.fallSpeed))
    }
}

雪花运动对象,用于生成每个雪花的一系列参数:

//雪运动对象
function flakeMove(canvasWidth, canvasHeight, flakeSize, fallSpeed) {
    this.canvasw = canvasWidth;
    this.canvash = canvasHeight;
    this.x = Math.floor(Math.random() * canvasWidth); /* x坐标 */
    this.y = Math.floor(Math.random() * canvasHeight); /* y坐标 */
    this.size = Math.random() * flakeSize + 2; /* 形状 */
    this.maxSize = flakeSize; /* 最大形状 */
    this.speed = Math.random() * 1 + fallSpeed; /* 坠落速度 */
    this.fallSpeed = fallSpeed; /* 坠落速度 */
    this.velY = this.speed; /* Y方向速度 */
    this.velX = 0; /* X方向速度 */
    this.stepSize = Math.random() / 100; /* 步长 */
}

在雪的运动对象上添加一个render方法,用于生成雪的形状

// 渲染雪花-随机形状(此处可修改雪花颜色!!!)
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(.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();
};

在雪的运动对象上添加一个雪花的运动方法,根据传入的参数不同,来让雪向左向右运动,当雪花飞到了边界后,调用reset方法重置这个雪花的状态:

flakeMove.prototype.update = function (n) {
    var x = this.x,
        y = this.y;
    if (n) {
        this.velX += this.stepSize;
    } else {
        this.velX -= this.stepSize;
    }
    this.y += this.velY;
    this.x += this.velX;
    /* 飞出边界的处理 */
    if (this.x >= this.canvasw || this.x <= 0 || this.y >= this.canvaswh || this.y <= 0) {
        this.reset(this.canvasw, this.canvash)
    }
};
/* 飞出边界-放置最顶端继续坠落 */
flakeMove.prototype.reset = function (width, height) {
    this.x = Math.floor(Math.random() * width);
    this.y = 0;
    this.size = Math.random() * this.maxSize + 2;
    this.speed = Math.random() * 1 + this.fallSpeed;
    this.velY = this.speed;
    this.velX = 0;
};

雪花对象设置完毕后,我们开始画雪了,每次绘制前我们都要清空一下画布,然后根据雪花的集合进行遍历,调用函数让一部分雪花向左飘,一部分向右飘,然后用requestAnimationFrame继续调用画雪的函数,一帧一帧绘制雪花:

/* 画雪 */
function drawSnow() {
    /* 清空雪花 */
    this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
    for (var e = 0; e < this.maxFlake; e++) {
        if (e % 3 == 0) {
            this.flakes[e].update(0);
            this.flakes[e].render(this.ctx);
        } else {
            this.flakes[e].update(1);
            this.flakes[e].render(this.ctx);
        };

    }
    /*  一帧一帧的画 */
    this.loop = requestAnimationFrame(function () {
        drawSnow.apply(this);
    }.bind(this));
}

最后我们 new snowFall(),最多绘制100个雪花,然后调用start方法,雪花就开始飞舞了:

/* 调用及控制方法 */
var snow = new snowFall({
    maxFlake: 100
});
snow.start();

效果展示:

本文示例:链接
本文代码地址:链接

您也可能喜欢...

发表评论

电子邮件地址不会被公开。 必填项已用*标注