Jump to content
Search Community

Pollux Septimus

Members
  • Posts

    47
  • Joined

  • Last visited

Everything posted by Pollux Septimus

  1. I believe I have found a viable solution. I have implemented a short delay so that everything is invisible during the refresh process. Additionally, I have modified the animation based on this delay. As for the dependency passed as a constant in the array, it is actually a custom hook that returns a boolean value depending on whether the user is on a mobile device or not. I didn't want to copy the entire hook, so I just set it to a random string to avoid any errors. Thank you all very much for your help.
  2. @Rodrigo Hello, Thank you for your time. I am aware that the code is quite a lot, I was hoping this is something common with React and it has a simple solution. Regarding the useLayoutEffect, I had more issues using it than not. I will try to find a solution myself and If I will I'll let you know.
  3. This is all I could do. For some reason, the styling does not work, but at least the animations work and also the issue is visible. Hope it helps.
  4. useEffect(() => { ScrollTrigger.refresh(); }, [activeTab, isMobile]); Forgot to also show the code.
  5. Thank you! I manage to fix the issue by refreshing the scrollTrigger whenever the tabs are changed. Unfortunately, this creates another issue where the tabs animation runs twice. The first time runs because it's supposed to and the second time because of the refresh. I hope it's clear in the video. Untitled (2).mp4
  6. @GSAP Helper Hello, The templates were very nice and I manage to build this minimal demo. It behaves exactly like it does in my project. @Cassie Hello Cassie, I have added ScrollTrigger.refresh() to the onComplete callback function of the last tween in the animation sequence, on the first component. There is a very high chance that I haven't done it right. I also apologize for the improper grammar. I meant to say that if a component's height changes through any means, and there is a different component below it that uses ScrollTrigger, the start indicator that is visible with the markers: true option does not update to reflect the new position of the component. With the minimal demo that I've linked above it should be clear. Thank you for your answer
  7. Hello, I am using ScrollTrigger in React and I've noticed that the start position doesn't update when a component before it changes height. I've tried refreshing the ScrollTrigger on Complete, but since the different sections are in different components, this doesn't work for me. Sorry for the lack of a minimal demo but the animations are a bit complex for me to be able to quickly put a minimal demo together. Component that changes size import { useState, useEffect, useRef } from 'react'; import gsap from 'gsap'; import { ScrollTrigger } from 'gsap/all'; import useIsMobile from 'hooks/useIsMobile'; import styles from './styles.module.css'; const Tabs = ({ config }) => { const [activeTab, setActiveTab] = useState(0); const [tabsHeight, setTabsHeight] = useState(); const isMobile = useIsMobile(501); const isTablet = useIsMobile(1200); const tl = useRef(); const tabsContainerRef = useRef(); const tabsBG = useRef(); useEffect(() => { setTabsHeight(tabsBG.current.getBoundingClientRect().height); }, [isMobile]); useEffect(() => { gsap.registerPlugin(ScrollTrigger); const context = gsap.context(() => { tl.current = gsap.timeline({ scrollTrigger: { trigger: tabsContainerRef.current, start: 'top bottom-=50', end: 'bottom', toggleActions: 'restart none none reverse', }, }); tl.current .from(tabsBG.current, { width: 45, height: 45, duration: 0.5, }) .from('#tabsID', { opacity: 0, }); }); return () => context.revert(); }, [isMobile, isTablet]); return ( <div ref={tabsContainerRef} className={styles.tabsContainer}> <div className={styles.tabsNav}> <div ref={tabsBG} className={styles.tabsBG}> {config.map((item, index) => ( <div key={index} id='tabsID' className={`${styles.tab} ${ activeTab === index && styles.tabActive }`} onClick={() => setActiveTab(index)} > {item.tab} </div> ))} </div> </div> <div>{config[activeTab]?.content}</div> </div> ); }; export default Tabs; The Component below: import { useState, useEffect, useRef } from 'react'; import AnimatedImage from 'components/AnimatedImage'; import gsap from 'gsap'; import { Link } from 'react-router-dom'; import useIsMobile from 'hooks/useIsMobile'; import styles from './styles.module.css'; const ProjectsSectionDesktop = ({ projectsData }) => { const [hover, setHover] = useState(false); const [animLength, setAnimLength] = useState(false); const [height, setHeight] = useState(); const projectsContainerRef = useRef(); const fadeInTl = useRef(); const scrollTl = useRef(); const trackRef = useRef(); const titleRef = useRef(); const pinContainerRef = useRef(); const isMobile = useIsMobile(1200); useEffect(() => { setAnimLength(trackRef.current.offsetWidth); console.log(height); const context = gsap.context(() => { const projects = gsap.utils.toArray('#projectsContainer'); gsap.set(projects, { xPercent: 50, opacity: 0, }); fadeInTl.current = gsap.timeline({ scrollTrigger: { trigger: pinContainerRef.current, start: 'top bottom', preventOverlaps: true, markers: true, }, }); fadeInTl.current .to(titleRef.current, { opacity: 0.1, duration: 2, ease: 'power1.out', }) .to( projects, { xPercent: 0, opacity: 1, duration: 1, stagger: 0.25, ease: 'power2.out', }, '<' ); }); return () => context.revert(); }, [projectsData, isMobile]); useEffect(() => { setHeight(projectsContainerRef.current.getBoundingClientRect().top); const scrollContext = gsap.context(() => { scrollTl.current = gsap.timeline({ scrollTrigger: { trigger: projectsContainerRef.current, start: 'top top', end: `+=${animLength}`, pin: true, scrub: 0.5, preventOverlaps: true, }, }); scrollTl.current .to(trackRef.current, { xPercent: -100, ease: 'none', }) .to( titleRef.current, { xPercent: -50, ease: 'none', }, '<' ); }); return () => scrollContext.revert(); }, [projectsData, animLength, isMobile, height]); return ( <div ref={pinContainerRef} style={{ border: '1px solid red' }}> <div ref={projectsContainerRef} className={styles.projectsContainer}> <h1 ref={titleRef} className={styles.title}> Projects </h1> <div ref={trackRef} className={styles.projectsTrack}> {projectsData?.map((project, index) => ( <div id='projectsContainer' key={index} className={styles.projectContainer} > <Link to={`/projects/${project.id}`} className={styles.link}> <div id='projectImageContainer' className={styles.projectImageContainer} onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)} > <AnimatedImage src={project.image} playAnim={hover} /> </div> </Link> </div> ))} </div> </div> </div> ); }; export default ProjectsSectionDesktop;
  8. Hello, I need some help from someone that knows and understand more about gsap scrollperProxy than I do because I am stuck with a problem that I can't seem to get around it. And honestly, I don't know if this is a gsap related question, and if it isn't I apologize in advance. In project I am using React Router and React Router keeps the same offsetHeight position when changing routes and I would like when the route has changed to have a scroll that scrolls to the Top. The issue is that I am using locomotive-scroll in combination with gsap's scrollTrigger. In order for the scrollTrigger to work with locomotive-scroll I have created a custom hook (which I will leave the code at the end because it's quite long), where I essentially tell scrollTrigger what the current locomotive-scroll, scroll position is using scrollerProxy. Unfortunately, if I try to scroll to the top of the page, for example, I can't. And the console doesn't even throw an error. I tried both using gsap scrollToPlugin and locomotive-scroll's scrollTo function but they only work If I don't use the hook that I've created. using gsap: useLocoScroll(true); const { pathname } = useLocation(); useEffect(() => { gsap.registerPlugin(ScrollToPlugin); gsap.to('.App', { duration: 0, scrollTo: 0, delay: 0, ease: 'none' }); }, [pathname]); using loco scroll: useLocoScroll(true); const { pathname } = useLocation(); const scrollRef = useRef(null); useEffect(() => { const scroll = new LocomotiveScroll(); scrollRef.current = scroll; if (scrollRef.current) { scrollRef.current.scrollTo('top', { offset: 0, duration: 600, easing: [0.25, 0.0, 0.35, 1.0], disableLerp: true, callback: () => { scrollRef.current.on('scroll', ScrollTrigger.update); }, }); } }, [pathname]); (Both of the options above work if useLocoScroll is set to false / `useLocoScroll(false)`) Locomotive-scroll scrollTo function also takes in an object with a callback where I tried to update the ScrollTrigger in various ways but nothing worked. So I was wondering if there is a way I could update the locomotive-scroll base on where the ScrollToPlugin is. Basically, doing the reverse of what I did in the custom hook? Here is the code for the custom hook: import { useLayoutEffect } from 'react'; import LocomotiveScroll from 'locomotive-scroll'; import gsap from 'gsap'; import ScrollTrigger from 'gsap/ScrollTrigger'; const useLocoScroll = (start) => { gsap.registerPlugin(ScrollTrigger); useLayoutEffect(() => { if (!start) return; const scrollEl = document.querySelector('.App'); let locoScroll = new LocomotiveScroll({ el: scrollEl, smoothMobile: false, smooth: true, multiplier: 1, }); locoScroll.on('scroll', ScrollTrigger.update); ScrollTrigger.scrollerProxy(scrollEl, { scrollTop(value) { if (locoScroll) { return arguments.length ? locoScroll.scrollTo(value, 0, 0) : locoScroll.scroll.instance.scroll.y; } return null; }, scrollLeft(value) { if (locoScroll) { return arguments.length ? locoScroll.scrollTo(value, 0, 0) : locoScroll.scroll.instance.scroll.x; } return null; }, getBoundingClientRect() { return { top: 0, left: 0, width: window.innerWidth, height: window.innerHeight, }; }, pinType: document.querySelector('.App').style.transform ? 'transform' : 'fixed', }); const locoScrollUpdate = () => { if (locoScroll) { locoScroll.update(); } }; new ResizeObserver(() => { if (locoScroll) { locoScroll.update(); } }).observe(document.querySelector('[data-scroll-container]')); ScrollTrigger.addEventListener('refresh', locoScrollUpdate); ScrollTrigger.refresh(); return () => { if (locoScroll) { ScrollTrigger.removeEventListener('refresh', locoScrollUpdate); locoScroll.destroy(); locoScroll = null; } }; }, [start]); }; export default useLocoScroll;
  9. Awesome! Thank you! Unfortunately, it had some issues. One of which was that the animation in reverse would play instantly.
  10. It did help! The question was about the `utils.toArray` method in gsap, specifically whether it might cause any problems with react's rerendering process. However, I resolved the issue by using `querySelectorAll` on the parent ref and initializing an empty array state when the component is rendered and adding that state to the dependency array of the useEffect where I keep all the gsap animation. This way the `links` are 100% rendered when gsap "does stuff to them" Although, There is still an issue where I get a flesh of the navbar before `gsap.set` sets all the initial stylings. Thank you for your answer!
  11. This is awesome! I will take a look. Thank you!
  12. I am working on this animation for a navbar where I have a list of links that I would like to fade in from `opacity 0 and y - some px` to `opacity 1 and y 0` in a staggered way. The issue is that when I refresh the page neither the `gsap.set` nor the animation from the TL seems to work properly. The only time they work as expected is when I do changes to TL and save. For example, I change the `duration` from 0.3 to 0.2 and save it. I am not sure what is the issue but I think it has something to do with the `toArray` method and the way react rerenders component. Is this something common with react? Is there a fix for it? Here is a code sandbox: https://codesandbox.io/s/compassionate-microservice-7u6vv3?file=/src/App.js
  13. @GreenSock Hi, Sorry for the delayed response, I was busy with work. Here is the minimal demo you asked for: https://codesandbox.io/s/compassionate-microservice-7u6vv3?file=/src/App.js. I was curious if I could replace the background with an svg and animate its path so that when it changes position from y-100 to y0 but the bottom of the "square" warps downwards a bit. I guess @Carl answered my question with some pretty good examples. Thank you very much!
  14. Hello, I have those svgs and I was wondering if I could animate their path to creating a sort of morph effect. If yes, how could go about selecting the `viewBox` and the `d` element from the svgs? top: <svg id="navBg" height="100%" width="100%" viewBox="0 0 1920 0" preserveAspectRatio="none"> <path class="navBg" d="0" fill="#3E46FD"/> </svg> middle: <svg id="navBg" height="100%" width="100%" viewBox="0 0 1920 1080" preserveAspectRatio="none"> <path class="navBg" d="M0,0L0,382.767C0,382.767 1497.67,969.894 1920,382.767L1920,0L0,0Z" fill="#3E46FD"/> </svg> bottom: <svg id="navBg" height="100%" width="100%" viewBox="0 0 1920 1080" preserveAspectRatio="none"> <path class="navBg" d="0" fill="#3E46FD"/> </svg>
  15. Interesting, It did not worked for me even when full screen. The issues from resizing can be fixed by adding using the useIsMobile hook. Adding it to the useLeyoutEffect watchers array should fix those issues.
  16. Hi @akapowl, Sorry for the not responding sooner, been bussie with work. The reason it work in you demo is because the locomotive-scroll is not working at all. You can see that by the scroll bar. When locomotive-scroll is working the scroll bat is the yellow scroll bar and has the locomotive-scroll styling. I have made a simpler example where is more evident if the locomotive-scroll is working or not: https://codesandbox.io/s/misty-moon-sch8xv?file=/src/hooks/useLocoScroll.js. Removing the data-scroll-section seems to help, also removing the pinType: document.querySelector(".App").style.transform ? "transform" : "fixed" from the hook also enable the pin on the scrollTrigger. Tring to fix the issue with the double scroll bar from locomotive-scroll I have tried a similar think as you did. This is what I've tired: return () => { if (locoScroll) { ScrollTrigger.removeEventListener('refresh', lsUpdate); locoScroll.destroy(); locoScroll = null; } }; Unfortunately this just makes the pin not to work at all. Your idea of using useLayoutEffect inside the hook it's actually what makes this work, almost. This allows the prev code to work, from the useLayoutEffect return function fixing the double scrollbar issue, the one that you suggested at point 1. Interesting enough using useLayoutEffect anywhere else in the code completely brakes the scrollTrigger again in a similar way. I don't know why this is happening, maybe someone from Gsap that is more familiar with how gsap works with useEffect and useLayoutEffect could give us an explanation. The reason I said it almost works is because in my "real" project I have a glitch that unfraternally is not visible in the codesanbox. The issue is when ever the pin should start a small jigger or lag appears. Adding a pin on the hero section on the logo with the start set to "top top" shows that the scroll is happening for a few pixels and then gets pined when it should have been pinned from the start. It's like taking a few pxs to realize that it should have been pinned. I think this is because the scrollTriggers still gets initialized before the locomotive-scroll. I have make some research on how I could delay the scrollTrigger from being created. One solution would be to use the setTimeout. But I am not a big fan on using this fix because I would have to use it evetime I create an animation that uses the pin. I have come across the fac that you could kill the scroll trigger so I am assuming that you could initialized it again but I don't know how I could kill all the scrollTriggers at the same time or have them killed by default and initialized them only if the loco-scroll is true. I know that scrollTrigger has a default prop that allows you to set properties as default for all the scrollTriggers so I will try to use that. I will make some more research on how I could do that and if I don't find an answer I'll probably open another thread and see if someone from gsap can help me. Thank you very much for taking the time! I truly appreciate it! Your input helped me a lot.
  17. Hello @akapowl, You are totally right. 1) I've noticed this, it's very bad and it's a problem with itself as is even worse then it should be. Loco-scroll would create 2 scroll bars and the use is able to grad both of them. If that happens when a bunch of problems appear. But simply scrolling dose not seem to effect the scrollTrigger in any meaningful way. 2) How did you log the creation of scrollTrigger? This also doesn't seem do effect the scrollTrigger in any way. I am imagine because the native scroll no loner exists and the scrollTrigger has no other option but to follow the scrollerProxy. But I would look into it. It seems like something that would cause problems along the way. 3) This is kind a weird. I know about this and gsap talk about this in their post about loco-scroll and scrollTrigger. This is way I added this pinType: document.querySelector(".App").style.transform ? "transform" : "fixed" to not run into this issue. But apparently this line of code created the issue. All I did was to remove this from the useLocomotiveScroll hook and everything works fine so far... I would not guess in a million years that this was coursing the problem. Thank you very much your your help! I appreciate it!
  18. Hello, I was afraid that it would be a lot of code but I guess react it's react after all... https://codesandbox.io/s/naughty-hodgkin-x7lv12?file=/src/pages/Homepage/sections/About/index.jsx Here is a demo with everything that I have set up that is using gsap.
  19. Thank you! Stopping the locomotive scroll and deleting scroller: '.App' does make the pin from from scrollTrigger work. The issue is that the pin does not work with the locomotive-scroll. It might be a ether from the locomotive-scroll or I did not set up scrollerProxy properly. I have tried all the ideas I got from your reply but unfortunately it's still not working.
  20. Hello, You pointed out some good mistakes I was making. This gives me some ideas to try to make it work. I hope I could fix it. When it comes to the data-scroll-container I tired to eliminate everything that has to do with the loco-scroll trying to debug it. It seems like I forgot about that one I thought it should make a difference. Thank you very much! Hope I can debug it, it's been a while since I am trying to figure it out.
  21. Hello @mvaneijgen, How did you know? In my project I do use locomotive-scroll but even when I do not use it the scrollTrigger does not work. I specifically did not include anything related to loco scroll because I did not tough that loco scroll was the problem. as everything else works fine except the pin. Can you please tell me how did you know that I am suing another library from the code sandbox? That would help me debug it the issue.
  22. Hello, I am having an issue where if I add pin: true to scrollTrigger it adds padding to the top and bottom, witch I know is does, but does not pin anything and it looks like I simply added a large padding to the top and bottom of the section. I was wondering if this is because of the CSS. Does ScrollTrigger change some stylings that I already changed in the CSS file? I've created a minimal code sanbox :https://codesandbox.io/s/stoic-mccarthy-h4qykw?file=/src/pages/Homepage/sections/About/index.jsx
  23. Hello @GreenSock, Thank you very much for your help! I have created a custom hook that integrates locomotive-scroll and ScrollTrigger using the video I linked in the original question, gsap Locomotive Scroll with ScrollTrigger demo, gsap docs for scrollerProxy, and some other Youtube videos. I have also took into consideration your comment from above. Everything works now, and having the hook where I could simply turn locomotive-scroll on and off helped me debug stuff. I will leave the code below for anyone else struggling. Maybe this thread will help. I hope you don't mind. Here is the custom hook: import React, { useEffect } from 'react'; import LocomotiveScroll from 'locomotive-scroll'; import gsap from 'gsap'; import ScrollTrigger from 'gsap/ScrollTrigger'; const useLocoScroll = (start) => { gsap.registerPlugin(ScrollTrigger); useEffect(() => { if (!start) return; const scrollEl = document.querySelector('.App'); let locoScroll = new LocomotiveScroll({ el: scrollEl, smooth: true, multiplier: 1.5, }); locoScroll.on('scroll', ScrollTrigger.update); ScrollTrigger.scrollerProxy(scrollEl, { scrollTop(value) { if (locoScroll) { return arguments.length ? locoScroll.scrollTo(value, 0, 0) : locoScroll.scroll.instance.scroll.y; } return null; }, scrollLeft(value) { if (locoScroll) { return arguments.length ? locoScroll.scrollTo(value, 0, 0) : locoScroll.scroll.instance.scroll.x; } return null; }, getBoundingClientRect() { return { top: 0, left: 0, width: window.innerWidth, height: window.innerHeight, }; }, }); const lsUpdate = () => { if (locoScroll) { locoScroll.update(); } }; ScrollTrigger.addEventListener('refresh', lsUpdate); ScrollTrigger.refresh(); }, [start]); }; export default useLocoScroll; To use this hook you simply call it inside theApp.js file like so: useLocoScroll(true) or any condition that will result to true You'll also need to add data-scroll-container to the".App" div and data-scroll-section to the most outer div of any of your sections. For simple use I have created a Section component that does that. For a batter understanding of the hook, please check gsap demo. import React from 'react'; const Section = ({ children }) => { return <section data-scroll-section>{children}</section>; }; export default Section; To use this, simply wrap your jsx into this component like so: return( <Section> code... </Section> ) For the gsap / ScrollTrigger code I've done exactly what Jack suggested. Here is another code example: useEffect(() => { let ctx = gsap.context(() => { const tl = gsap.timeline({ scrollTrigger: { trigger: heroContainerRef.current, scroller: '.App', start: 'top top', scrub: 1, }, }); tl.to(textColRef.current, { x: 200, opacity: 0, }); tl.to( imageWrapperRef.current, { x: -200, opacity: 0, }, 0 ); }); return () => ctx.revert(); }, []); Please note the scroller: '.App' inside the ScrollTrigger. This is very important as you need to specify what the new scroller is. Also, don't forget to add into your App.css or index.css the CSS that locomotive-scroller recommends. Hope this helps
×
×
  • Create New...