import React, { useEffect, useRef } from 'react'; import { useUserStore } from '@/store/userStore'; interface Particle { x: number; y: number; vx: number; vy: number; radius: number; } export const ParticleNetwork: React.FC = () => { const canvasRef = useRef(null); const { isDark } = useUserStore(); useEffect(() => { const canvas = canvasRef.current; if (!canvas) return; const ctx = canvas.getContext('2d'); if (!ctx) return; let particles: Particle[] = []; let animationFrameId: number; const resize = () => { canvas.width = window.innerWidth; canvas.height = window.innerHeight; initParticles(); }; const initParticles = () => { particles = []; const numParticles = Math.floor((canvas.width * canvas.height) / 15000); for (let i = 0; i < numParticles; i++) { particles.push({ x: Math.random() * canvas.width, y: Math.random() * canvas.height, vx: (Math.random() - 0.5) * 0.5, vy: (Math.random() - 0.5) * 0.5, radius: Math.random() * 1.5 + 0.5, }); } }; const draw = () => { ctx.clearRect(0, 0, canvas.width, canvas.height); const color = isDark ? 'rgba(255, 255, 255,' : 'rgba(0, 0, 0,'; // Update positions particles.forEach((p) => { p.x += p.vx; p.y += p.vy; if (p.x < 0 || p.x > canvas.width) p.vx *= -1; if (p.y < 0 || p.y > canvas.height) p.vy *= -1; }); // Draw connections for (let i = 0; i < particles.length; i++) { for (let j = i + 1; j < particles.length; j++) { const dx = particles[i].x - particles[j].x; const dy = particles[i].y - particles[j].y; const distance = Math.sqrt(dx * dx + dy * dy); if (distance < 120) { ctx.beginPath(); ctx.strokeStyle = `${color} ${1 - distance / 120})`; ctx.lineWidth = 0.5; ctx.moveTo(particles[i].x, particles[i].y); ctx.lineTo(particles[j].x, particles[j].y); ctx.stroke(); } } } // Draw particles particles.forEach((p) => { ctx.beginPath(); ctx.arc(p.x, p.y, p.radius, 0, Math.PI * 2); ctx.fillStyle = `${color} 0.5)`; ctx.fill(); }); animationFrameId = requestAnimationFrame(draw); }; window.addEventListener('resize', resize); resize(); draw(); return () => { window.removeEventListener('resize', resize); cancelAnimationFrame(animationFrameId); }; }, [isDark]); return ( ); };