Canvas粒子背景效果
canvas | 2017年12月21日 |
- 最近有人问我博客的背景效果怎么实现的,其实就是一个canvas效果,今天抽空写篇博客简单分享下思路
- Demo演示
主要分为两步
- 首先就是根据窗口缩放比例随机生成点
- 再者就是就算点与点之间的距离,根据距离生成线段
- 综上所述,就是画点连线的过程
实现过程
- 第一步封装个函数mainBgFullScreen初始化canvas
- 使canvas根据窗口自适应
width = $(':root').width(); height = $(':root').height(); zoom = getZoom(); $canvas.attr('width', width); $canvas.attr('height', height); 复制代码
- 由于要做到自适应需要监听resize事件,在回调中执行mainBgFullScreen
- 绘制Canvas,固定套路
if ($canvas[0].getContext) { var ctx = $canvas[0].getContext('2d'); ctx.fillStyle = '#ffffff'; ctx.strokeStyle = 'rgba(255,255,255,0)'; ctx.lineWidth = 1 * zoom; drawCanvas(ctx); } 复制代码
- 使canvas根据窗口自适应
- 第二步在drawCanvas函数中根据一定的逻辑画点画线
- 画点:
- 封装一个工厂生成不同大小,不同位置,运动速度不同的点,这些根据屏幕缩放比生成,保证各个屏幕大小下显示协调
function creatPoint() { var xsKew = (Math.random() - 0.5) * zoom;//x方向速度 var ysKew = (Math.random() - 0.5) * zoom;//y方向速度 var r = ~~(Math.random() * 5 * zoom); var x = ~~(Math.random() * (width - r)) + 2 * r; var y = ~~(Math.random() * (height - r)) + 2 * r; var point = { x: x, y: y, xsKew: xsKew, ysKew: ysKew, r: r } return point; } 复制代码
- 在初始化Canvas时循环生成一些点,塞到数组中,画点时循环数组画点
//初始化先放200个点 for (var i = 0; i < ~~(200 * zoom); i++) { pointArry.push(creatPoint()); } //drawCanvas函数中 $.each(pointArry, function (index) { //绘制点 ctx.arc(this.x, this.y, this.r, 0, 2 * Math.PI); ctx.fill(); }) 复制代码
- 由于监听resize事件所以每次初始化,先清空数组
- 封装一个工厂生成不同大小,不同位置,运动速度不同的点,这些根据屏幕缩放比生成,保证各个屏幕大小下显示协调
- 画线
- 封装一个函数drawLine,参数是两点坐标以及ctx,根据勾股定理,大家应该都懂的,画两点之间的连线
//画线 function drawLine(ctx, p1x, p1y, p2x, p2y) { var xDistance = Math.abs(p1x - p2x);//计算两点间的x距离 var yDistance = Math.abs(p1y - p2y);//计算两点间的y距离 var distance = Math.sqrt(xDistance * xDistance + yDistance * yDistance); if (distance <= 120) { ctx.fillStyle = '#ffffff';//解决窗口缩放时圆点变黑 ctx.strokeStyle = 'rgba(255,255,255,' + (1 - distance / 120) + ')'; ctx.save(); ctx.beginPath(); ctx.moveTo(p1x, p1y); ctx.lineTo(p2x, p2y); ctx.stroke(); ctx.restore(); } } 复制代码
- 这里只有一个判断,当两点距离小于等于120时才画线,根据两点距离不同,线的粗细也在变化
- 最后就是在drawCanvas函数中调用了,逻辑:每次画一个点的时候,循环所有的点,当其它点距离当前点距离小于等于120时,画线
$.each(pointArry, function (index) { if (index != i) { drawLine(ctx, pointArry[i].x, pointArry[i].y, this.x, this.y); } }); 复制代码
- 封装一个函数drawLine,参数是两点坐标以及ctx,根据勾股定理,大家应该都懂的,画两点之间的连线
- 画点:
- 第三步就是让这些东西动起来,毫无疑问就是定时器了,这里用requestAnimationFrame递归,原因不用多说,性能好呗
if (window.requestAnimationFrame) timer = window.requestAnimationFrame(drawCanvas.bind(this, ctx)); else if (window.msRequestAnimationFrame) timer = window.msRequestAnimationFrame(drawCanvas.bind(this, ctx)); else if (window.mozRequestAnimationFrame) timer = window.mozRequestAnimationFrame(drawCanvas.bind(this, ctx)); else if (window.webkitRequestAnimationFrame) timer = window.webkitRequestAnimationFrame(drawCanvas.bind(this, ctx)); 复制代码
- 不要忘了在resize回调中取消动画哦!!!
- 第四步就看需求了,鼠标移动,鼠标附近的点与鼠标连线,其实经过上面的思路,这也很容易实现了,就是或取鼠标坐标,在循环画点时,与鼠标连线就可以了
$canvas.on('mousemove', function (ev) { ev = ev || event; mouseX = ev.offsetX; mouseY = ev.offsetY; }); //drawCanvas函数中 if (mouseX > 0 && mouseY > 0) { drawLine(ctx, mouseX, mouseY, this.x, this.y); } 复制代码
至此大功告成
- 大家可以直接看效果
- 小伙伴们如果有更好的方案,请分享一下,互相学习