要展示的页面
import {useEffect,useRef} from "react";
import {BGAnimate} from "../../types/CanvasAnimation.ts";
function Home(){
const bgAnimate = useRef<BGAnimate>(null)
const bgCanvasRef = useRef<HTMLCanvasElement>(null)
useEffect(() => {
bgAnimate.current = new BGAnimate(bgCanvasRef.current!);
// 创建50个小球
for(let i=0;i<50;i++){
bgAnimate.current.createCircle(10)
}
// 小球开启运动
bgAnimate.current.start();
}, []);
return (
<>
<canvas ref={bgCanvasRef}></canvas>
</>
)
}
export default Home;
主要代码
const CIRCLE_LEN = 16; // 两个小球多长距离内会连线
class Circle {
x: number;
y: number;
r: number;
sleepX: number;
sleepY: number;
color: string;
width: number;
height: number;
isSelect:boolean;//是否选中
constructor(x: number, y: number, r: number, width: number, height: number) {
this.x = x;
this.y = y;
this.r = r;
this.sleepX = this.getRandom();
this.sleepY = this.getRandom();
this.width = width;
this.height = height;
this.isSelect = false;
this.color = this.getColor();
}
setSleep() {
if (this.x < 0 || this.x > this.width) {
this.sleepX = -this.sleepX;
}
if (this.y < 0 || this.y > this.height) {
this.sleepY = -this.sleepY;
}
}
move() {
if(this.isSelect) return;
this.setSleep()
this.x += this.sleepX;
this.y += this.sleepY;
}
getColor(){
const r = Math.random()*255;
const g = Math.random()*255;
const b = Math.random()*255;
return `rgb(${r},${g},${b}`;
}
// 生成随机数
getRandom() {
return Math.random() * 3 + 1;
}
// 两个球是否相近
circleAichika(ctx:CanvasRenderingContext2D,circle:Circle){
// if(this.x)
// 当前点的坐标
const w = Math.abs(this.x-circle.x);
const h = Math.abs(this.y-circle.y);
// 目标坐标
const len = Math.sqrt(w+h);
if(len<=CIRCLE_LEN){//画线
this.drawLine(ctx,circle);
}
}
drawLine(ctx:CanvasRenderingContext2D,circle:Circle){
ctx.beginPath();
ctx.lineWidth=0.5;
ctx.strokeStyle="#535c68";
ctx.moveTo(this.x,this.y);
ctx.lineTo(circle.x,circle.y);
ctx.stroke();
ctx.closePath();
}
}
export class BGAnimate {
private canvas: HTMLCanvasElement;
private ctx: CanvasRenderingContext2D;
private circles: Circle[];
private width: number;
private height: number;
constructor(canvas: HTMLCanvasElement) {
const {clientWidth, clientHeight} = document.documentElement;
this.canvas = canvas;
this.width = clientWidth;
this.height = clientHeight;
this.init();
this.ctx = canvas.getContext("2d")!;
this.circles = [];
}
init() {
this.canvas.width = this.width;
this.canvas.height = this.height;
this.canvas.style.position = "absolute";
this.canvas.style.top = "0";
this.canvas.style.left = "0";
this.canvas.style.width = this.width + "px";
this.canvas.style.height = this.height + "px";
this.canvas.style.background = "#2c3e50";
this.canvas.addEventListener("mousemove",e=>{
// 得到当前坐标
const {clientX:x,clientY:y} = e;
this.circles.forEach(circle=>{
if(circle.isSelect){
if(x>circle.x-circle.r&&x<circle.x+circle.r&&
y>circle.y-circle.r&&y<circle.y+circle.r){
circle.isSelect = true;
return;
}
circle.isSelect = false;
}
if(x>circle.x-circle.r&&x<circle.x+circle.r&&
y>circle.y-circle.r&&y<circle.y+circle.r){
circle.isSelect = true;
}
})
})
}
createCircle( r: number) {
const circle = new Circle(Math.random()*this.width, Math.random()*this.height, r, this.width, this.height);
this.circles.push(circle)
this.draw(circle);
}
// 开始移动
start() {
this.move();
requestAnimationFrame(() => {
this.start();
})
}
// 移动
move() {
this.ctx.clearRect(0, 0, this.width, this.height)
this.circles.forEach(circle => {
circle.move();
this.circles.forEach(v=>{
circle.circleAichika(this.ctx,v);
})
this.draw(circle)
})
}
//绘画
draw(circle: Circle) {
this.ctx.beginPath();
this.ctx.arc(circle.x, circle.y, circle.r, 0, Math.PI * 2);
this.ctx.fillStyle = circle.color;
this.ctx.fill();
this.ctx.closePath();
}
}
鼠标停留在某个小球上 可以让他暂停