[Js进阶]Canvas实现雪花特效

[Js进阶]Canvas实现雪花特效

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <title>雪花特效</title>
    <style>
        body {
            background-color: black;
        }
    </style>
</head>
<body>
<script src="./js/snowflake2canvas.js"></script>
<script src="./js/clickEffect.js"></script>
</body>
</html>

clickEffect.js

;(function (global, factory) {
    'use strict'
    typeof exports === 'object' && typeof module !== 'undefined'
        ? (module.exports = factory())
        : typeof define === 'function' && define.amd
            ? define(factory)
            : ((global = global || self), (global.clickEffect = factory()))
})(typeof window !== 'undefined' ? window : this, function () {
    function clickEffect() {
        var balls = []
        var longPressed = false
        var longPress
        var multiplier = 0
        var width, height
        var origin
        var normal
        var ctx
        var colours = ['#F73859', '#14FFEC', '#00E0FF', '#FF99FE', '#FAF15D']
        var canvas = document.createElement('canvas')
        document.body.appendChild(canvas)
        canvas.setAttribute(
            'style',
            'width: 100%; height: 100%; top: 0; left: 0; z-index: 99999; position: fixed; pointer-events: none;'
        )

        if (canvas.getContext && window.addEventListener) {
            ctx = canvas.getContext('2d')
            updateSize()
            window.addEventListener('resize', updateSize, false)
            loop()
            window.addEventListener(
                'mousedown',
                function (e) {
                    pushBalls(randBetween(10, 20), e.clientX, e.clientY)
                    document.body.classList.add('is-pressed')
                    longPress = setTimeout(function () {
                        document.body.classList.add('is-longpress')
                        longPressed = true
                    }, 500)
                },
                false
            )
            window.addEventListener(
                'mouseup',
                function (e) {
                    clearTimeout(longPress)
                    if (longPressed == true) {
                        document.body.classList.remove('is-longpress')
                        pushBalls(randBetween(50 + Math.ceil(multiplier), 100 + Math.ceil(multiplier)), e.clientX, e.clientY)
                        longPressed = false
                    }
                    document.body.classList.remove('is-pressed')
                },
                false
            )

            // window.addEventListener(
            //   'mousemove',
            //   function (e) {
            //     pushMoveBalls(randBetween(2, 4), e.clientX, e.clientY)
            //   },
            //   false
            // )
        } else {
            console.log('canvas or addEventListener is unsupported!')
        }

        // 更新气球大小
        function updateSize() {
            canvas.width = window.innerWidth * 2
            canvas.height = window.innerHeight * 2
            canvas.style.width = window.innerWidth + 'px'
            canvas.style.height = window.innerHeight + 'px'
            ctx.scale(2, 2)
            width = canvas.width = window.innerWidth
            height = canvas.height = window.innerHeight
            origin = {
                x: width / 2,
                y: height / 2
            }
            normal = {
                x: width / 2,
                y: height / 2
            }
        }

        // 气球类
        class Ball {
            constructor(x = origin.x, y = origin.y) {
                this.x = x
                this.y = y
                this.angle = Math.PI * 2 * Math.random()
                if (longPressed == true) {
                    this.multiplier = randBetween(14 + multiplier, 15 + multiplier)
                } else {
                    this.multiplier = randBetween(6, 12)
                }
                this.vx = (this.multiplier + Math.random() * 0.5) * Math.cos(this.angle)
                this.vy = (this.multiplier + Math.random() * 0.5) * Math.sin(this.angle)
                this.r = randBetween(8, 12) + 3 * Math.random()
                this.color = colours[Math.floor(Math.random() * colours.length)]
            }

            update() {
                this.x += this.vx - normal.x
                this.y += this.vy - normal.y
                normal.x = (-2 / window.innerWidth) * Math.sin(this.angle)
                normal.y = (-2 / window.innerHeight) * Math.cos(this.angle)
                this.r -= 0.3
                this.vx *= 0.9
                this.vy *= 0.9
            }
        }

        // 添加气球
        function pushBalls(count = 1, x = origin.x, y = origin.y) {
            for (let i = 0; i < count; i++) {
                balls.push(new Ball(x, y))
            }
        }

        // 添加移动气球
        function pushMoveBalls(count = 1, x = origin.x, y = origin.y) {
            for (let i = 0; i < count; i++) {
                balls.push(new Ball(x, y))
            }
        }

        // 随机数
        function randBetween(min, max) {
            return Math.floor(Math.random() * max) + min
        }

        // 动画循环
        function loop() {
            ctx.fillStyle = 'rgba(255, 255, 255, 0)'
            ctx.clearRect(0, 0, canvas.width, canvas.height)
            for (let i = 0; i < balls.length; i++) {
                let b = balls[i]
                if (b.r < 0) continue
                ctx.fillStyle = b.color
                ctx.beginPath()
                ctx.arc(b.x, b.y, b.r, 0, Math.PI * 2, false)
                ctx.fill()
                b.update()
            }
            if (longPressed == true) {
                multiplier += 0.2
            } else if (!longPressed && multiplier >= 0) {
                multiplier -= 0.4
            }
            removeBall()
            requestAnimationFrame(loop)
        }

        // 删除气球
        function removeBall() {
            for (let i = 0; i < balls.length; i++) {
                let b = balls[i]
                if (b.x + b.r < 0 || b.x - b.r > width || b.y + b.r < 0 || b.y - b.r > height || b.r < 0) {
                    balls.splice(i, 1)
                }
            }
        }
    }

    clickEffect()

    return clickEffect
})

