class PortfolioAnimations { constructor() { this.init(); } init() { this.setupIntersectionObserver(); this.setupMagneticEffects(); this.setupParallaxEffects(); this.addFloatingShapes(); } setupIntersectionObserver() { const observerOptions = { threshold: 0.1, rootMargin: '0px 0px -50px 0px' }; const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { const element = entry.target; const animation = element.dataset.animation; const delay = element.dataset.delay || 0; setTimeout(() => { element.classList.add(`animate-${animation}`); if (element.dataset.counter) { this.animateCounter(element); } }, delay); observer.unobserve(element); } }); }, observerOptions); document.querySelectorAll('.animate-on-scroll').forEach(el => { observer.observe(el); }); } setupMagneticEffects() { document.querySelectorAll('.magnetic').forEach(button => { button.addEventListener('mousemove', (e) => { const rect = button.getBoundingClientRect(); const x = e.clientX - rect.left - rect.width / 2; const y = e.clientY - rect.top - rect.height / 2; button.style.transform = `translate(${x * 0.1}px, ${y * 0.1}px) scale(1.02)`; }); button.addEventListener('mouseleave', () => { button.style.transform = 'translate(0px, 0px) scale(1)'; }); }); } setupParallaxEffects() { window.addEventListener('scroll', () => { const scrolled = window.pageYOffset; const parallaxElements = document.querySelectorAll('.parallax'); parallaxElements.forEach(element => { const speed = element.dataset.speed || 0.5; const yPos = -(scrolled * speed); element.style.transform = `translateY(${yPos}px)`; }); }); } animateCounter(element) { const target = parseInt(element.dataset.counter); const duration = 2000; const start = 0; const increment = target / (duration / 16); let current = start; const timer = setInterval(() => { current += increment; if (current >= target) { current = target; clearInterval(timer); } element.textContent = Math.floor(current); }, 16); } addFloatingShapes() { const hero = document.querySelector('.hero-gradient'); if (!hero) return; const shapesContainer = document.createElement('div'); shapesContainer.className = 'floating-shapes'; for (let i = 0; i < 3; i++) { const shape = document.createElement('div'); shape.className = 'floating-shape'; shapesContainer.appendChild(shape); } hero.appendChild(shapesContainer); } static typeWriter(element, text, speed = 100) { let i = 0; element.textContent = ''; function type() { if (i < text.length) { element.textContent += text.charAt(i); i++; setTimeout(type, speed); } } type(); } static revealText(element) { const text = element.textContent; const words = text.split(' '); element.innerHTML = ''; words.forEach((word, index) => { const span = document.createElement('span'); span.textContent = word + ' '; span.style.opacity = '0'; span.style.transform = 'translateY(20px)'; span.style.transition = `all 0.6s ease ${index * 0.1}s`; element.appendChild(span); setTimeout(() => { span.style.opacity = '1'; span.style.transform = 'translateY(0)'; }, 100); }); } static setupSmoothScroll() { document.querySelectorAll('a[href^="#"]').forEach(anchor => { anchor.addEventListener('click', function (e) { e.preventDefault(); const target = document.querySelector(this.getAttribute('href')); if (target) { target.scrollIntoView({ behavior: 'smooth', block: 'start' }); } }); }); } } document.addEventListener('DOMContentLoaded', () => { new PortfolioAnimations(); PortfolioAnimations.setupSmoothScroll(); }); window.PortfolioAnimations = PortfolioAnimations; function initScrollAnimations() { const observerOptions = { threshold: 0.1, rootMargin: '0px 0px -50px 0px' }; const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { const delay = entry.target.dataset.delay || 0; setTimeout(() => { entry.target.classList.add('visible'); }, delay); } }); }, observerOptions); document.querySelectorAll('.animate-on-scroll').forEach(el => { observer.observe(el); }); } function initMagneticEffect() { const magneticElements = document.querySelectorAll('.magnetic'); magneticElements.forEach(el => { el.addEventListener('mousemove', (e) => { const rect = el.getBoundingClientRect(); const x = e.clientX - rect.left - rect.width / 2; const y = e.clientY - rect.top - rect.height / 2; el.style.transform = `translate(${x * 0.1}px, ${y * 0.1}px) scale(1.02)`; }); el.addEventListener('mouseleave', () => { el.style.transform = 'translate(0px, 0px) scale(1)'; }); }); } document.addEventListener('DOMContentLoaded', () => { initScrollAnimations(); initMagneticEffect(); });