class ParticleSimulator { constructor(canvasId) { this.canvas = document.getElementById(canvasId); this.particles = []; this.isRunning = false; this.animationId = null; this.init(); } init() { this.createParticles(25); this.start(); // Add resize listener window.addEventListener('resize', () => { this.handleResize(); }); } createParticles(count) { this.particles = []; const colors = [ 'rgba(14, 165, 233, 0.8)', 'rgba(100, 116, 139, 0.8)', 'rgba(2, 132, 199, 0.8)', 'rgba(71, 85, 105, 0.8)' ]; for (let i = 0; i < count; i++) { const size = Math.random() * 8 + 4; const particle = { x: Math.random() * this.canvas.offsetWidth, y: Math.random() * this.canvas.offsetHeight, size: size, speedX: (Math.random() - 0.5) * 3, speedY: (Math.random() - 0.5) * 3, color: colors[Math.floor(Math.random() * colors.length)], trail: [] }; this.particles.push(particle); } } start() { this.isRunning = true; this.animate(); } stop() { this.isRunning = false; if (this.animationId) { cancelAnimationFrame(this.animationId); } } reset() { this.stop(); this.particles = []; this.createParticles(25); this.start(); } animate() { if (!this.isRunning) return; // Clear canvas this.canvas.innerHTML = ''; // Update and draw particles this.particles.forEach(particle => { // Update position particle.x += particle.speedX; particle.y += particle.speedY; // Boundary check if (particle.x <= 0 || particle.x >= this.canvas.offsetWidth) { particle.speedX *= -1; } if (particle.y <= 0 || particle.y >= this.canvas.offsetHeight) { particle.speedY *= -1; } // Add to trail particle.trail.push({ x: particle.x, y: particle.y }); if (particle.trail.length > 10) { particle.trail.shift(); } // Draw trail particle.trail.forEach((trailPos, index) => { const trailElement = document.createElement('div'); trailElement.className = 'particle-trail'; trailElement.style.width = `${particle.size * (index / particle.trail.length)}px`; trailElement.style.height = `${particle.size * (index / particle.trail.length)}px`; trailElement.style.left = `${trailPos.x}px`; trailElement.style.top = `${trailPos.y}px`; trailElement.style.backgroundColor = particle.color.replace('0.8', `${0.3 * (index / particle.trail.length)}`); this.canvas.appendChild(trailElement); }); // Draw particle const particleElement = document.createElement('div'); particleElement.className = 'particle'; particleElement.style.width = `${particle.size}px`; particleElement.style.height = `${particle.size}px`; particleElement.style.left = `${particle.x}px`; particleElement.style.top = `${particle.y}px`; particleElement.style.backgroundColor = particle.color; particleElement.style.boxShadow = `0 0 ${particle.size * 2}px ${particle.color}`; this.canvas.appendChild(particleElement); }); this.animationId = requestAnimationFrame(() => this.animate()); } handleResize() { this.stop(); this.start(); } updateParticleCount(count) { this.stop(); this.createParticles(count); this.start(); } } // Initialize simulator when DOM is loaded document.addEventListener('DOMContentLoaded', () => { const simulator = new ParticleSimulator('simulationCanvas'); // Add event listeners for control buttons document.querySelector('button:nth-child(1)').addEventListener('click', () => { simulator.start(); }); document.querySelector('button:nth-child(2)').addEventListener('click', () => { simulator.stop(); }); document.querySelector('button:nth-child(3)').addEventListener('click', () => { simulator.reset(); }); // Add event listeners for sliders const sliders = document.querySelectorAll('input[type="range"]'); sliders[0].addEventListener('input', (e) => { simulator.updateParticleCount(parseInt(e.target.value)); }); });