echoes/frontend/hooks/Background.tsx

95 lines
2.3 KiB
TypeScript

import { useEffect, useRef } from 'react';
import { useThemeMode } from 'hooks/ThemeMode';
export const AnimatedBackground = () => {
const canvasRef = useRef<HTMLCanvasElement>(null);
const { mode } = useThemeMode();
useEffect(() => {
const canvas = canvasRef.current;
if (!canvas) return;
const ctx = canvas.getContext('2d')!;
if (!ctx) return;
const canvasElement = canvas!;
// 生成随机HSL颜色
const getRandomHSLColor = () => {
const hue = Math.random() * 360;
const saturation = 70 + Math.random() * 30;
const lightness = mode === 'dark'
? 40 + Math.random() * 20
: 60 + Math.random() * 20;
return `hsl(${hue}, ${saturation}%, ${lightness}%)`;
};
const ballColor = getRandomHSLColor();
let ballRadius = 100;
let x = canvas.width / 2;
let y = canvas.height - 200;
let dx = 0.2;
let dy = -0.2;
// 设置canvas尺寸为窗口大小
const resizeCanvas = () => {
// 保存调整前的相对位置
const relativeX = x / canvas.width;
const relativeY = y / canvas.height;
// 更新canvas尺寸
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// 根据新尺寸更新球的位置
x = canvas.width * relativeX;
y = canvas.height * relativeY;
// 立即重绘
drawBall();
};
function drawBall() {
ctx.beginPath();
ctx.arc(x, y, ballRadius, 0, Math.PI * 2);
ctx.fillStyle = ballColor;
ctx.fill();
ctx.closePath();
}
function draw() {
ctx.clearRect(0, 0, canvasElement.width, canvasElement.height);
drawBall();
if (x + dx > canvasElement.width - ballRadius || x + dx < ballRadius) {
dx = -dx;
}
if (y + dy > canvasElement.height - ballRadius || y + dy < ballRadius) {
dy = -dy;
}
x += dx;
y += dy;
}
resizeCanvas();
window.addEventListener('resize', resizeCanvas);
const interval = setInterval(draw, 10);
return () => {
clearInterval(interval);
window.removeEventListener('resize', resizeCanvas);
};
}, [mode]);
return (
<div className="fixed inset-0 -z-10">
<canvas
ref={canvasRef}
className="w-full h-full"
style={{ filter: 'blur(150px)' }}
/>
</div>
);
};