Spaces:
Running
Running
| class ParticlesBackground extends HTMLElement { | |
| connectedCallback() { | |
| this.attachShadow({ mode: 'open' }); | |
| this.shadowRoot.innerHTML = ` | |
| <style> | |
| :host { | |
| display: block; | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| z-index: -1; | |
| overflow: hidden; | |
| } | |
| canvas { | |
| width: 100%; | |
| height: 100%; | |
| } | |
| </style> | |
| <canvas id="particles-canvas"></canvas> | |
| `; | |
| // Initialize particles | |
| this.initParticles(); | |
| } | |
| initParticles() { | |
| const canvas = this.shadowRoot.getElementById('particles-canvas'); | |
| const ctx = canvas.getContext('2d'); | |
| // Set canvas size | |
| canvas.width = canvas.offsetWidth; | |
| canvas.height = canvas.offsetHeight; | |
| // Particle system | |
| const particles = []; | |
| const particleCount = 150; | |
| const colors = [ | |
| '#3B82F6', '#10B981', '#8B5CF6', '#EF4444', '#F59E0B', | |
| '#EC4899', '#06B6D4', '#84CC16', '#F97316', '#6366F1' | |
| ]; | |
| // Create particles | |
| for (let i = 0; i < particleCount; i++) { | |
| particles.push({ | |
| x: Math.random() * canvas.width, | |
| y: Math.random() * canvas.height, | |
| radius: Math.random() * 3 + 1, | |
| color: colors[Math.floor(Math.random() * colors.length)], | |
| speedX: Math.random() * 2 - 1, | |
| speedY: Math.random() * 2 - 1, | |
| opacity: Math.random() * 0.5 + 0.2 | |
| }); | |
| } | |
| // Mouse interaction | |
| let mouseX = 0; | |
| let mouseY = 0; | |
| let mouseRadius = 100; | |
| canvas.addEventListener('mousemove', (e) => { | |
| const rect = canvas.getBoundingClientRect(); | |
| mouseX = e.clientX - rect.left; | |
| mouseY = e.clientY - rect.top; | |
| }); | |
| // Animation | |
| function animate() { | |
| ctx.clearRect(0, 0, canvas.width, canvas.height); | |
| // Update and draw particles | |
| particles.forEach(p => { | |
| // Move particle | |
| p.x += p.speedX; | |
| p.y += p.speedY; | |
| // Bounce off edges | |
| if (p.x < 0 || p.x > canvas.width) p.speedX *= -1; | |
| if (p.y < 0 || p.y > canvas.height) p.speedY *= -1; | |
| // Draw particle | |
| ctx.beginPath(); | |
| ctx.arc(p.x, p.y, p.radius, 0, Math.PI * 2); | |
| ctx.fillStyle = p.color; | |
| ctx.globalAlpha = p.opacity; | |
| ctx.fill(); | |
| // Draw connections | |
| particles.forEach(p2 => { | |
| const dx = p.x - p2.x; | |
| const dy = p.y - p2.y; | |
| const distance = Math.sqrt(dx * dx + dy * dy); | |
| if (distance < 100) { | |
| ctx.beginPath(); | |
| ctx.strokeStyle = p.color; | |
| ctx.globalAlpha = 0.1 * (1 - distance / 100); | |
| ctx.lineWidth = 0.5; | |
| ctx.moveTo(p.x, p.y); | |
| ctx.lineTo(p2.x, p2.y); | |
| ctx.stroke(); | |
| } | |
| }); | |
| // Mouse interaction | |
| const dx = p.x - mouseX; | |
| const dy = p.y - mouseY; | |
| const distance = Math.sqrt(dx * dx + dy * dy); | |
| if (distance < mouseRadius) { | |
| const angle = Math.atan2(dy, dx); | |
| const force = (mouseRadius - distance) / mouseRadius; | |
| p.x += Math.cos(angle) * force * 5; | |
| p.y += Math.sin(angle) * force * 5; | |
| } | |
| }); | |
| requestAnimationFrame(animate); | |
| } | |
| // Handle resize | |
| window.addEventListener('resize', () => { | |
| canvas.width = canvas.offsetWidth; | |
| canvas.height = canvas.offsetHeight; | |
| }); | |
| animate(); | |
| } | |
| } | |
| customElements.define('particles-background', ParticlesBackground); |