先看效果(完整代码在底部):
实现过程(可一步一步实现):
1.定义标签与基本css样式:
<canvas id="canvas"></canvas>
canvas{
display: block;
}
2. 开始正式js部分,先获取画布:
var canvas = document.querySelector("#canvas");
var ctx = canvas.getContext("2d");
3.定义基本变量:
// 画布宽与高
var kuan=0,gao=0;
// 线条数量
var num=25;
//数组,存储每条线的基本信息
var arr=[];
// 存几个喜欢的颜色后面给线条
var colors = ["#2196F3","#1976D2","#00BCD4","#4CAF50","#FF5252","#E040FB"];
4. 使得画布动态与窗口一样大小,直接copy该方法就行,顺便定义初始鼠标位置变量为画布的中间位置:
window.onresize=resizeCanvas;
function resizeCanvas(){
kuan=canvas.width=window.innerWidth;
gao=canvas.height=window.innerHeight;
}
resizeCanvas();
var mouseX = kuan/2,mouseY = gao/2;
5. 初始化数组,初始化每条线条的基本信息:
注:Math.random()*(max-min) + min 为随机获取min到max间的一个数。
for(let i=0;i<num;i++){
arr.push({
// 线条的宽度
r: Math.random()*(5-3) + 3,
// 线条的颜色
color: colors[parseInt(Math.random()*6)],
/* 线条最初始小点所在旋转圆上的位置,就是在旋转开始的角度 */
rot: Math.random()*2*Math.PI,
/* 线条与旋转圆中心的距离 */
distance: Math.random() * (75 - 40) + 40,
/* 记录初始位置,后面鼠标拖拽时做缓动动画用 */
lastMouse:{
x:kuan/2,
y:gao/2
}
})
}
6.绑定鼠标移动事件:
window.addEventListener('mousemove',function(event){
mouseX = event.clientX;
mouseY = event.clientY;
})
7.执行更新操作,在更新里调用绘制:
注意:在一个圆上,坐标 x=cos(…)× r,y = sin(…)× r 。
cos(.)与sin(.)取值范围为【-1,1】。细品。
function update (){
for(let i=0;i<num;i++){
//先保存上一帧的位置与i值
let last ={x:arr[i].x,y:arr[i].y,i:i};
// 移动后位置 = 当前位置 + (移动后位置-当前位置)*0.05 缓动动画原理
arr[i].lastMouse.x+=(mouseX-arr[i].lastMouse.x)*0.05;
arr[i].lastMouse.y+=(mouseY-arr[i].lastMouse.y)*0.05;
// 角度改变,就是进行旋转
arr[i].rot+=0.1;
// 坐标X改变
arr[i].x = arr[i].lastMouse.x + Math.cos(arr[i].rot)*arr[i].distance;
// 坐标y改变
arr[i].y = arr[i].lastMouse.y + Math.sin(arr[i].rot)*arr[i].distance;
/* 位置改变了,把last传给draw,得到不同两点后绘制画线 */
draw(last);
}
}
8. 绘制:
function draw(last) {
var yuan = arr[last.i];
// 开始绘制
ctx.beginPath();
//颜色
ctx.strokeStyle = yuan.color;
// 宽度
ctx.lineWidth = yuan.r;
ctx.moveTo(last.x,last.y);
ctx.lineTo(yuan.x,yuan.y);
ctx.stroke();
ctx.closePath();
}
9. 设置定时器,同时实现线条尾部慢慢消失效果:
setInterval(function(){
/* ctx.clearRect(0,0,kuan,gao); */
/* 不直接用clearRect让上一帧内容全部变透明,而是逐渐给上一帧
蒙上一层有点透明的当前背景色,这样一帧一帧的叠加,最开始的线段
会逐渐与背景融合变得相当与消失 */
ctx.fillStyle = "rgba(0,0,0,0.1)";
ctx.fillRect(0,0,kuan,gao);
update();
/* draw(); */
},20)
完整代码:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
*{
margin: 0;
padding: 0;
box-sizing: border-box;
}
body{
background-color: rgb(0, 0, 0);
}
canvas{
display: block;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script>
var canvas = document.querySelector("#canvas");
var ctx = canvas.getContext("2d");
// 画布宽与高
var kuan=0,gao=0;
var num=25;
var arr=[];
var colors = ["#2196F3","#1976D2","#00BCD4","#4CAF50","#FF5252","#E040FB"];
window.onresize=resizeCanvas;
function resizeCanvas(){
kuan=canvas.width=window.innerWidth;
gao=canvas.height=window.innerHeight;
}
resizeCanvas();
var mouseX = kuan/2,mouseY = gao/2;
for(let i=0;i<num;i++){
arr.push({
/* x: kuan/2,
y: gao/2, */
r: Math.random()*(5-3) + 3,
color: colors[parseInt(Math.random()*6)],
/* 旋转开始角度 */
rot: Math.random()*2*Math.PI,
/* 旋转小球距离中心距离 */
distance: Math.random() * (75 - 40) + 40,
/* 记录初始位置,鼠标拖拽时做缓动动画用 */
lastMouse:{
x:kuan/2,
y:gao/2
}
})
}
function draw(last) {
/* for(let i=0;i<num;i++){ */
var yuan = arr[last.i];
ctx.beginPath();
/* ctx.fillStyle = yuan.color;
ctx.arc(yuan.x,yuan.y,yuan.r, 0,Math.PI* 2, false);
ctx.fill(); */
ctx.strokeStyle = yuan.color;
ctx.lineWidth = yuan.r;
ctx.moveTo(last.x,last.y);
ctx.lineTo(yuan.x,yuan.y);
ctx.stroke();
ctx.closePath();
/* } */
}
window.addEventListener('mousemove',function(event){
mouseX = event.clientX;
mouseY = event.clientY;
})
/* var moveX=kuan/2,moveY=gao/2; */
function update (){
for(let i=0;i<num;i++){
/* 传当前绘制的第i个的线的绘制前一帧的位置和当前i保存 */
let last ={x:arr[i].x,y:arr[i].y,i:i};
/* 移动后位置 = 当前位置 + (移动后位置-当前位置)*0.05 缓动动画原理 */
arr[i].lastMouse.x+=(mouseX-arr[i].lastMouse.x)*0.05;
arr[i].lastMouse.y+=(mouseY-arr[i].lastMouse.y)*0.05;
arr[i].rot+=0.1;
arr[i].x = arr[i].lastMouse.x + Math.cos(arr[i].rot)*arr[i].distance;
arr[i].y = arr[i].lastMouse.y + Math.sin(arr[i].rot)*arr[i].distance;
/* 位置改变,把last传给draw,画线 */
draw(last);
}
}
setInterval(function(){
/* ctx.clearRect(0,0,kuan,gao); */
/* 不直接用clearRect让上一帧内容全部变透明,而是逐渐给上一帧
蒙上一层有点透明的当前背景色,这样一帧一帧的叠加,最开始的小球
会逐渐与背景融合变得相当与消失 */
ctx.fillStyle = "rgba(0,0,0,0.1)";
ctx.fillRect(0,0,kuan,gao);
update();
/* draw(); */
},20)
</script>
</body>
</html>
|