H5雪花飘落效果

H5绘制雪花,JS实现雪花旋转飘落


主要运用canvas+js实现

效果图
雪花效果图

步骤:

  • 定义雪花: 每片雪花有3条线,每两条线的夹角为60度,每条线长度的一半为snowLength,中点为坐标原点;为了美观,线的长度与宽度的比为一定值;雪花下落自身旋转,给每片雪花一个水平和竖直的随机速度
  • 画出一片雪花 : 画布中顶部区域随机一个点,取这一点画一条倾斜随机角度(不要太大,否则后面旋转效果不明显)的线,根据三角函数求出线的两端点的坐标,再依次计算出另外两条线;
  • 让画出的线直接旋转是做不了的(反正我没试出来),但可以让下次画出的线在当前展示的线上旋转一个角度,清空当前的线再展示出来,只要线的颜色一样就有旋转效果.

语言太无力,直接上图(请原谅我拙劣的画图功底)
雪花图解

HTML部分:

    <canvas height="700px" width="1500px"></canvas>

CSS样式部分:

	* {
            padding: 0px;
            margin: 0px;
            list-style: none;
        }

        :root {
            height: 100%;
        }

        body {
            height: 100%;
            display: flex;
            justify-content: center;
            align-items: center;
            background-color: #000;
        }

        canvas {
            border: 1px solid black;
            box-sizing: border-box;
            background-image:url('./src/timg.jpg');
            background-size: cover;
        }

JavaScript部分:

准备工作:

 		var oCanvas = document.getElementsByTagName('canvas')[0];
        var ctx = oCanvas.getContext('2d');
        
        // 获取画布宽高
        var height = oCanvas.height;
        var width = oCanvas.width;
        
       	// 初始旋转角度的倍数
        var rotateCount = 0; 

生成一片随机雪的信息(在画布的位置、大小、长度、x轴和y轴的速度、自身旋转速度)

		function randomSnow() {
            var left = parseInt(Math.random() * width);
            var top = 50;
            var snowRotateDeg = parseInt(Math.random() * 10 + 5);
            var snowLength = parseInt(Math.random() * 10 + 10) / 2;    //该值为雪花每条线的一半
            var snowSpeedX = parseInt(Math.random() * 10 + 3);
            var snowSpeedY = parseInt(Math.random() * 10 + 2);

           	// 让画布中一半的雪花向左下角移动
            if (Math.random() < 0.5) {
                snowSpeedX *= (.5 - Math.random()) * 2;
            }

            // 将雪花信息返回到外面
            return {
                left: left,
                top: top,
                snowRotateDeg: snowRotateDeg,
                snowLength: snowLength,
                snowSpeedX: snowSpeedX,
                snowSpeedY: snowSpeedY
            }

       	}

