完整代码如下
const dots = ref<number>(200)
const canvasRef = ref<HTMLCanvasElement | null>(null);
const init = () => {
const canvas = canvasRef.value;
if (!canvas) return;
const ctx = canvas.getContext('2d');
if (!ctx) return;
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.style.backgroundColor = 'black';
return ctx;
};
const getRandom = (min: number, max: number) => {
return Math.floor(Math.random() * (max - min + 1)) + min;
};
class Point {
r: number;
x: number;
y: number;
vx: number; // x轴速度
vy: number; // y轴速度
constructor(canvas: HTMLCanvasElement) {
this.r = 1.5;
this.x = getRandom(this.r, canvas.width - this.r);
this.y = getRandom(this.r, canvas.height - this.r);
this.vx = Math.random() * 2 - 1; // -1到1之间的随机速度
this.vy = Math.random() * 2 - 1;
}
draw(ctx: CanvasRenderingContext2D | undefined) {
if (!ctx) return;
ctx.beginPath()
ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2, true)
ctx.fillStyle = '#fff'
ctx.fill();
}
update(canvas: HTMLCanvasElement) {
this.x += this.vx;
this.y += this.vy;
// 边界检测,碰到边缘反弹
if (this.x <= this.r || this.x >= canvas.width - this.r) {
this.vx = -this.vx;
}
if (this.y <= this.r || this.y >= canvas.height - this.r) {
this.vy = -this.vy;
}
}
}
class Graph {
points: Point[];
maxDistance = 200;
canvas: HTMLCanvasElement;
constructor(canvas: HTMLCanvasElement, length: number = 100) {
this.canvas = canvas;
this.points = Array.from({ length }, () => {
return new Point(canvasRef.value!);
});
}
addPoint(num: number) {
this.points.push(...Array.from({ length: num }, () => {
return new Point(this.canvas);
}));
}
update() {
this.points.forEach(point => point.update(this.canvas));
}
draw(ctx: CanvasRenderingContext2D) {
if (!ctx) return;
ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
for (let i = 0; i < this.points.length; i++) {
const prevPoint = this.points[i];
prevPoint.draw(ctx);
for (let j = i + 1; j < this.points.length; j++) {
const nextPoint = this.points[j];
const distance = Math.sqrt(
Math.pow(prevPoint.x - nextPoint.x, 2) +
Math.pow(prevPoint.y - nextPoint.y, 2)
);
if (distance > this.maxDistance) continue;
ctx.beginPath();
ctx.moveTo(prevPoint.x, prevPoint.y);
ctx.lineTo(nextPoint.x, nextPoint.y);
ctx.strokeStyle = `rgba(255, 255, 255, 1 - distance / this.maxDistance)`;
// ctx.strokeStyle = '#fff'
ctx.lineWidth = 0.5;
ctx.stroke();
}
}
}
}
onMounted(() => {
const ctx = init();
const graph = new Graph(canvasRef.value!, dots.value);
function animate() {
graph.update();
if (!ctx) return;
graph.draw(ctx);
requestAnimationFrame(animate);
}
animate();
const btn = document.querySelector('.add-btn')
btn?.addEventListener('click', () => {
dots.value += 10;
graph.addPoint(10);
})
})