Untitled

 avatar
unknown
javascript
2 months ago
5.3 kB
6
Indexable
/**
 * Portfolio Parallax & Navigation Controller
 * Handles: 7-item swapping, progress tracking, and side-nav visibility.
 */
  //Enable Horizontal Parallax Scrolling
  
const parallaxSection = document.getElementById('parallax-section');
const projectItems = document.querySelectorAll('.project-item');
const sideNav = document.querySelector('.side-nav');
const dots = document.querySelectorAll('.nav-dot');
const totalItems = projectItems.length;

const handleParallaxScroll = () => {
    const sectionRect = parallaxSection.getBoundingClientRect();
    const viewportHeight = window.innerHeight;
    
    // 1. Toggle Side-Nav Visibility
    // Shows the dots only when the portfolio section is active in the viewport
    if (sectionRect.top <= 0 && sectionRect.bottom >= viewportHeight / 2) {
        sideNav.classList.add('show');
    } else {
        sideNav.classList.remove('show');
    }

    // 2. Calculate Overall Progress (0 to 1)
    const totalScrollDist = sectionRect.height - viewportHeight;
    const currentScrollPos = -sectionRect.top;
    
    let overallProgress = currentScrollPos / totalScrollDist;
    overallProgress = Math.max(0, Math.min(overallProgress, 1));

        // 3. Update Each Project Item
    const activeIndex = Math.round(overallProgress * (totalItems - 1));

    projectItems.forEach((item, i) => {
        // itemActiveProgress: 0 is perfectly centered
        const itemActiveProgress = (overallProgress * (totalItems - 1)) - i;
        
        // Determine visibility: 
        // We use isActive for the hard toggle.
        // The "at the end" logic ensures the last item stays visible if we scroll past the section.
        const isActive = (i === activeIndex);

        // Parallax Transforms (Always active for smooth movement)
        const xOffset = itemActiveProgress * -160; 
        const scale = 1 - (Math.abs(itemActiveProgress) * 0.05);
        item.style.transform = `translateX(${xOffset}px) scale(${scale})`;

        // Hard Visibility Toggle (No Fading)
        if (isActive) {
            item.style.opacity = 1;
            item.style.pointerEvents = 'auto';
            item.style.zIndex = 2;
            item.style.visibility = 'visible';
        } else {
            item.style.opacity = 0;
            item.style.pointerEvents = 'none';
            item.style.zIndex = 1;
            item.style.visibility = 'hidden'; // Completely hide non-active items
        }

        // Dot Navigation Update
        if (dots[i]) {
            dots[i].classList.toggle('active', isActive);
        }

        // Internal Image Parallax
        const img = item.querySelector('.parallax-img');
        if (img) {
            // Keeps the image moving slightly even when the item is stationary
            img.style.transform = `translateY(${itemActiveProgress * 40}px)`;
        }
    });
};


// --- Event Listeners ---

window.addEventListener('scroll', handleParallaxScroll);

dots.forEach((dot, index) => {
    dot.addEventListener('click', () => {
        const sectionTop = parallaxSection.offsetTop;
        const totalHeight = parallaxSection.offsetHeight - window.innerHeight;
        const targetScroll = sectionTop + (totalHeight * (index / (totalItems - 1)));
        
        window.scrollTo({
            top: targetScroll,
            behavior: 'smooth'
        });
    });
});

handleParallaxScroll();

// SKILLS & EXPERTISE (Isometric Layers)
document.addEventListener('DOMContentLoaded', () => {
    const layers = document.querySelectorAll('.iso-layer');

    layers.forEach(layer => {
        const img = layer.querySelector('img');

        layer.addEventListener('mouseenter', () => {
            if (!layer.classList.contains('is-active')) {
                img.src = img.getAttribute('data-active');
            }
        });

        layer.addEventListener('mouseleave', () => {
            if (!layer.classList.contains('is-active')) {
                img.src = img.getAttribute('data-default');
            }
        });
    });
});

function handleLayerClick(event, clickedElement) {
    event.stopPropagation();
    const layers = document.querySelectorAll('.iso-layer');
    
    layers.forEach(layer => {
        const img = layer.querySelector('img');
        if (layer === clickedElement) {
            layer.classList.add('is-active');
            img.src = img.getAttribute('data-active');
        } else {
            layer.classList.remove('is-active');
            img.src = img.getAttribute('data-default');
        }
    });
}

window.addEventListener('click', () => {
    document.querySelectorAll('.iso-layer').forEach(layer => {
        const img = layer.querySelector('img');
        layer.classList.remove('is-active');
        img.src = img.getAttribute('data-default');
    });
});

// TEXT PATH ANIMATION
const globalPath = document.getElementById('globalTextPath');
let globalOffset = 0;

function animateGlobalScroll() {
    globalOffset -= 0.02; 
    if (globalOffset < -50) {
        globalOffset = 0;
    }
    if(globalPath) globalPath.setAttribute('startOffset', globalOffset + '%');
    requestAnimationFrame(animateGlobalScroll);
}

animateGlobalScroll();

       
Editor is loading...
Leave a Comment