根据随机生成的雪的信息在画布中画出雪花 (调试时建议用不同的颜色便于观察,看我画的图便于理解)

        function drawSnow(deg, snow) {
            ctx.beginPath();

            // θ角满足正弦规律,即0度时渲染雪花的一条线为竖直方向;θ1表示雪花第一条线与y轴正半轴的夹角
            var θ1 = deg % 60 * (Math.PI / 180);
            ctx.moveTo(snow.left + snow.snowLength * Math.sin(θ1), snow.top + snow.snowLength * Math.cos(θ1));
            ctx.lineTo(snow.left - snow.snowLength * Math.sin(θ1), snow.top - snow.snowLength * Math.cos(θ1));
            ctx.strokeStyle = "#fff";
            ctx.lineCap = 'round';
            ctx.lineWidth = snow.snowLength * 4 / 9;
            ctx.stroke();
            ctx.beginPath();

            // θ1表示雪花第二条线与y轴正半轴的夹角
            var θ2 = (60 - deg % 60) * (Math.PI / 180);
            ctx.moveTo(snow.left - snow.snowLength * Math.sin(θ2), snow.top + snow.snowLength * Math.cos(θ2));
            ctx.lineTo(snow.left + snow.snowLength * Math.sin(θ2), snow.top - snow.snowLength * Math.cos(θ2));
            ctx.strokeStyle = "#fff";
            ctx.lineCap = 'round';
            ctx.lineWidth = snow.snowLength * 4 / 9;
            ctx.stroke();
            ctx.beginPath();

            var θ3;
            if (deg % 60 + 60 > 90) {
                // 随着后续的旋转,deg值会越来越大,也就存在摩除60还比30大的情况,而此时雪花的第三条线就会被挤到随机点的第四象限中,并横跨二、四象限
                // 该θ3表示雪花第三条线与x轴正半轴的夹角
                θ3 = (deg % 60 - 30) * (Math.PI / 180);
                ctx.moveTo(snow.left - snow.snowLength * Math.cos(θ3), snow.top + snow.snowLength * Math.sin(θ3));
                ctx.lineTo(snow.left + snow.snowLength * Math.cos(θ3), snow.top - snow.snowLength * Math.sin(θ3));
            } else {

                // 该θ3表示雪花第三条线第一次渲染时与x轴正半轴的夹角
                θ3 = (30 - deg % 60) * (Math.PI / 180);
                ctx.moveTo(snow.left - snow.snowLength * Math.cos(θ3), snow.top - snow.snowLength * Math.sin(θ3));
                ctx.lineTo(snow.left + snow.snowLength * Math.cos(θ3), snow.top + snow.snowLength * Math.sin(θ3));
            }
            ctx.strokeStyle = "#fff";
            ctx.lineCap = 'round';
            ctx.lineWidth = snow.snowLength * 4 / 9;
            ctx.stroke();
        }

绘制雪花:

		var snowArr = [];

        // 每个30毫秒创建一片雪花,
        setInterval(function () {
            var snow = randomSnow();
            snowArr.push(snow);
            snowArr = snowArr.filter(function (item) {

                //容器保存当前还在画布的雪花       
                return item.top < height;
            })
        }, 30)

每隔一定时间清除画布并重绘页面

		setInterval(function () {
            ctx.clearRect(0, 0, width, height);
            snowArr.forEach(function (ele, index) {
                drawSnow(ele.snowRotateDeg * rotateCount, ele);
                ele.top += ele.snowSpeedY;
                ele.left += ele.snowSpeedX;
            })
            rotateCount++;
        }, 50)

完整代码

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            padding: 0px;
            margin: 0px;
            list-style: none;
        }

        :root {
            height: 100%;

        }

        body {
            height: 100%;
            display: flex;
            justify-content: center;
            align-items: center;
            background-color: #000;
        }

        canvas {
            border: 1px solid black;
            box-sizing: border-box;
            background-image:url('./src/timg.jpg');
            background-size: cover;
        }
    </style>
</head>

