zoukankan      html  css  js  c++  java
  • 使用JavaScript和Canvas实现下雪动画效果

    该下雪动画效果使用了HTML5中Canvas画布实现,其中涉及了物理学中曲线运动的相关知识与运算。

    index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no" name="viewport">
        <meta content="yes" name="apple-mobile-web-app-capable">
        <meta content="black" name="apple-mobile-web-app-status-bar-style">
        <meta content="telephone=no" name="format-detection">
        <meta content="email=no" name="format-detection">
        <title>Snow</title>
        <link rel="stylesheet" href="css/main.css">
    </head>
    <body>
        <canvas id="canvas"></canvas>
        <script src="js/snow.js"></script>
        <script>
            window.addEventListener('load', function(){
                this.snow = new Snow();
                // 初始化snow对象并开始下雪动画
                snow.init().start();
            });
        </script>
    </body>
    </html>
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    main.css

    html, body{
         100%;
        height: 100%;
        overflow: hidden;
        margin: 0;
        padding: 0;
        background-color: #000;
        font-family: 微软雅黑, 华文细黑, 黑体;
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    Snow.js

    (function(exports, undefined){
        'use strict';
        var document = exports.document;
        function Snow(){
            this.colors = ['#fff'];
            this.balls = [];
            this.windDirection = -1;
            this.ballRadius = 3;
            this.ballsPerFrame = 2;
            this.timeInterval = 40;
            this.windDirectionChangedInterval = 5000;
            this.accumulativeTime = 0;
            return this;
        };
        exports.Snow = Snow;
        Snow.prototype = {
            init: function(args){
                for(var p in args){
                    this[p] = args[p];
                }
                this.canvas = this.canvas || document.querySelector('#canvas');
                this.context = this.context || this.canvas.getContext('2d');
                this.canvasWidth = this.canvasWidth || document.body.offsetWidth || document.body.clientWidth;
                this.canvasHeight = this.canvasHeight || document.body.offsetHeight || document.body.clientHeight;
                this.canvas.width = this.canvasWidth;
                this.canvas.height = this.canvasHeight;
                return this;
            },
            start: function(){
                this.timer = this.timer || setTimeout(this.frame.bind(this), this.timeInterval);
                return this;
            },
            frame: function(){
                this.accumulativeTime += this.timeInterval;
                (this.accumulativeTime % this.windDirectionChangedInterval < this.timeInterval) && (this.windDirection *= -1);
                this.render.call(this);
                this.update.call(this);
                this.timer = null;
                this.timer = setTimeout(this.frame.bind(this), this.timeInterval);
            },
            update: function(){
                this.addBalls.call(this);
                this.updateBalls.call(this);
            },
            updateBalls: function(){
                var balls = this.balls,
                    len = balls.length,
                    i = 0,
                    cnt = 0;
                for(;i<len;i++){
                    balls[i].x += balls[i].vx * this.windDirection;
                    balls[i].y += balls[i].vy;
                    balls[i].vy += balls[i].g * balls[i].t;
                    balls[i].t += this.timeInterval;
                    if(balls[i].y - this.ballRadius < this.canvasHeight){
                        balls[cnt++] = balls[i];
                    }
                }
                while(len>cnt){
                    balls.pop();
                    len--;
                }
            },
            addBalls: function(){
                var ball,
                    i = 0,
                    len = this.ballsPerFrame,
                    _this = this;
                for(;i<len;i++){
                    ball = {
                        x: Math.pow(-1, Math.ceil(Math.random() * 1000)) * Math.floor(Math.random() * _this.canvasWidth * 1.5),
                        y: Math.floor(Math.random() * this.ballRadius) * -1,
                        g: 0.00005,
                        vx: 1 + Math.floor(Math.random() * 2),
                        vy: 2 + Math.floor(Math.random() * 5),
                        t: 0,
                        color: _this.colors[Math.floor(Math.random() * _this.colors.length)]
                    }
                    this.balls.push(ball);
                }
            },
            render: function(){
                var cxt = this.context,
                    i = 0,
                    len = this.balls.length;
                cxt.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
                for(;i<len;i++){
                    cxt.fillStyle = this.balls[i].color;
                    cxt.beginPath();
                    cxt.arc(this.balls[i].x, this.balls[i].y, this.ballRadius, 0, 2 * Math.PI, true);
                    cxt.closePath();
                    cxt.fill();
                }
            },
            pause: function(){
                clearTimeout(this.timer);
                this.timer = null;
            },
            resume: function(){
                this.start.call(this);
            },
            clear: function(){
                clearTimeout(this.timer);
                this.timer = null;
                this.context.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
            }
        }
    })(window);
     
  • 相关阅读:
    .Net4.0并行库介绍——线程专有存储
    解决WPF中TextBox文件拖放问题
    POJ 2063 Investment(完全背包)
    HDU 1698 Just a Hook(线段树,成段更新)
    HDU 2665 Kth number(划分树入门题,纯套模板)
    HDU 4251 The Famous ICPC Team Again(划分树入门题)
    POJ 3295 Tautology(构造法)
    HDU 1540 Tunnel Warfare(线段树,去最大连续区间)
    HDU 1394 Minimum Inversion Number(求逆序数,线段树或者树状数组)
    POJ 2993 Emag eht htiw Em Pleh(水模拟)
  • 原文地址:https://www.cnblogs.com/gongcheng9990/p/4664412.html
Copyright © 2011-2022 走看看