snowflake2canvas.js

;(function (global, factory) {
    'use strict'
    typeof exports === 'object' && typeof module !== 'undefined'
        ? (module.exports = factory())
        : typeof define === 'function' && define.amd
            ? define(factory)
            : ((global = global || self), (global.snowflake2canvas = factory()))
})(typeof window !== 'undefined' ? window : this, function () {
    function snowflake2canvas() {
        var canvasDom = document.getElementById('snowflakeCanvas')
        if (!canvasDom) {
            canvasDom = document.createElement('canvas')
            document.body.appendChild(canvasDom)
        }
        var ctx = canvasDom.getContext('2d')
        var fillStyleColor = '#fff'
        var angle = 0

        // 设置画布的宽高
        var W = window.innerWidth
        var H = window.innerHeight

        canvasDom.width = W
        canvasDom.height = H
        canvasDom.style.cssText += `
    z-index: 99999;
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    pointer-events: none; 
  `

        // 设置雪花数目
        var flakesCount = 100
        var flakes = [] // flake instances

        // 每片雪花的初始属性
        for (var i = 0; i < flakesCount; i++) {
            flakes.push({
                x: Math.random() * W,
                y: Math.random() * H,
                r: Math.random() * 5 + 2, // 2px - 7px
                d: Math.random() + 1,
            })
        }

        requestAnimationFrame(drawFlakes)

        // 画图
        function drawFlakes() {
            ctx.clearRect(0, 0, W, H)
            ctx.fillStyle = fillStyleColor
            ctx.beginPath()
            for (var i = 0; i < flakesCount; i++) {
                var flake = flakes[i]
                ctx.moveTo(flake.x, flake.y)
                ctx.arc(flake.x, flake.y, flake.r, 0, Math.PI * 2, true)
            }
            ctx.fill()
            moveFlakes()
            requestAnimationFrame(drawFlakes)
        }

        // 雪花移动
        function moveFlakes() {
            angle += 0.01
            for (var i = 0; i < flakesCount; i++) {
                var flake = flakes[i]
                flake.y += Math.pow(flake.d, 2) + 1
                flake.x += Math.sin(angle) * 2

                if (flake.y > H) {
                    flakes[i] = { x: Math.random() * W, y: 0, r: flake.r, d: flake.d }
                }
            }
        }
    }

    snowflake2canvas()

    return snowflake2canvas
})

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值