<body>
    <canvas height="700px" width="1500px"></canvas>
    <script>
        var oCanvas = document.getElementsByTagName('canvas')[0];
        var ctx = oCanvas.getContext('2d');
        
        // 获取画布宽高
        var height = oCanvas.height;
        var width = oCanvas.width;

        // 初始旋转角度的倍数
        var rotateCount = 0; 

        // 生成一片随机雪的信息(在画布的位置、大小、长度、x轴和y轴的速度、自身旋转速度)
        function randomSnow() {
            var left = parseInt(Math.random() * width);
            var top = 50;
            var snowRotateDeg = parseInt(Math.random() * 10 + 5);
            var snowLength = parseInt(Math.random() * 10 + 10) / 2;    //该值为雪花每条线的一半
            var snowSpeedX = parseInt(Math.random() * 10 + 3);
            var snowSpeedY = parseInt(Math.random() * 10 + 2);

            // 让画布中一半的雪花向左下角移动
            if (Math.random() < 0.5) {
               
                snowSpeedX *= (.5 - Math.random()) * 2;

            }else{
                // snowSpeedX /= 5;
            }

            // 将雪花信息返回到外面
            return {
                left: left,
                top: top,
                snowRotateDeg: snowRotateDeg,
                snowLength: snowLength,
                snowSpeedX: snowSpeedX,
                snowSpeedY: snowSpeedY
            }

        }


        // 根据随机生成的雪的信息在画布中画出雪花  
        function drawSnow(deg, snow) {
            ctx.beginPath();

            // θ角满足正弦规律,即0度时渲染雪花的一条线为竖直方向;θ1表示雪花第一条线与y轴正半轴的夹角
            var θ1 = deg % 60 * (Math.PI / 180);
            ctx.moveTo(snow.left + snow.snowLength * Math.sin(θ1), snow.top + snow.snowLength * Math.cos(θ1));
            ctx.lineTo(snow.left - snow.snowLength * Math.sin(θ1), snow.top - snow.snowLength * Math.cos(θ1));
            ctx.strokeStyle = "#fff";
            ctx.lineCap = 'round';
            ctx.lineWidth = snow.snowLength * 4 / 9;
            ctx.stroke();
            ctx.beginPath();

            // θ1表示雪花第二条线与y轴正半轴的夹角
            var θ2 = (60 - deg % 60) * (Math.PI / 180);

            ctx.moveTo(snow.left - snow.snowLength * Math.sin(θ2), snow.top + snow.snowLength * Math.cos(θ2));
            ctx.lineTo(snow.left + snow.snowLength * Math.sin(θ2), snow.top - snow.snowLength * Math.cos(θ2));
            ctx.strokeStyle = "#fff";
            ctx.lineCap = 'round';
            ctx.lineWidth = snow.snowLength * 4 / 9;
            ctx.stroke();
            ctx.beginPath();

            var θ3;
            if (deg % 60 + 60 > 90) {
                // 随着后续的旋转,deg值会越来越大,也就存在摩除60还比30大的情况,而此时雪花的第三条线就会被挤到随机点的第四象限中,并横跨二、四象限
                // 该θ3表示雪花第三条线与x轴正半轴的夹角
                θ3 = (deg % 60 - 30) * (Math.PI / 180);
                ctx.moveTo(snow.left - snow.snowLength * Math.cos(θ3), snow.top + snow.snowLength * Math.sin(θ3));
                ctx.lineTo(snow.left + snow.snowLength * Math.cos(θ3), snow.top - snow.snowLength * Math.sin(θ3));
            } else {

                // 该θ3表示雪花第三条线第一次渲染时与x轴正半轴的夹角
                θ3 = (30 - deg % 60) * (Math.PI / 180);
                ctx.moveTo(snow.left - snow.snowLength * Math.cos(θ3), snow.top - snow.snowLength * Math.sin(θ3));
                ctx.lineTo(snow.left + snow.snowLength * Math.cos(θ3), snow.top + snow.snowLength * Math.sin(θ3));
            }
            ctx.strokeStyle = "#fff";
            ctx.lineCap = 'round';
            ctx.lineWidth = snow.snowLength * 4 / 9;
            ctx.stroke();

        }

        // 在画布中展示的雪花
        var snowArr = [];

        // 每个30毫秒创建一片雪花,
        setInterval(function () {
            var snow = randomSnow();
            snowArr.push(snow);
            snowArr = snowArr.filter(function (item) {

                // 容器只保存当前还在画布的雪花
                return item.top < height;
            })
        }, 30)

        // 每50毫秒重新绘制一次画布
        setInterval(function () {
            ctx.clearRect(0, 0, width, height);
            snowArr.forEach(function (ele, index) {
                drawSnow(ele.snowRotateDeg * rotateCount, ele);
                ele.top += ele.snowSpeedY;
                ele.left += ele.snowSpeedX;
            })
            rotateCount++;
        }, 50)



    </script>
</body>
</html>

背景图片

背景

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值