mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-09-29 22:06:38 +08:00
97 lines
2.3 KiB
TypeScript
97 lines
2.3 KiB
TypeScript
'use client';
|
|
|
|
import { useEffect, useRef } from 'react';
|
|
|
|
interface Snowflake {
|
|
x: number;
|
|
y: number;
|
|
radius: number;
|
|
speed: number;
|
|
opacity: number;
|
|
drift: number;
|
|
}
|
|
|
|
export function SnowEffect() {
|
|
const canvasRef = useRef<HTMLCanvasElement>(null);
|
|
|
|
useEffect(() => {
|
|
const canvas = canvasRef.current;
|
|
if (!canvas) return;
|
|
|
|
const ctx = canvas.getContext('2d');
|
|
if (!ctx) return;
|
|
|
|
let animationFrameId: number;
|
|
let snowflakes: Snowflake[] = [];
|
|
|
|
const resizeCanvas = () => {
|
|
canvas.width = window.innerWidth;
|
|
canvas.height = window.innerHeight;
|
|
};
|
|
|
|
const createSnowflakes = () => {
|
|
const count = Math.floor(window.innerWidth / 4);
|
|
snowflakes = [];
|
|
for (let i = 0; i < count; i++) {
|
|
snowflakes.push({
|
|
x: Math.random() * canvas.width,
|
|
y: Math.random() * canvas.height,
|
|
radius: Math.random() * 3 + 1,
|
|
speed: Math.random() * 2 + 0.5,
|
|
opacity: Math.random() * 0.5 + 0.3,
|
|
drift: Math.random() * 1 - 0.5,
|
|
});
|
|
}
|
|
};
|
|
|
|
const drawSnowflakes = () => {
|
|
if (!ctx || !canvas) return;
|
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
|
|
snowflakes.forEach((flake) => {
|
|
ctx.beginPath();
|
|
ctx.arc(flake.x, flake.y, flake.radius, 0, Math.PI * 2);
|
|
ctx.fillStyle = `rgba(255, 255, 255, ${flake.opacity})`;
|
|
ctx.fill();
|
|
|
|
flake.y += flake.speed;
|
|
flake.x += flake.drift;
|
|
|
|
if (flake.y > canvas.height) {
|
|
flake.y = -flake.radius;
|
|
flake.x = Math.random() * canvas.width;
|
|
}
|
|
if (flake.x > canvas.width) {
|
|
flake.x = 0;
|
|
} else if (flake.x < 0) {
|
|
flake.x = canvas.width;
|
|
}
|
|
});
|
|
|
|
animationFrameId = requestAnimationFrame(drawSnowflakes);
|
|
};
|
|
|
|
resizeCanvas();
|
|
createSnowflakes();
|
|
drawSnowflakes();
|
|
|
|
window.addEventListener('resize', () => {
|
|
resizeCanvas();
|
|
createSnowflakes();
|
|
});
|
|
|
|
return () => {
|
|
cancelAnimationFrame(animationFrameId);
|
|
window.removeEventListener('resize', resizeCanvas);
|
|
};
|
|
}, []);
|
|
|
|
return (
|
|
<canvas
|
|
ref={canvasRef}
|
|
className='fixed inset-0 pointer-events-none z-50'
|
|
style={{ background: 'transparent' }}
|
|
/>
|
|
);
|
|
}
|