canvas小练习之随机色彩变化

<!DOCTYPE html>
<html lang="en">
<style>
    body {
        overflow: hidden;
        margin: 0px;
    }
</style>

<body>
    <canvas id="canvas"></canvas>
    <script type="text/javascript">
        // 动画兼容函数
        window.requestAnimFrame = (function () {
            return (
                window.requestAnimationFrame ||
                window.webkitRequestAnimationFrame ||
                window.mozRequestAnimationFrame ||
                window.oRequestAnimationFrame ||
                window.msRequestAnimationFrame ||
                function (callback) {
                    window.setTimeout(callback, 1000 / 60)      //延迟一帧执行一次绘制,每秒60帧
                }
            )
        })()

        const canvas = document.getElementById('canvas')
        canvas.height = window.innerHeight      //根据屏幕显示canvas大小
        canvas.width = window.innerWidth
        const context = canvas.getContext('2d')
        window.addEventListener('resize', resizeCanvas)

        var color_r = {value:Math.random()*255,flag:true}
        var color_g = {value:Math.random()*255,flag:true}
        var color_b = {value:Math.random()*255,flag:true}
        var rgba = 'rgba('+color_r.value+','+color_g.value+','+color_b.value+',1)'//随机色
        var timer = null

        function resizeCanvas() {       //实时调整canvas大小
            canvas.height = window.innerHeight
            canvas.width = window.innerWidth
        }

        // 创建粒子
        var dots = []
        for (var i = 0; i < 100; i++) {
            dots.push({
                x: Math.random() * canvas.width, // x  , y  为  粒子坐标
                y: Math.random() * canvas.height,
                xa: Math.random() * 3 - 1, // xa , ya 为  粒子 xy 轴加速度
                ya: Math.random() * 3 - 1,
                max: 100 // 连线的最大距离 px
            })
        }

        // 鼠标粒子
        let warea = {
            x: null,
            y: null,
            max: 200 // 鼠标位置 和点的连线
        }
        //获取鼠标活动时的鼠标坐标
        canvas.onmousemove = (e) => {
            warea.x = e.clientX
            warea.y = e.clientY
        }
        //鼠标移出界面时清空
        canvas.onmouseout = (e) => {
            warea.x = null
            warea.y = null
        }

        // 绘制粒子
        function drawDots() {
            // 先清空
            context.clearRect(0, 0, canvas.width, canvas.height)
            context.fillStyle = 'rgba(0,43,54,1)'
            context.fillRect(0, 0, canvas.width, canvas.height)

            // 循环加载粒子
            dots.forEach((dot) => {
                // 粒子位移
                dot.x += dot.xa     //与其说是加速度不如说是速度
                dot.y += dot.ya

                // 遇到边界将 加速度 反向
                dot.xa *= dot.x > canvas.width || dot.x < 0 ? -1 : 1
                dot.ya *= dot.y > canvas.height || dot.y < 0 ? -1 : 1

                // 绘制点
                context.fillRect(dot.x - 1, dot.y - 1, 2, 2)
                context.fillStyle = 'rgba(255,218,27,1)'

                drawLine(dot, dots)
            })
        }

        /**
         * 计算距离 并连线
         * @param dot 当前点
         * @param dots 所有点
         */
        function drawLine(dot, dots) {

            var ndots = [warea].concat(dots)

            for (var i = 0; i < ndots.length; i++) {
                var item = ndots[i]

                // 过滤错误信息
                if (dot === item || item.x === null || item.y === null) continue
                // 创建变量
                let xc = dot.x - item.x,
                    yc = dot.y - item.y,
                    dis = '',
                    ratio = ''

                // 两个粒子之间的距离
                dis = Math.sqrt(xc * xc + yc * yc)

                // 判断 粒子 之间的距离
                if (dis < item.max) {

                    // 如果是鼠标,则让其他粒子向鼠标的位置移动
                    if (item === warea && dis > item.max / 10) {
                        dot.x -= xc * 0.03
                        dot.y -= yc * 0.03
                    }


                    // 计算距离比 -- 用于线 厚度
                    ratio = (item.max - dis) / item.max
                    // 画线
                    context.beginPath()
                    context.lineWidth = ratio / 2
                    if(!timer){
                        timer = this.setInterval(() => {
                            rgba = 'rgba('+revColor(color_r)+','+revColor(color_g)+','+revColor(color_b)+',1)'
                            console.log(rgba)
                        }, 1000/15);
                    }
                    
                    
                    context.strokeStyle = rgba
                    context.moveTo(dot.x, dot.y)
                    context.lineTo(item.x, item.y)
                    context.stroke()
                }
            }
        }

        function revColor(c) {
            if (c.flag) {
                if ((c.value + Math.random() * 20) < 255) {
                    c.value += Math.random() * 20
                    return c.value
                } else {
                    c.flag = !c.flag
                    c.value -= Math.random() * 20
                    return c.value
                }
            } else {
                if ((c.value - Math.random() * 20) > 0) {
                    c.value -= Math.random() * 20
                    return c.value
                } else {
                    c.flag = !c.flag
                    c.value += Math.random() * 20
                    return c.value
                }
            }

        }

        //   drawDots()
        function animate() {        // 使用递归实现动画
            requestAnimFrame(animate)       //用递归实现定时器的功效
            drawDots()
        }
        console.log(canvas.getBoundingClientRect())
        animate()
      //
    </script>
</body>

</html>

随机颜色变化难点在于需要自己加一个定时器,不然每帧颜色变化太快看起来很难受.

问题: 如果不用timer,直接用回调函数进行绘制线,线会一直闪烁,很辣眼睛
原因: timer的定时器可以让所有的线统一进行变化,如果用回调函数就会变成这个变换完另一条线按照这条的颜色再变,导致每条都不一样,而且每帧颜色变化很大

主要的颜色算法流程是rgb每个最大只有255,到了255就要往回走这样颜色变化才会柔和,所以我设了一个flag,到255了就变成-(应该有更好的方法,望指出)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值