Jump to content
Search Community

Search the Community

Showing results for 'overwrite'.

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • GreenSock Forums
    • GSAP
    • Banner Animation
    • Jobs & Freelance
  • Flash / ActionScript Archive
    • GSAP (Flash)
    • Loading (Flash)
    • TransformManager (Flash)

Product Groups

  • Club GreenSock
  • TransformManager
  • Supercharge

Categories

There are no results to display.


Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


Personal Website


Twitter


CodePen


Company Website


Location


Interests

Found 1,407 results

  1. @Rodrigo Thank you for this tip. I used the ScrollTrigger Batch and it seems to be working. The final code is something like this useEffect(() => { gsap.set(cardRef.current, { autoAlpha: 0, y: 60 }) const show = (batch) => { gsap.set(batch, { autoAlpha: 0, y: 60 }) batch.forEach((item, i) => { gsap.timeline().to(item, { autoAlpha: 1, y: 0, overwrite: true, duration: 0.9, stagger: 0.2, ease: 'back.out' }) }) } const hide = (batch) => { gsap.set(batch, { autoAlpha: 0, y: 60, overwrite: true }) } const createBatch = (target) => { ScrollTrigger.refresh() ScrollTrigger.batch(target, { onEnter: show, onLeave: hide, onEnterBack: show, onLeaveBack: hide, markers: true, start: 'top 80%', end: '100% -10%' }) } createBatch(cardRef.current) }, [isSuccess, cardRef]) useEffect(() => { isSuccess && ScrollTrigger.refresh(true) }, [isSuccess]) In createBatch(), the ScrollTrigger.refresh() is required for it to work properly otherwise it is just like before. If you see any mistake in above code please tell me. Thank You very much for you help.
  2. Hi I've been struggling with the issue of conflicting timelines/tweens over and over again. Notice how in the example, the "more info" divs are consistently not appearing after resizing the browser window while the animation is playing (you'll have to open the example in a new tab to see the problem). https://codepen.io/ynamite/pen/jOeovBm I can't seem to revert a timeline/tween to it's initial state and reinitializing the timeline/animation after resizing the browser window. I've tried killing and/or clearing a timeline, I've tried spamming `overwrite: true` everywhere, I've tried debouncing the resize event etc. I'm at a wits end ... I've checked the forum but could only find the solutions I've already tried. Neither overwriting nor killing/clearing tweens/timelines seems to do the job, at least not in all cases. Sometimes it works and in other cases it just doesn't. It feels inconsistent and my code is starting to feel quite hacky. I'm probably missing a thing or doing something wrong. The example shown on the following page seems to exhibit the same behaviour I'm experiencing: Once you click on "move back" and then click on "restart" the animation seems to break. At least in the way that I understand it. By clicking "restart" I'd expect the element to move back to the right edge and roll back to the left (like it doesk on page load). Instead it just hangs and rolls on the left. Thanks!
  3. Hi there, I'm using near latest npm greensock (3.11.4), and there seems to be a change in behaviour since version 2.0.1 and I'm not sure how to resolve it. Before I could have 3 items with infinitely repeating tween inside a timeline, but later I want to stop those tweens on a delay (so they don't stop at the same time), but I don't want to pause the timeline... so I'd add my tweens to a timeline like this: ``` // start rows anim this.spinTimeline = new TimelineLite({paused:true}); _.each(this.rows, (row, i) => { var slideTween = new TweenMax(row.sprite, 3, {x: row.offset, ease: Power0.easeNone, repeat: -1 }); this.spinTimeline.add(slideTween , "startRowT" + i, "-=0.1"); }); this.spinTimeline.play(); ``` then later I could stop them animating repeatedly by just calling a new tween on the row.sprite, with a slightly increasing delay on each, and the animations would transition smoothly from repeating x to landing on a specific point on the x axis. ``` stopRows() { _.each(this.rows, (row, i) => { TweenMax.to(row.sprite, 0.75, {x: row.offset, ease: Elastic.easeOut, delay: 0.75 * i, onComplete: this.animComplete.bind(this) }); }); } ``` Now with latest gsap versions I can't figure out how to recreate this. the repeating tween just keeps playing after the stopping tween finishes. If I pause the timeline first, it works but the repeating anims pause immediately.. If I use overwrite: true, then the repeating anims pause immediately (not when the stop anim starts after the delay). If I use timeline.killTweensOf(row.sprite) onStart, then it happens immediately, (not after the delay).. so i can't transition from one tween to the other anymore. My new code looks like this: ``` // start anim const tl = this.tl; this.rows.map((row, i) => { const offsetX = row.container.width / 2; tl.to(row.container, {x: offsetX, duration: 3, ease: 'none', repeat: -1}); }); tl.play(); // stop anim: this.rows.map((row, i) => { const toX = row.stopOffset; gsap.to(row.container, { duration: 1, x: toX , ease: 'elastic.out', delay: 0.75 * i, overwrite: true, // i'd expect this overwrite to happen after the delay, not immediately. onComplete: () => { //this.tl.killTweensOf(row.container); this.state = 'ready'; }, }); }); Edit: I found the problem, I needed to remove the duration from my new version and use t.killTweensOf in the onComplete (the line i had commented!).. that works as I want now!
  4. Hey, I have found a great and straightforward demo on the forum of repeat and reverse animation, which was created by @mikel. Here it is https://codepen.io/mikeK/pen/dyooKjJ But using the latest GSAP version, the reverse animation doesn’t work the same as in the 3.1.1 version. The animation doesn’t stop on mouseleave. My main goal is to have repeated animation on mouseenter. But on mouseleave, I need to reverse only once instead of reversing the whole repeats. I understand I can do that with tweens and overwrite properties on mouseleave, but I'm looking for a better solution with timeline. Can you help me, please? Below is the same animation with the latest GSAP version.
  5. Hi, The issue is that the calculations ScrollTrigger is making here when creating the linkST instances: let menu = gsap.utils.toArray(".nav a"); menu.forEach((a) => { let element = document.querySelector(a.getAttribute("href")), linkST = ScrollTrigger.create({ trigger: element, start: "top top" }); a.addEventListener("click", (e) => { e.preventDefault(); gsap.to(window, { duration: 1, scrollTo: linkST.start, overwrite: "auto" }); }); }); Are being affected by the ScrollTrigger instances created in the panels loop. Since you know that the home section is at the top of the document just use zero there: a.addEventListener("click", (e) => { e.preventDefault(); const target = e.target.getAttribute("href") === "#home" ? 0 : linkST.start; gsap.to(window, { duration: 1, scrollTo: target, overwrite: "auto", }); }); Finally is worth noticing that pinType : "sticky" is not an option. It's either "fixed" or "transform" pinType "fixed" | "transform" - by default, position: fixed is used for pinning only if the scroller is the <body>, otherwise transforms are used (because position: fixed won't work in various nested scenarios), but you can force ScrollTrigger to use position: fixed by setting pinType: "fixed". Typically this isn't necessary or helpful. Beware that if you set the CSS property will-change: transform, browsers treat it just like having a transform applied, breaking position: fixed elements (this is unrelated to ScrollTrigger/GSAP). Hopefully this helps. Happy Tweening!
  6. Hi, I'm trying to figure out how to reposition and scale an element that has been scaled by a previous animation. The previous animation may have been completed and killed at the time the next animation is called. Overwrite appeared to work only if the animation that positioned and scaled the element previously had not been killed. In this example, I'd like to first apply new position and size attributes, and then apply a new scale. I'd like ellipse1 to end up at the position and scale of ellipse2 after the sequence is completed. Is a sequence like this best accomplished by recording several states in a different order with gsap flip, and animating to those states in the order I'd like them to be played? Thanks for your help!
  7. Yeah, you had !important CSS styles that were interfering. Also, you can simplify this: images.forEach((image) => { if (isEnter) { gsap.to(image, { opacity: 1, scale: 1 }); } else { gsap.to(image, { opacity: 0, scale: 0 }); } }); To this: gsap.to(images, { opacity: isEnter ? 1 : 0, scale: isEnter ? 1 : 0 }); You should also make sure to set opacity/scale to 1 right before the flip in case there's a hover animation running and things are partially-tweened. Like if you hover and then almost immediately click the button, the scale might be 0.5 at that point which could contaminate the final state you're flipping to. So do a gsap.set() with overwrite: true to make sure that other tween is killed too. If you click back and forth between the trigger and reverse buttons in @Rodrigo's demo, you'll see some odd behavior because of that. https://codepen.io/GreenSock/pen/dygzdPE?editors=0010
  8. Hi @GreenSock, Thanks for pointing out my misunderstanding. It really helps me understand how the timeline and overwrite works! After building a tiny playground, I found my problem was not about overwriting but states. https://codepen.io/latteouka/pen/gOBmYxz I was trying to tween some "current" elements which need to be set again because "current index" have changed. That is why I was trying to find some solutions about overwriting conflicts. I also had some problems with tweening something before the last delay animation is not yet played. I am happy to stay with the default overwrite: false and more confident about tuning my page transition now. Thank you again for the help.
  9. Hi @latteouka. Thanks for sharing. I don't have time to dig through all that code but I wanted to make sure I pointed out that this is not true: There are no such limits. But you shouldn't create multiple simultaneous tweens that are all trying to control the same property of the same element because obviously the same value can't go in a bunch of different directions at the same time. You might want to consider overwrite: "auto" which only overwrites individual overlapping properties rather than entire tweens (which is what overwrite: true does). If you've got any GSAP-specific questions that you'd like answered, feel free to post them here.
  10. Really like the idea because I don't need to install any other dependencies. Also the logic of the intro/outro animation can be clear thanks to GSAP. I tried to do some page transitions with Next.js and three.js using this technique. What I want to achieve is to combine both html and threejs element in intro/outro animations. Demo After I finished the demo, I wrap the context into a tiny package for my own reuse. @chundev/gtranz I remove the setTimeline, background, setBackground in the context because I didn't use them at all and that also make sure context does not trigger re-render because of state change. The context itself is very simple you can just grab the code from src folder if you need it. I want to share the biggest problem I encountered. As I wrote in the Github readme, if I tweened something that is already be set in the outro. (I need instant scroll animation of the images which are also the outro elements) That will break the transition later because as I researched, one element can only have one tween at a time. (I could barely find information about this topic and struggled for a while) So I set the default to overwrite:true (default is false, in the original post, it only do the simplest css intro/outro so no problems) and arrange the order of animation setup by myself. What I did was: 1. use a state to determine the setup order of intro/outro. (if you overwrite some tweens that are used in the outro.) 2. use custom event to re-setup outro whenever you want (mostly after the animation that tweened the same element, with onComplete callback) I don't really know if it's good practice or not. But I did solve my problem and make nice transition by doing so. Just want to share my experience. I really love this community and learn so much things here. Thank you!
  11. Hey @Rodrigo, Thanks for the recommendations here! I have implemented them and everything is much smoother. My message above was about creating a lerp type of effect fpr the cards using the velocityY property - that's what that this chunk is trying to do using onUp or onDown: const posSetter = gsap.quickSetter(cards, "x", "%"); const clamp = gsap.utils.clamp(-20, 20); const lerp = [8, 16, 24]; const proxy = { x: 0 }; Observer.create({ target: cardItems, type: "wheel,touch,pointer", onUp: (self) => { let lapsedProgress; if (lapsedProgress === 1) return; lapsedProgress = scrollTl.progress() - 0.075; progressTo(lapsedProgress); const x = clamp((self.velocityY / -300) * lerp[Math.floor(Math.random() * lerp.length)]); if (Math.abs(x) > Math.abs(proxy.x)) { proxy.x = x; gsap.to(proxy, { x: 0, duration: 0.8, ease: "none", overwrite: true, onUpdate: () => posSetter(proxy.x) }); } }, }) I guess this is a better example of what i'm trying to do, but wanted to use the velocityY property: https://codepen.io/GreenSock/pen/wvMeNee?editors=0010 Do you think this is doable or should I go down the route of the above example? Here is the updated Codepen for reference: https://codepen.io/jackkemm/pen/RwearyE?editors=0011 EDIT: One thing I noticed too, on mobile/touch devices, the scroll is in the opposite direction. I have tried adding -1 to wheelSpeed and scrollSpeedfor touch devices but the scroll is still in the opposite direction. Is there a way to change this? Thanks, Jack
  12. I'll also have to read up on the overwrite: true. I hadn't come across that in my Googling, either.
  13. Yep, sorta like this: https://codepen.io/GreenSock/pen/oNaxdje?editors=1010 Better? And the reason the killTweensOf() helped is because you were creating a TON of conflicting tweens all trying to control the same properties of the same element. You could have solved it equally well by setting overwrite: true. None of that is necessary if you use the gsap.quickTo() technique.
  14. @GreenSock I would like to re-open this topic once more. On the same example, try to scroll using laptop trackpad, as using mouse it seems to be working fine. And try to do long, short scrolls. The scrollbar then goes to the end of next section, but automatically scrolls back to to top section. overwrite or autoKill seems not helping
  15. It looks like you're creating a ton of conflicting tweens that are fighting with each other. Set overwrite: true on your tween to have it immediately kill all other tweens of the same target. And I'm not sure why you're using two different ScrollTriggers for each element - why not just use one? https://stackblitz.com/edit/vue-fchh5m?file=src%2FApp.vue
  16. @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;
  17. I'd probably add a small delay on the "reset" tween and set overwrite to true. Something like this: https://codepen.io/PointC/pen/ZEMjdLj/364a470e414172b8fbd6a7420de056f6 More info about overwrite. Happy tweening.
  18. Hi @Roman S. is you're issue that your elements are not obeying the width you've set? That is because flexbox is trying to 'help', flexbox will automatically distribute the elements over the width you've given it. You can overwrite that using the flex-grow, flex-shrink and flex-basis property or the short hand flex: 0 0 "your width". You're right that this is a CSS issue and we like to focus these forums to just GSAP related questions. Still hope it helps and happy tweening! https://codepen.io/mvaneijgen/pen/GRXOvgo?editors=0110
  19. Hmm.. So I tried the Attribute Plugin using this code, but it doesn't work with my SVG. Actually it doesn't seem to work with the basic div's either. let elements = document.querySelectorAll('.button'); let clickEvent = (e) => { console.log('some event content here...') console.log("----------------" + e.target.id + "----------------------") } elements.forEach((item) => { item.addEventListener("mouseenter", ()=>{ gsap.to(item, {attr: {fill: "#F2653A"}, duration: 1, overwrite: "auto" }); }); item.addEventListener("mouseout", ()=>{ gsap.to(item, {attr: {fill: "red"} ,duration: 1, overwrite: "auto" }); }); item.addEventListener('click', clickEvent) }); });
  20. Hmm.. So I tried the Attribute Plugin using this code, but it doesn't work with my SVG. let elements = document.querySelectorAll('.button'); let clickEvent = (e) => { console.log('some event content here...') console.log("----------------" + e.target.id + "----------------------") } elements.forEach((item) => { item.addEventListener("mouseenter", ()=>{ gsap.to(item, {attr: {fill: "#F2653A"}, duration: 1, overwrite: "auto" }); }); item.addEventListener("mouseout", ()=>{ gsap.to(item, {attr: {fill: "red"} ,duration: 1, overwrite: "auto" }); }); item.addEventListener('click', clickEvent) }); });
  21. Nice job, @Toso ? Minor tweaks: https://codepen.io/GreenSock/pen/KKxXjvW?editors=0010 I'd use backgroundColor rather than background, and I'd set the overwrite to either true or "auto" just in case the user rolls over/out quickly, you don't want to create conflicting animations.
  22. Yes you can! Like you do with CSS you can call all your elements at once and then use a stagger (see Stagger docs) to have them animate in one by one. Then when using a smart position parameter we can start the next animation right after the first one is done! Also you can target all transform properties directly with GSAP x, y, rotate, skew, scale ect and if you want to use percentage based values use xPercent and yPercent. I would also recommend keeping all he animation values to GSAP instead of setting something with in CSS that you then need to overwrite with GSAP, that is where .from() is really handy. I've sprinkled a lot of useful comments throughout your pen to explain certain parts, be sure to read through them! Hope it helps and happy tweening! https://codepen.io/mvaneijgen/pen/GRXmQqV?editors=0100 Oh and a side note! When working with ScrollTrigger I like to disable it, to really focus on just the animation I find it a lot easier. I've also added a repeat: -1, so be sure to remove those when you're going to enable ScrollTrigger again.
  23. Hello all, So in this codepen example I use Flip.from to get items into grid slots, and then on another flip to get them back in old parent, but also to transform each item to value I set with gsap.set. This works too, but on 3rd click, when I want to animate items again into grid, the gsap.set doesnt set xPercent value back to 0. I also tried overwrite: true but it didnt work. Is there something Im missing? Thanks
  24. Hi, I've been fiddling with your codepen example for a bit and this seems to do the trick: ScrollTrigger.create({ trigger: ".images", start: "center top", markers: true, onEnter: self => { let state = Flip.getState(images); images.forEach((image, i) => slots[i].appendChild(image)); gsap.set(images, {xPercent: 0, rotation: 0}); Flip.from(state, { duration: 6, overwrite: true, // <- HERE ease: "power1.inOut" }) } }) Since the first ScrollTrigger instance you're creating for the images has once: true, it doesn't really matter if the Flip animation overwrites those. In the tests that I've ran seems to work as expected: https://codepen.io/GreenSock/pen/ZEMeBKR Hopefully this helps. Let us know if you have more questions. Happy Tweening!
  25. That's because you created conflicting animations - you've got your motionPath animation first in the timeline that controls the x/y position, and then you ALSO have another one that's affecting x to go in a completely different direction. So they're both fighting for control. If you do overwrite: "auto" (or true), all that does is basically KILL the overwritten part (so of course you won't see it affecting things after that point at all). You definitely should not be creating conflicting animations like that. The reason it looks different when scrolling forwards vs backwards is because the rendering order inverts in reverse. In other words, when moving the playhead forward, the LATER tween would render last whereas when moving the playhead backwards, the EARLIER tween would render last. That's exactly how it's supposed to work. Possible solutions: Don't overlap the animations. https://codepen.io/GreenSock/pen/dyqNQRR?editors=1010 Use a different (invisible) motionPath that has the shape you want. Basically copy the path you have now, but add that extra part at the top that's curved in the way you want your objects to travel. You can still leave the red stroked path as-is. Everything would look the same visually, but you'd just use one motionPath tween where the path actually has the shape you're going for. You technically could write a bunch of extra JavaScript to force things to render in a particular order no matter which direction the playhead travels, but honestly that seems quite hacky and unintuitive to me. It is doable, though. If you need help with that, we're available for paid custom consulting - just reach out directly to explore those options. I hope that helps!
×
×
  • Create New...