1.编写样式
* {
margin: 0;
padding: 0;
}
canvas {
background: #000;
display: block;
pointer-events: none;
}
2.编写html标签内容
<canvas></canvas>
3.编写JavaScript内容
第一步:创建窗口重载函数让窗口变化时重新设置canvas的大小
// 设置canvas的大小
const setCanvasSize = () => {
const window_width = window.innerWidth;
const window_height = window.innerHeight;
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
};
// 窗口变化时重载canvas大小
window.onresize = function () {
setCanvasSize();
};
// 获取canvas元素
const canvas = document.querySelector("canvas");
// 设置大小
setCanvasSize();
获取min到max之间的随机数
// 获取min到max之间的随机数
function getRandomNum(min, max) {
return Math.floor(Math.random() * (max + 1 - min) + min);
}
生成点的构造函数
// 生成点的构造函数
class Point {
constructor() {
this.radius = 2;
this.x = getRandomNum(0, canvas.width - this.radius / 2);
this.y = getRandomNum(0, canvas.height - this.radius / 2);
this.xSpeed = getRandomNum(-50, 50);
this.ySpeed = getRandomNum(-50, 50);
this.lastDrawTime = null;
}
// 画点的方法
drawPoint() {
// 判断是否是第一次画点
if (this.lastDrawTime) {
const duration = (Date.now() - this.lastDrawTime) / 1000;
// 算出距离
const xDis = this.xSpeed * duration,
yDis = this.ySpeed * duration;
// 算出新的坐标
let x = this.x + xDis,
y = this.y + yDis;
// 判断坐标是否超出边界
if (x > canvas.width - this.radius / 2) {
x = canvas.width - this.radius / 2;
this.xSpeed = -this.xSpeed;
} else if (x < 0) {
x = 0;
this.xSpeed = -this.xSpeed;
}
if (y > canvas.height - this.radius / 2) {
y = canvas.height - this.radius / 2;
this.ySpeed = -this.ySpeed;
} else if (y < 0) {
y = 0;
this.ySpeed = -this.ySpeed;
}
// 设置更新坐标位置
this.x = x;
this.y = y;
}
// 绘画点
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
ctx.fillStyle = "#fff";
ctx.fill();
this.lastDrawTime = Date.now();
}
}
// 构造多个点的类
class GraphLinePoint {
constructor(number = 20, maxDis = 200) {
this.points = new Array(number).fill(0).map(() => new Point());
this.maxDis = maxDis;
}
// 连线
drawLinePoint() {
// 循环动画产生的函数 (类似于setTimeout等定时器,requestAnimationFrame是新API)
requestAnimationFrame(() => {
this.drawLinePoint();
});
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 循环产生的点
for (let i = 0; i < this.points.length; i++) {
const pl = this.points[i];
pl.drawPoint();
// 将产生的点与后面的点连线(比较重要的一步)
for (let j = i + 1; j < this.points.length; j++) {
const p2 = this.points[j];
// 计算两个点之间的直线距离
const d = Math.sqrt((pl.x - p2.x) ** 2 + (pl.y - p2.y) ** 2);
// 超出预设范围继续下一次循环
if (d > this.maxDis) {
continue;
}
// 开始绘制直线
ctx.beginPath();
ctx.moveTo(pl.x, pl.y);
ctx.lineTo(p2.x, p2.y);
ctx.closePath();
// 设置线的颜色
// ctx.strokeStyle = "#fff";
// 渐变的颜色(也是比较重要的一步)
ctx.strokeStyle = `rgba(25,255,255,${1 - d / this.maxDis})`;
ctx.stroke();
}
}
}
}
创建实例,并初始化实例,即可得到效果
const glp = new GraphLinePoint(100, 200);
glp.drawLinePoint();
完整代码
<!DOCTYPE html>
<html lang="en">
<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>粒子动画</title>
<style>
* {
margin: 0;
padding: 0;
}
canvas {
background: #000;
display: block;
pointer-events: none;
}
</style>
</head>
<body>
<canvas></canvas>
<script>
// 设置canvas的大小
const setCanvasSize = () => {
const window_width = window.innerWidth;
const window_height = window.innerHeight;
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
};
// 窗口变化时重载canvas大小
window.onresize = function () {
setCanvasSize();
};
window.onmousemove = function (e) {
console.log(e.offsetX);
console.log(e.offsetY);
ctx.clearRect(0, 0, canvas.width, canvas.height);
};
// 获取canvas元素
const canvas = document.querySelector("canvas");
// 设置大小
setCanvasSize();
// 获取canvas上下文对象
const ctx = canvas.getContext("2d");
// 获取min到max之间的随机数
function getRandomNum(min, max) {
return Math.floor(Math.random() * (max + 1 - min) + min);
}
// 生成点的构造函数
class Point {
constructor() {
this.radius = 2;
this.x = getRandomNum(0, canvas.width - this.radius / 2);
this.y = getRandomNum(0, canvas.height - this.radius / 2);
this.xSpeed = getRandomNum(-50, 50);
this.ySpeed = getRandomNum(-50, 50);
this.lastDrawTime = null;
}
drawPoint() {
if (this.lastDrawTime) {
const duration = (Date.now() - this.lastDrawTime) / 1000;
// 算出距离
const xDis = this.xSpeed * duration,
yDis = this.ySpeed * duration;
// 算出新的坐标
let x = this.x + xDis,
y = this.y + yDis;
// 判断坐标是否超出边界
if (x > canvas.width - this.radius / 2) {
x = canvas.width - this.radius / 2;
this.xSpeed = -this.xSpeed;
} else if (x < 0) {
x = 0;
this.xSpeed = -this.xSpeed;
}
if (y > canvas.height - this.radius / 2) {
y = canvas.height - this.radius / 2;
this.ySpeed = -this.ySpeed;
} else if (y < 0) {
y = 0;
this.ySpeed = -this.ySpeed;
}
this.x = x;
this.y = y;
}
ctx.beginPath();
ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
ctx.fillStyle = "#fff";
ctx.fill();
this.lastDrawTime = Date.now();
}
}
// 构造多个点的类
class GraphLinePoint {
constructor(number = 20, maxDis = 200) {
this.points = new Array(number).fill(0).map(() => new Point());
this.maxDis = maxDis;
}
drawLinePoint() {
requestAnimationFrame(() => {
this.drawLinePoint();
});
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (let i = 0; i < this.points.length; i++) {
const pl = this.points[i];
pl.drawPoint();
for (let j = i + 1; j < this.points.length; j++) {
const p2 = this.points[j];
const d = Math.sqrt((pl.x - p2.x) ** 2 + (pl.y - p2.y) ** 2);
if (d > this.maxDis) {
continue;
}
ctx.beginPath();
ctx.moveTo(pl.x, pl.y);
ctx.lineTo(p2.x, p2.y);
ctx.closePath();
// ctx.strokeStyle = "#fff";
ctx.strokeStyle = `rgba(25,255,255,${1 - d / this.maxDis})`;
ctx.stroke();
}
}
}
}
const glp = new GraphLinePoint(100, 200);
glp.drawLinePoint();
</script>
</body>
</html>