Jump to content
Search Community

pravSab

Members
  • Posts

    7
  • Joined

  • Last visited

Everything posted by pravSab

  1. @Cassie @GreenSock Thanks for the reply, however I am using 2 timelines with same pin value, as I need to implement the following scenarios 1. I need to scale out the image or video from starting to its final value - Timeline 1 with same pin value. - It's working perfectly ( imageTimelineAnimation in the below code) 2. The second timeline is for snap scrolling the other images / Videos while the component is pinned. - Timeline 2 - This also works. (snapScrollAnimation in the below code) however the pinning is working and animation also plays smooth, but it's leaving large space at the bottom for desktop, tablet, mobile. I am adding margin bottom to the main container to adjust the bottom spacing. but while doing snap scrolling until I reach the last element it never appears on the screen, I have given fixed height for the container as well but not helping. I want to make the next element of the container to be maintaining the exact bottom spacing which I want to but struggling to achieve that. Need your suggestion if you know anything I'm missing. The elements I'm making animations are inside a grid container - FYI I understand that it'll be tough to understand to provide any suggestions based on the explanation on this, but whatever I know I have posted here to seek help on this. I would like to tell you that it's a really great package, you guys are Rockstars. Keep rocking. This is my code for your reference, it's huge but it gives you overall picture of what I'm trying to do ( Starting Point InitializeAnimation ) import gsap from 'gsap'; import { ScrollTrigger } from 'gsap/dist/ScrollTrigger'; export function getScrollY() { return window.pageYOffset != null ? window.pageYOffset : document.documentElement.scrollTop != null ? document.documentElement.scrollTop : document.body.scrollTop; } export function isLandscape() { return window?.matchMedia('(orientation: landscape)')?.matches; } export function detectTabletOrientation() { return isLandscape() && window.innerWidth < 1180 ? '10% 65%' : isLandscape() && window.innerWidth >= 1180 && window.innerWidth < 1400 ? '10% 80%' : '20% 50%'; } let currentCount = 0; // Text Area - START export const slidePrevNextText = (current, next) => { const currentText = gsap.fromTo( current, { autoAlpha: 1, duration: 1, overwrite: 'auto', paused: true, x: 0, }, { autoAlpha: 0, duration: 1, overwrite: 'auto', paused: true, x: '-200px', } ); const nextText = gsap.fromTo( next, { autoAlpha: 0, duration: 1, overwrite: 'auto', paused: true, x: 0, }, { autoAlpha: 1, duration: 1, overwrite: 'auto', paused: true, x: 0, } ); currentText.play('<'); nextText.play('>'); return [currentText, nextText]; }; export const slidePrevNextTextReverse = (current, next) => { const currentText = gsap.fromTo( current, { autoAlpha: 1, duration: 1, overwrite: 'auto', paused: true, x: 0, }, { autoAlpha: 0, duration: 1, overwrite: 'auto', paused: true, x: 0, } ); const nextText = gsap.fromTo( next, { autoAlpha: 0, duration: 1, overwrite: 'auto', paused: true, x: '-200px', }, { autoAlpha: 1, duration: 1, overwrite: 'auto', paused: true, x: 0, } ); currentText.play('<'); nextText.play('>'); return [currentText, nextText]; }; // Text Area - END // Initial Move out animation for Device asset and Optional Element const mainContainerTween = (id, isTablet, isMobile) => gsap.fromTo( `div#device-${id} .device-outline-border`, { duration: 2, opacity: 1, overwrite: 'auto', paused: true, stagger: 0.1, visibility: 'visible', x: 0, y: 0, yPercent: 0, }, { duration: 2, opacity: 1, overwrite: 'auto', paused: true, stagger: 0.1, visibility: 'visible', x: isTablet ? -135 : -225, y: !isTablet && !isMobile ? -50 : 0, yPercent: !isTablet ? -4 : 0, } ); const childContainerTween = (id, isTablet) => gsap.fromTo( `div#device-${id} div.child-container`, { bottom: '0', duration: 2, left: isTablet ? '9%' : '14%', opacity: 0, overwrite: 'auto', paused: true, position: 'relative', right: '0', stagger: 0.1, top: '-35%', visibility: 'hidden', x: 0, y: !isTablet ? -150 : 0, }, { bottom: '0', duration: 2, opacity: 1, overwrite: 'auto', paused: true, position: 'relative', right: '0', stagger: 0.1, visibility: 'visible', x: isTablet && window.innerWidth < 1024 ? 350 : isTablet && window.innerWidth >= 1024 ? 420 : 520, y: !isTablet ? -125 : -36, } ); const progressButtonTween = (id) => gsap.fromTo( `.progress-container--${id}`, { opacity: 0, overwrite: 'auto', paused: true, visibility: 'hidden', }, { opacity: 1, overwrite: 'auto', paused: true, visibility: 'visible', } ); const progressButtonPositionSet = (id, buttonStyles?) => gsap.set(`.progress-container--${id}`, { ...buttonStyles, }); const progressElementPosition = (id, styles) => gsap.set(`.progress-container--${id}`, { ...styles, }); const fullScreenTween = (id, isTablet?) => gsap.fromTo( `div#device-${id} .full-screen`, { duration: 0.6, opacity: 0, overflowY: isTablet ? 'hidden' : 'auto', visibility: 'hidden', }, { duration: 0.6, opacity: 1, overflowY: 'auto', visibility: 'visible', } ); const firstImageGradientTween = (id) => gsap.fromTo( `div#device-${id} div.asset-overlay`, { duration: 0.6, opacity: 1, paused: true, visibility: 'visible', }, { duration: 0.6, opacity: 0, paused: true, visibility: 'hidden', } ); export const scrollWindowToTween = (value, seconds?) => gsap.to(window, { duration: seconds ? seconds : 2.25, overwrite: 'auto', paused: true, scrollTo: { y: value, }, }); const firstTextAreaTween = (id, isMobile?, isTablet?) => gsap.fromTo( `.tarea--${id}:first-child`, { paused: true, y: 0, }, { paused: true, y: isMobile ? -10 : 0, } ); export const initialImageAnimation = (id, isTablet, isMobile) => { const dCards = gsap?.utils?.toArray(`div.asset--${id} div.asset-component`); const sCards = gsap?.utils?.toArray(`div.optional--${id}`); const [, snapTrigger] = ScrollTrigger.getAll(); return scrollWindowToTween(snapTrigger.start, 2.5) .play() .eventCallback('onStart', () => { firstImageGradientTween(id).play('<'); firstTextAreaTween(id, isMobile, isTablet).play('<'); gsap.to(`div#device-${id} div.drop-shadow`, { opacity: 1, transition: 'opacity 1s, visibility 1s', visibility: 'visible', }); }) .eventCallback('onComplete', () => { if (!isMobile) { if (secondaryCards.length > 0 && window.innerHeight > 719) { mainContainerTween(id, isTablet, isMobile).play('-=2.5'); childContainerTween(id, isTablet) .play('-=2.5') .eventCallback('onStart', () => { if (isTablet && window.innerWidth > 600 && window.innerWidth < 1024) { gsap.to(`div#device-${id} div.child-container`, { inset: window.innerWidth < 820 ? `-20% 0px 0px 2%` : `-20% 0px 0px 7%`, }); } }); } if (dCards.length > 1) { progressButtonTween(id).play('>'); } if (dCards.length >= 1) { fullScreenTween(id, isTablet).play('>'); } } }); }; export const reverseInitialImageAnimation = (id, isTablet, isMobile) => { const dCards = gsap?.utils?.toArray(`div.asset--${id} div.asset-component`); const sCards = gsap?.utils?.toArray(`div.optional--${id}`); const [imageTrigger] = ScrollTrigger.getAll(); return scrollWindowToTween(imageTrigger.start - 50, 2.5) .play() .eventCallback('onStart', () => { firstImageGradientTween(id).reverse('<'); firstTextAreaTween(id).reverse('<'); if (!isMobile) { if (sCards.length > 0) { mainContainerTween(id, isTablet, isMobile).reverse('-=1.5'); childContainerTween(id, isTablet).reverse('-=1.5'); gsap.to(`div#device-${id} div.drop-shadow`, { opacity: 0, transition: 'opacity 1s, visibility 1s', visibility: 'hidden', }); } if (dCards.length > 1) { progressButtonTween(id).reverse(0); } if (dCards.length >= 1) { fullScreenTween(id, isTablet).reverse(0); } } }); }; async function finishOnFastLeave( { isActive, progress, getVelocity, animation, direction }: ScrollTrigger, current: number, id: any ) { const dCards = gsap?.utils?.toArray(`div.parent-container div.asset--${id}`); const sCards = gsap?.utils?.toArray(`div.child-container div.optional--${id}`); const textElements = gsap?.utils?.toArray(`.tarea--${id}`); const progressValue = +progress.toPrecision(2) * 100; const length = dCards.length - 1; const index = Math.round(+(+(progressValue / 100).toPrecision(1) * length).toPrecision(1)); const currentCard: any = dCards[current]; const currentSecondaryCard: any = sCards[current]; const targetCard: any = dCards[index]; const targetSecondaryCard: any = sCards[index]; if (!isActive && Math.abs(getVelocity()) > 1000) { await animation.progress(progress === 1 ? 1 : 0).pause(); slideTween(targetCard, targetSecondaryCard) .play() .eventCallback('onStart', () => { slidePrevNextText(textElements[current], textElements[index]); const currentElements: any = textElements.filter((ele, i) => i !== index); gsap.set([...currentElements], { autoAlpha: 0, }); }) .eventCallback('onComplete', () => { slideTween(currentCard, currentSecondaryCard).reverse(); }); } } // first card Animation here export const firstImageAnimation = (id, setInViewport, isTablet, isMobile, theme) => { const dCards = gsap?.utils?.toArray(`div.asset--${id} div.asset-component`); imageTimelineAnimation = gsap.timeline({ ease: 'Power3.easeOut', paused: true, reversed: true, scrollTrigger: { end: (self) => !isTablet && !isMobile ? self.next().start - 10 : isMobile ? self.next().start : self.next().start - 50, fastScrollEnd: true, invalidateOnRefresh: true, onEnter: () => { setInViewport(true); }, onEnterBack: ({ isActive, animation }) => { if (isActive) { animation.scrollTrigger.vars.scrub = 2; reverseInitialImageAnimation(id, isTablet, isMobile); setInViewport(false); } }, onLeave: () => { if (dCards.length === 1) { setInViewport(false); } }, onLeaveBack: () => { firstImageGradientTween(id).reverse(); }, onToggle: async ({ isActive, getVelocity, direction, animation, progress }) => { if (!isActive && currentCount > 0 && direction === -1 && getVelocity() < 0) { await animation.progress(progress === 1 ? 1 : 0).pause(); gsap.set([`.asset--${id}:first-child`, `.optional--${id}:first-child`], { opacity: 1, visibility: 'visible', yPercent: 0, }); gsap.set([`.asset--${id}:not(:first-child)`, `.optional--${id}:not(:first-child)`], { opacity: 0, visibility: 'hidden', yPercent: 100, }); } }, pin: `.container--${id} div.ui-demo-container--${id}`, scrub: 2, start: () => (isMobile ? '5% 50%' : isTablet ? detectTabletOrientation() : '20% 55%'), trigger: `div.asset-container--${id} div.asset-${id}-0`, // markers: {startColor: 'blue', endColor: 'black'}, }, }); imageTimelineAnimation .fromTo( `div#device-${id} .transparent-border`, { duration: 0.5, opacity: 0.95, outline: 'none', }, { duration: 0.5, onStart: async (self) => { await initialImageAnimation(id, isTablet, isMobile); }, opacity: 1, outline: !isMobile && !isTablet ? '4px solid' : isMobile ? '1.72px solid' : '2px solid', } ) return imageTimelineAnimation; }; export const slideTween = (nextCard, nextSecondaryCard?) => gsap.fromTo( [nextCard, nextSecondaryCard], { autoAlpha: 0, duration: 1.25, paused: true, stagger: 0.1, yPercent: 100, }, { autoAlpha: 1, duration: 1.25, paused: true, stagger: 0.1, yPercent: 0, } ); export const onStartTweens = (currentIndex, nextIndex, textElements) => { slidePrevNextText(textElements[currentIndex], textElements[nextIndex]); const currentElements: any = textElements.filter((ele, i) => i !== currentIndex); gsap.set([...currentElements], { autoAlpha: 0, }); }; function checkIfAnyOverlap(rect1: any, rect2: any) { return !( rect1.right < rect2.left || rect1.left > rect2.right || rect1.bottom < rect2.top || rect1.top > rect2.bottom ); } export const checkForElementOverlap = (id) => { const element = document ?.querySelector(`section#${id} div.ui-demo-container--${id}`) ?.getBoundingClientRect(); const nextSiblingElement = document.querySelector(`section#${id}`)?.nextElementSibling?.getBoundingClientRect(); const mainElement = document.querySelector(`main`).getBoundingClientRect(); if ( (!!nextSiblingElement && checkIfAnyOverlap(element, nextSiblingElement)) || (!!mainElement && checkIfAnyOverlap(element, mainElement)) ) { return !!nextSiblingElement ? nextSiblingElement?.top - element?.bottom : mainElement?.bottom - element?.bottom; } else { return false; } }; export const handleBottomSpacing = (id, isTablet, isMobile) => { const element = document ?.querySelector(`section#${id} div.ui-demo-container--${id}`) ?.getBoundingClientRect(); const childContainer = document?.querySelector(`section#${id} div.child-container`)?.getBoundingClientRect(); const value = element?.bottom > childContainer?.bottom ? Math.round(element?.bottom - childContainer?.bottom) : Math.round(childContainer?.bottom - element?.bottom); if (!isMobile && !isTablet) { gsap.set(`section#${id}`, { marginBottom: element?.bottom > childContainer?.bottom ? (value > 0 ? 96 - value : 96 + value) : 96, }); } else if (!isMobile && isTablet) { gsap.set(`section#${id}`, { marginBottom: element?.bottom > childContainer?.bottom ? (value > 0 ? 64 - value : 64 + value) : 64, }); } }; export const goToCard = (progress: number, direction: number, index: number, currenIndex: number, nextCount: number, id: string) => { const dCards = gsap?.utils?.toArray(`div.parent-container div.asset--${id}`); const sCards = gsap?.utils?.toArray(`div.child-container div.optional--${id}`); const textElements = gsap?.utils?.toArray(`.tarea--${id}`); const currentCard: any = dCards[currenIndex]; const currentSecondaryCard: any = sCards[currenIndex]; const nextCard: any = dCards[nextCount]; const nextSecondaryCard: any = sCards[nextCount]; const targetCard: any = dCards[index]; const targetSecondaryCard: any = sCards[index]; if (index === currenIndex && direction === 1) { slideTween(nextCard, nextSecondaryCard) .play() .eventCallback('onStart', () => onStartTweens(index, nextCount, textElements)) .eventCallback('onComplete', () => { slideTween(currentCard, currentSecondaryCard).reverse(); }); } else if (index === currenIndex && direction === -1) { slideTween(currentCard, currentSecondaryCard).reverse(-0.5); slideTween(nextCard, nextSecondaryCard) .play('-=0.5') .eventCallback('onStart', () => onStartTweens(index, nextCount, textElements)); } else if (index > currenIndex) { slideTween(targetCard, targetSecondaryCard) .play() .eventCallback('onStart', () => onStartTweens(currenIndex, index, textElements)) .eventCallback('onComplete', () => { slideTween(currentCard, currentSecondaryCard).reverse(); }); } else if (index < currenIndex) { slideTween(targetCard, targetSecondaryCard) .play() .eventCallback('onStart', () => { const currentElements: any = textElements.filter((ele, i) => i !== currenIndex); gsap.set([...currentElements], { autoAlpha: 0, }); slidePrevNextTextReverse(textElements[currentCount], textElements[index]); }) .eventCallback('onComplete', () => { slideTween(currentCard, currentSecondaryCard).reverse(); }); } }; export const snapTimeline = (id, stateMethods) => { const { setActive, setInViewport, isTablet, isMobile } = stateMethods; const dCards = gsap?.utils?.toArray(`div.parent-container div.asset--${id}`); const sCards = gsap?.utils?.toArray(`div.child-container div.optional--${id}`); const textElements = gsap?.utils?.toArray(`.tarea--${id}`); if (dCards.length > 1) { const getEnd = () => { return isMobile ? 'bottom' : isTablet ? 'bottom top' : '+=5000'; }; snapScrollAnimation = gsap.timeline({ ease: 'Power3.easeOut', reversed: true, scrollTrigger: { end: () => getEnd(), endTrigger: `.ui-demo-container--${id} div.snap-last`, fastScrollEnd: true, invalidateOnRefresh: true, onEnterBack: () => { currentCount = dCards.length - 1; setActive(currentCount); setInViewport(true); }, onLeave: (self) => { currentCount = dCards.length - 1; setActive(currentCount); }, onLeaveBack: () => { currentCount = 0; setActive(0); setInViewport(true); }, onToggle: (self) => { finishOnFastLeave(self, dCards.length - 1, id); }, pin: `.container--${id} .ui-demo-container--${id}`, preventOverlaps: true, scrub: 2, // markers: true, snap: { duration: 1, ease: 'none', onComplete: ({ progress, direction }) => { const progressValue = +progress.toPrecision(2) * 100; const length = dCards.length - 1; const index = Math.round(+(+(progressValue / 100).toPrecision(1) * length).toPrecision(1)); currentCount = index; handleBottomSpacing(id, isMobile, isTablet); }, onStart: ({ progress, direction }) => { const progressValue = +progress.toPrecision(2) * 100; const length = dCards.length - 1; const index = Math.round(+(+(progressValue / 100).toPrecision(1) * length).toPrecision(1)); const nextCount = currentCount + 1 < dCards.length && direction === 1 ? currentCount + 1 : currentCount - 1 > 0 ? currentCount - 1 : 0; if (index > currentCount) { setActive(index); } else if (index < currentCount) { setActive(index); } else { setActive(nextCount); } goToCard(progress, direction, index, currentCount, nextCount, id); }, snapTo: 1 / (dCards?.length - 1), }, start: () => (isMobile ? 'top 9%' : isTablet ? 'top 4.5%' : 'top 5%'), trigger: `.ui-demo-container--${id} div.snap-first`, }, }); } return snapScrollAnimation; }; // tslint:disable-next-line: no-big-function export const initializeAnimation = async (id, stateMethods) => { const dCards = gsap?.utils?.toArray(`div.asset--${id} div.asset-component`); const secondaryCards = gsap?.utils?.toArray(`div.optional--${id}`); const { setInViewport, isTablet, isMobile, theme } = stateMethods; firstImageAnimation(id, setInViewport, isTablet, isMobile, theme); snapTimeline(id, stateMethods); const matchMediaRef: gsap.MatchMedia = gsap?.matchMedia(); const desktopTabletSet = () => { gsap.set(`.asset--${id}:first-child`, { opacity: 1, visibility: 'visible', yPercent: 0, }); gsap.set(`.asset--${id}:not(:first-child)`, { opacity: 0, visibility: 'hidden', yPercent: 100, }); gsap.set(`div#device-${id} div.asset-overlay`, { visibility: 'visible', opacity: 1 }); dCards.forEach((assetCard: HTMLDivElement, i) => { const secondaryCard: any = secondaryCards[i]; if (i === 0) { gsap.set(`div#device-${id} .outline-border`, { background: 'transparent', scale: isTablet ? 2 : 1.5, }); gsap.set(`div#device-${id} .transparent-border.${theme}`, { background: 'transparent', borderColor: 'transparent', borderRadius: '0px', }); gsap.set(`.tarea--${id}:first-child`, { opacity: 1, visibility: 'visible', x: 0, y: 0, }); gsap.set(secondaryCard, { opacity: 1, visibility: 'visible', yPercent: 0, }); } else { gsap.set(secondaryCard, { opacity: 0, visibility: 'hidden', yPercent: 100, }); } }); if (sCards.length === 0) { mainContainerTween(id, isTablet, isMobile).kill(); progressButtonTween(id).kill(); } if (dCards.length === 1) { progressButtonTween(id).kill(); } else if (dCards.length === 0) { fullScreenTween(id).kill(); progressButtonTween(id).kill(); } }; const mobileSet = () => { gsap.set(`.asset--${id}:first-child`, { opacity: 1, visibility: 'visible', yPercent: 0, }); gsap.set(`.asset--${id}:not(:first-child)`, { opacity: 0, visibility: 'hidden', yPercent: 100, }); gsap.set(`div#device-${id} div.asset-overlay`, { visibility: 'visible', opacity: 1 }); gsap.set( [`div#device-${id} div.child-container`, `div#device-${id} .full-screen`, `.progress-container--${id}`], { display: 'none' } ); childContainerTween(id, isTablet).kill(); fullScreenTween(id, isTablet).kill(); progressButtonTween(id).kill(); mainContainerTween(id, isTablet, isMobile).revert(); gsap.set(`div#device-${id} .outline-border`, { background: 'transparent', scale: 2, }); gsap.set(`div#device-${id} .transparent-border.${theme}`, { background: 'transparent', borderColor: 'transparent', borderRadius: '0px', }); gsap.set(`.tarea--${id}:first-child`, { opacity: 1, visibility: 'visible', x: 0, y: 0, }); }; matchMediaRef .add( [ '(min-width: 960px)', '(min-width: 1440px)', '(min-width: 1920px)', '(min-width: 768px) and (max-width: 1023px)', '(min-width: 768px) and (max-width: 1023px) and (orientation: landscape)', '(min-width: 1024px) and (max-width: 1180px) and (orientation: landscape)', ], () => desktopTabletSet() ) .add( [ '(min-width: 320px) and (max-width: 719px)', '(min-width: 320px) and (max-width: 719px) and (orientation: landscape)', '(max-height: 719px) and (orientation: landscape)', ], () => mobileSet() ); }; export let snapScrollAnimation: gsap.core.Timeline; export let imageTimelineAnimation: gsap.core.Timeline;
  2. Woudn't this create a lot of space if I'm pinning an element and pinSpacing is true, how to avoid pinSpacing in this case ? if I make pinSpacing false the component scroll is overlapping with its below elements, need your help on this. Thanks @GreenSock
  3. What if We want to do for landscape or portrait mode in the above , will it work if I add like below @Zach
  4. and also I am not able to click on the controls(play, pause seek) of the youtube in tablet or mobile, Do I need fix from animation end or youtube end I'm in dilemma, please throw some light if you are known to these issues. @Rodrigo
  5. Iframe not able to load youtube video or autoplay in mobile or tablet, not sure if I'm doing any thing wrong, it works fine in desktop. Here is the CodePen for your reference, apologies I couldn't add the proper stylings in the code, https://codepen.io/Praveen_Saboji/pen/LYBJMNM - For Tablet, Mobile I'm not able to pause or autoplay doesn't work even if I send autoPlay=1, Not sure why this is happening, please help in understanding if I'm missing anything. Thanks.
  6. How to scroll to only next element on mouse wheel and not to any other element ? how to scroll to specific element if I click from any random button from 1 - 5 ? (if I click from 1 - 5 or 5 - 1 incrementally it works fine but not with random button click) how to avoid dragging effect when I scroll in snap scrolling ? do you have any such examples where based on main div scroll, it's children is in sync ?
×
×
  • Create New...