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.效果展示