canvas实例:绚丽小球

1.思路分析

  • 监听页面尺寸变化(防抖),动态设置canvas大小
  • 监听鼠标移动事件(节流),动态创建小球,小球包含大小,原点坐标,移动方向等信息,其内部方法支持移动和缩小
  • 开启定时器,更新画布内容(清屏后根据数据重新渲染)

2.主函数

  • 事件监听以及全局变量设定
  • 开启循环定时器实时渲染,过滤无效小球(尺寸小于0)
<script>
    //存储小球的数组
    var balls = []
    //定时器
    var timer = null

    //监听加载
    window.onload = function(){
        //宽高初始化
        setCanvasSize()

        //开启定时器渲染
        timer = setInterval(()=>{
            //遍历小球,使其动起来
            balls.forEach(ball=>{
                //更新小球信息
                ball.update()
            })
            //移除无效的小球(体积小于0就移除)
            balls = balls.filter(ball=>{
                return ball.size > 0
            })

            //如果小球已经没有,则移除循环定时器
            // if(balls.length == 0){
            //     clearInterval(timer)
            // }

            //根据数据渲染小球
            renderCanvas(balls)
        },30)
    }
    //监听页面尺寸变化(防抖)
    window.addEventListener('resize', debounce(setCanvasSize,200))
    //监听鼠标移动(节流),创建小球
    var canvas = document.querySelector('canvas')
    canvas.addEventListener('mousemove', throttle(createBall,20))


    //设定画布大小
    function setCanvasSize(){
        //获取canvas元素
        var canvas = document.querySelector('canvas')
        //设定宽高(全屏,保证根标签高度是100%)
        canvas.setAttribute('width',document.documentElement.clientWidth)
        canvas.setAttribute('height',document.documentElement.clientHeight)
    }

    //防抖函数
    function debounce(fn, wait) {    
        //默认情况下 没有延时定时器
        var timeout = null
        //定义内部函数并返回,形成闭包,缓存 timeout
        return function() {        
            //获取函数调用时的上下文
            var context = this
            //获取参数(事件对象)
            var event = arguments[0]

            //如果已经存在延时定时器 则尝试清除
            if(timeout !== null) {
                clearTimeout(timeout) 
            }
            //开启新的延时计时器      
            timeout = setTimeout(fn.bind(context,event), wait)    
        }
    }

    //节流函数
    function throttle(cb,delay){
        //记录上次回调执行时的时间戳
        var prev = 0
        //定义内部函数并返回,形成闭包,缓存prev
        return function(){
            //获取函数调用时的上下文
            var context = this
            //获取参数(事件对象)
            var event = arguments[0]
            //对比时间差 超过时间间隔则执行回调
           if(Date.now() - prev >= delay){
               //执行回调(绑定this,传递参数)
               cb && cb.call(context,event)
               //更新prev
               prev = Date.now()
           }
        }

    }
</script>

3.创建动感小球的类

  • 使用构造函数创建小球,包括其初始大小,坐标,颜色
  • 为其定义更新方法(大小变化,位置移动)
<script>
    //创建小球
    function createBall(e){
        //小球尺寸
        var size = 50
        //小球原点坐标
        var x = e.offsetX
        var y = e.offsetY
        //创建小球
        var ball = new DynamicBall(size,x,y)
        //将小球添加到数组(待渲染)
        balls.push(ball)
    }
    //小球构造函数(自动移动和缩小)
    class DynamicBall{
        //构造器
        constructor(size = 50,x = 0,y = 0){
            //初始化
            this.init(size,x,y)
        }

        //初始化
        init(size,x,y){
            //保存坐标与大小信息
            this.size = size
            this.x = x
            this.y = y
            //颜色
            this.color = this.getRandomColor()
            //移动角度
            this.move_deg = Math.random() * Math.PI * 2
            //每次移动距离
            //this.distanca = 2
            //this.distanca_x = this.distanca * Math.cos(this.move_deg)
            //this.distanca_y = this.distanca * Math.sin(this.move_deg)
        }

        //获取随机颜色
        getRandomColor() {
            var r = Math.round(Math.random() * 255)
            var g = Math.round(Math.random() * 255)
            var b = Math.round(Math.random() * 255)
            return 'rgb(' + r + ',' + g + ',' + b + ')'
        }

        //小球更新(大小和位置)
        update(scale = 1,distanca = 2){
            //更新大小
            this.size -= Number(scale)
            //更新位置
            this.x += (distanca * Math.cos(this.move_deg))
            this.y += (distanca * Math.sin(this.move_deg))
        }
    }
</script>

4.根据数据渲染小球

  • 渲染前清屏
  • 根据小球的尺寸,坐标进行渲染
<script>
    function renderCanvas(balls){
        //获取canvas元素
        var canvas = document.querySelector('canvas')
        //获取画笔
        var ctx = canvas.getContext('2d')
        //清屏
        ctx.clearRect(0,0,canvas.width,canvas.height)
        //遍历小球数据进行渲染
        balls.forEach(ball=>{
            //开启新路径
            ctx.beginPath()
            //绘制圆弧
            ctx.arc(ball.x,ball.y,ball.size,0,Math.PI*2)
            //设置填充颜色
            ctx.fillStyle = ball.color
            //填充
            ctx.fill()
        })
    }
</script>

5.效果展示

posted @ 2020-11-20 23:20  ---空白---  阅读(189)  评论(0编辑  收藏  举报