<!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了就变成-(应该有更好的方法,望指出)