Jump to content
Search Community

Search the Community

Showing results for tags 'observer'.

  • 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

  • Blog

Categories

  • Products
  • Plugins

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...

  1. Original: https://codepen.io/GreenSock/pen/XWzRraJ I want to achieve the following: I want to scroll through the page in a normal way. So first, I scroll through the intro. Then, when div.wrapper reaches the top of my screen, I want to pin it using ScrollTrigger. At that point, I only want to swipe through the swiper using this Observer. Once I reach the end of my swiper, I want to continue scrolling through the page, and the Observer can stop at that point. I'm having trouble making this work. Can anyone help me?
  2. By Huy

    GSAP Observer Marquee with Lenis

    Hello everyone, As this is my first time using GSAP, I'm having quite a bit of trouble getting the scroll velocity logic for the marquee right. At the moment the logic sort of works but it doesn't really work as I intended as there is an abrupt stop as soon as you stop scrolling and then it continues the looping animation at a normal speed which sort of breaks the seamless speed scroll. Would also be happy to get any other feedback on improving my GSAP code, it feels like I'm just hammering away at the code while reading the docs and it just happens to work a little. Any other questions I would be happy to answer!
  3. Hi, I am stuck in a position where I need some help. I am currently using using these scripts on my webflow website: <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/gsap.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.11.5/gsap.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.11.5/Observer.min.js"></script> <script src="https://unpkg.com/splitting/dist/splitting.min.js"></script> <script src="https://qe6cmz.csb.app/script.js"></script> This is the working Animation and It works perfectly https://www.judexaya.com/anomalies But one I use a Hash link to navigate to my slide, it show the correct slide but then the animation breaks and It won't work. Neither the scroll works nor the Navigation buttons works. Here is the link to the Problem : https://judexaya.webflow.io/anomalies#ZENITH Is there any way to fix this problem? I want the animation to work even with the URL with hash.
  4. Hiii, I am trying create a reel like web application. In which I am trying to create a reel component in which I will use Observer for listening user's swipe up and swipe down action and scrollTo to animate slide to next page. But, the issue is when user swipes, onUp/onDown is being called even after user stops swiping. Here paginated api response will come also so we have to update slides as user scrolls the reels. Here is a code for that component: import gsap from 'gsap' import { ScrollToPlugin, Observer, ScrollTrigger } from 'gsap/all' import { useGSAP } from '@gsap/react' import { type VideoSizeBoxType } from '@/lib/stores/genuin-options' import { useEffect, useRef } from 'react' gsap.registerPlugin(ScrollToPlugin, Observer, ScrollTrigger) const customColors = [ '#E74C3C', '#1ABC9C', '#8E44AD', '#3498DB', '#F1C40F', '#2ECC71', '#D35400', '#9B59B6', '#27AE60', '#34495E', ] export function CustomSwiper({ sizeBox }: { sizeBox: VideoSizeBoxType }) { const scopeRef = useRef<HTMLDivElement | null>(null) useGSAP( () => { let isAnimating = false let currentIndex = 0 const obs = Observer.create({ debounce: true, type: 'wheel,touch,pointer,scroll', wheelSpeed: 0, target: '#swiper-test', lockAxis: true, tolerance: 0, preventDefault: true, onDown: (self) => { console.log('self::', isAnimating) if (!isAnimating) { swipeNext(currentIndex + 1) } }, onUp: () => { if (!isAnimating) { swipePrev(currentIndex - 1) } }, }) function swipeNext(newIndex: number) { isAnimating = true gsap.to('#swiper-test', { duration: 0.5, ease: 'power3.inOut', scrollTo: { y: `+=${document.getElementById('swiper-test')!.clientHeight}px` }, onComplete: () => { isAnimating = false currentIndex = newIndex }, }) } function swipePrev(newIndex: number) { isAnimating = true gsap.to('#swiper-test', { duration: 1, scrollTo: { y: `-=${document.getElementById('swiper-test')!.clientHeight}px` }, onComplete: () => { isAnimating = false currentIndex = newIndex }, }) } }, { scope: scopeRef } ) return ( <div ref={scopeRef}> <div id="swiper-test" className="overflow-hidden" style={{ ...sizeBox }}> {customColors.map((item, index) => { return ( <div key={index} className="flex h-full w-full" style={{ backgroundColor: item }}> {index} </div> ) })} </div> </div> ) }
  5. Transcend Studios

    Observer not working on touch devics

    HI, I'm facing a problem with Observer. It perfectly works on every device except touch device. In a touch device, the observer starts from the opposite direction. If you visit my website (https://transcendstudios.asia/) from mobile, I hope you will get the issue. Also, you can check the example (CodePen) from mobile. onDown, slider should slide bottom to up and onUp slider shoud slide up to bottom. But in mobile it reversed. Thanks
  6. As you can see from the minimal demo, when you load in you have some text and when you scroll an observer triggers a timeline to play. And then the Observer disables and the user can scroll through the rest of the page. This is all great. However, after you scroll once you cant scroll back up to let the animation play in reverse. You actually have to scroll down again into the page and then come back up for it to play in reverse. This of course is not ideal. I understand that it is doing this because I have an onComplete() in the scrollTrigger that disables the Observer and then only re-enables it on an OnLeaveBack() So I understand the issue but because I am fairly new to Observers in general and using them with scrollTrigger I can not figure out the right approach for this... There is quite a bit of javaScript in my codepen but you should be able to ignore the top half. Everything inside the commented section IMAGE SLIDESHOW can be ignored. Its clearly marked with comments with a start and end point of that code. Furthermore the section in between the gsap.timeline() and the const scrollObserver is mostly just tl.to animations, which can also be ignored I believe the issue I am trying to show is clear, to recreate the issue just scroll down once. Let the animation play out, and then try to scroll back up and you will see the animation will not reverse. You will notice if you scroll down, let the animation play out, then scroll down past the section, then scroll back up to the observer area, then it will in fact play in reverse Any help at all is much apprieciated!
  7. Hi everyone, I’m working on a project where I’m trying to use GSAP’s Observer plugin in combination with ScrollTrigger to create a section-based scrolling experience. The goal is to have vertically pinned sections, and when the user reaches a certain section (Section 3), a zoom animation starts. During the zoom animation, I want to disable the Observer to prevent the user from scrolling to the next or previous sections, and re-enable the Observer once the zoom animation is reset or the user scrolls back to a previous section. I also tried disable the Observer logic directly in the onComplete function to be able to start the Zoom Animation, but i could not re-enable it again to scroll back to previous section Can anyone help me? thank you.
  8. Hello everyone, I am trying to create a slideshow based on the demo found at the end of this post. https://codepen.io/cassie-codes/pen/vYWvwXV Instead, my version uses React to try to recreate the same effect. However I am running into problems. Here is my code: slides.jsx import { useEffect, useRef } from "react"; import gsap from "gsap"; import { ScrollTrigger } from "gsap/ScrollTrigger"; import { Observer } from "gsap/Observer"; import { projects } from "./projects"; import "./slideshow.scss"; gsap.registerPlugin(ScrollTrigger, Observer); const SlideShow = () => { const sectionsRef = useRef([]); const imagesRef = useRef([]); const slideImagesRef = useRef([]); const outerWrappersRef = useRef([]); const innerWrappersRef = useRef([]); const countRef = useRef(null); const currentIndex = useRef(0); const animating = useRef(false); useEffect(() => { const sections = sectionsRef.current; const images = imagesRef.current.reverse(); const slideImages = slideImagesRef.current; const outerWrappers = outerWrappersRef.current; const innerWrappers = innerWrappersRef.current; const count = countRef.current; const wrap = gsap.utils.wrap(0, sections.length); gsap.set(outerWrappers, { xPercent: 100 }); gsap.set(innerWrappers, { xPercent: -100 }); gsap.set(sections[0].querySelector(".slide__outer"), { xPercent: 0 }); gsap.set(sections[0].querySelector(".slide__inner"), { xPercent: 0 }); function gotoSection(index, direction) { animating.current = true; index = wrap(index); let tl = gsap.timeline({ defaults: { duration: 1, ease: "expo.inOut" }, onComplete: () => { animating.current = false; console.log("slide changed"); }, }); const currentSection = sections[currentIndex.current]; const heading = currentSection.querySelector(".slide__heading"); const nextSection = sections[index]; const nextHeading = nextSection.querySelector(".slide__heading"); gsap.set([sections, images], { zIndex: 0, autoAlpha: 0 }); gsap.set([sections[currentIndex.current], images[index]], { zIndex: 1, autoAlpha: 1, }); gsap.set([sections[index], images[currentIndex.current]], { zIndex: 2, autoAlpha: 1, }); tl.set(count, { text: index + 1 }, 0.32) .fromTo( outerWrappers[index], { xPercent: 100 * direction }, { xPercent: 0 }, 0 ) .fromTo( innerWrappers[index], { xPercent: -100 * direction }, { xPercent: 0 }, 0 ) .to(heading, { "--width": 800, xPercent: 30 * direction }, 0) .fromTo( nextHeading, { "--width": 800, xPercent: -30 * direction }, { "--width": 200, xPercent: 0 }, 0 ) .fromTo( images[index], { xPercent: 125 * direction, scaleX: 1.5, scaleY: 1.3 }, { xPercent: 0, scaleX: 1, scaleY: 1, duration: 1 }, 0 ) .fromTo( images[currentIndex.current], { xPercent: 0, scaleX: 1, scaleY: 1 }, { xPercent: -125 * direction, scaleX: 1.5, scaleY: 1.3 }, 0 ) .fromTo(slideImages[index], { scale: 2 }, { scale: 1 }, 0) .timeScale(0.8); currentIndex.current = index; } Observer.create({ type: "wheel,touch,pointer", preventDefault: true, wheelSpeed: -1, onUp: () => { if (animating.current) return; gotoSection(currentIndex.current + 1, 1); }, onDown: () => { if (animating.current) return; gotoSection(currentIndex.current - 1, -1); }, tolerance: 10, }); const logKey = (e) => { if ( (e.code === "ArrowUp" || e.code === "ArrowLeft") && !animating.current ) { gotoSection(currentIndex.current - 1, -1); } if ( (e.code === "ArrowDown" || e.code === "ArrowRight" || e.code === "Space" || e.code === "Enter") && !animating.current ) { gotoSection(currentIndex.current + 1, 1); } }; document.addEventListener("keydown", logKey); return () => { document.removeEventListener("keydown", logKey); }; }, []); return ( <div className="slideshow_container"> {projects.map((project, i) => ( <section className="slide" key={project.id} ref={(el) => (sectionsRef.current[i] = el)} > <div className="slide__outer" ref={(el) => (outerWrappersRef.current[i] = el)} > <div className="slide__inner" ref={(el) => (innerWrappersRef.current[i] = el)} > <div className="slide__content"> <div className="slide__container"> <h2 className="slide__heading">{project.projName}</h2> <figure className="slide__img-cont" ref={(el) => (slideImagesRef.current[i] = el)} > <img src={project.codeImgSrc} alt={project.codeImgAlt} /> </figure> </div> </div> </div> </div> <div className="overlay"> <div className="overlay__content"> <p className="overlay__count">{i + 1}</p> <figure className="overlay__img-cont" ref={(el) => (imagesRef.current[i] = el)} > <img src={project.demoImgSrc} alt={project.demoImgAlt} /> </figure> </div> </div> </section> ))} <div className="link_buttons"> <button>Code</button> <button>Demo</button> </div> </div> ); }; export default SlideShow; slideshow.scss I want this slideshow to take up only half the screen @font-face { font-family: "Bandeins Sans & Strange Variable"; src: url("https://res.cloudinary.com/dldmpwpcp/raw/upload/v1566406079/BandeinsStrangeVariable_esetvq.ttf"); } @import url("https://fonts.googleapis.com/css2?family=Sora&display=swap"); * { box-sizing: border-box; user-select: none; } ::-webkit-scrollbar { display: none; } figure { margin: 0; overflow: hidden; } html, body { overflow: hidden; margin: 0; padding: 0; height: 100vh; height: -webkit-fill-available; } .slide { height: 100%; width: 100%; top: 0; left: 50%; position: fixed; visibility: hidden; &__outer, &__inner { width: 100%; height: 100%; overflow-y: hidden; } &__content { display: flex; align-items: center; justify-content: center; position: absolute; height: 100%; width: 100%; top: 0; } &__container { position: relative; max-width: 1400px; width: 100vw; margin: 0 auto; height: 90vh; margin-bottom: 10vh; display: grid; grid-template-columns: repeat(10, 1fr); grid-template-rows: repeat(10, 1fr); grid-column-gap: 0px; grid-row-gap: 0px; padding: 0 1rem; } &__heading { --width: 200; display: block; text-align: left; font-family: "Bandeins Sans & Strange Variable"; font-size: clamp(5rem, 5vw, 5rem); font-weight: 900; font-variation-settings: "wdth" var(--width); margin: 0; padding: 0; color: #f2f1fc; z-index: 999; mix-blend-mode: difference; grid-area: 2 / 2 / 3 / 10; align-self: baseline; } &__img-cont { margin-top: 4rem; grid-area: 2 / 1 / 7 / 8; img { width: 100%; height: 100%; object-fit: cover; } } } .slide:nth-of-type(1) { visibility: visible; .slide__content { backdrop-filter: blur(10px); } } .slide:nth-of-type(2) { .slide__content { backdrop-filter: blur(10px); } } .slide:nth-of-type(3) { .slide__content { backdrop-filter: blur(10px); } } .slide:nth-of-type(4) { .slide__content { backdrop-filter: blur(10px); } } .overlay { position: fixed; top: 0; bottom: 0; left: 50%; right: 0; z-index: 2; &__content { max-width: 1400px; width: 100vw; margin: 0 auto; padding: 0 1rem; height: 90vh; margin-bottom: 10vh; display: grid; grid-template-columns: repeat(10, 1fr); grid-template-rows: repeat(10, 1fr); grid-column-gap: 0px; grid-row-gap: 0px; } &__img-cont { position: relative; overflow: hidden; margin: 0; grid-area: 4 / 3 / 9 / 5; img { position: absolute; width: 100%; height: 100%; object-fit: cover; object-position: 50% 50%; } } &__count { grid-area: 3 / 5 / 4 / 5; font-family: "Bandeins Sans & Strange Variable"; font-size: clamp(3rem, 4vw, 15rem); margin: 0; padding: 0; text-align: right; border-bottom: 7px white solid; } } @media screen and (min-width: 900px) { .overlay__content, .slide__container { padding: 0 3rem; margin-top: 10vh; height: 80vh; } .overlay__img-cont { grid-area: 6 / 2 / 10 / 6; } .overlay__count { grid-area: 3 / 5 / 4 / 5; font-family: "Bandeins Sans & Strange Variable"; color: white; } .slide__img-cont { margin-top: 0; grid-area: 2 / 1 / 8 / 7; } .slide__heading { grid-area: 1 / 1 / 4 / 10; } } projects.js export const projects = [ { id: 1, projName: "test1", codeLink: "(some link)", demoLink: "(some other link)", codeImgSrc: "(some picture src)", codeImgAlt: "", demoImgSrc: "(some other picture src)", demoImgAlt: "", }, { id: 2, projName: "test2", codeLink: "(some link)", demoLink: "(some other link)", codeImgSrc: "(some picture src)", codeImgAlt: "", demoImgSrc: "(some other picture src)", demoImgAlt: "", }, { id: 3, projName: "test3", codeLink: "(some link)", demoLink: "(some other link)", codeImgSrc: "(some picture src)", codeImgAlt: "", demoImgSrc: "(some other picture src)", demoImgAlt: "", }, { id: 4, projName: "test4", codeLink: "(some link)", demoLink: "(some other link)", codeImgSrc: "(some picture src)", codeImgAlt: "", demoImgSrc: "(some other picture src)", demoImgAlt: "", }, ]; My major issue right now is that I cannot get the overflow: hidden; to apply correctly causing the old text and pictures to remain on the screen instead of being hidden. Also when the next slide animates, the current and next numbers on the counter render at the same time, overlapping for a moment. If anyone can help it would be appreciated. Thanks in advance!
  9. Hello Everyone. I am still learning gsap and am running into an issue. In a project I was previously using a scrollTrigger and using scrub to make pictures fade in and out of each other. However, I realized if a user scrolls very long they can skip through all of the slides without seeing it. I wanted to make it so if the user scrolled they would have to sit through the animation until it was finished before they would be able to scroll again. After a little research I found that observer was the route to go. Here comes the issue. I have successfully got it scrolling from one slide to another however the animations when scrolling DOWN and only down don't play. So the image just skips to the next one instead of fading in and out like it does when the user scrolls up. Same thing with the titles (the countries array). They are supposed to fade from 0.2 opacity to 1 and they just skip the animation on the way down. Lastly the subheaderWrappers array and descWrappersArray seem to animate IN fine when scrolling down however the previous index's in these arrays do the same behavior where they just jump to the finished spot instead of animating there when scrolling down. Any help is much appreciated I am using HTML SCSS and JS.
  10. Pavel Buchta

    How to use Observer in next.js?

    It works, but I'm not sure whether I should do it like this or using useGSAP hook. And if I should use it with useGSAP hook then how to do it precicely? useEffect(() => { const observer = ScrollTrigger.observe({ target: container.current, onHover: () => setHover(true), onHoverEnd: () => setHover(false), }); return () => { observer.kill(); }; }, []); I looked at the documentation, but I couldn't find how to use it in next.js.
  11. Nice to meet you, I would like to discuss the GSAP ScrollTrigger. I am modifying the GSAP Observer demo to GSAP ScrollTrigger. I have pinned the sections in the .section-wrap and the image switches as it scrolls. I want to do the following about this. 1. separate the section pinning for each .section-wrap. 2. when I finish scrolling a section in the first .section-wrap, I want to move to the second .section-wrap. Here's the HTML, and it mentions CSS too. <div class="section-wrap"><!--← add position: relative;--> <section class="first"><!-- position: absolute;--> <div class="outer"> <div class="inner"> <!-- The background image for this element is a photo --> </div> </div> </section> <section class="second"> <!--Abbreviations--> </section> <section class="third"> <!--Abbreviations--> </section> </div> <div class="section-wrap"> <!--Abbreviations. Same as the element above.--> </div> The JavaScript is this. I have written comments where I have added from the demo. //Change ScrollTrigger gsap.registerPlugin(ScrollTrigger); let sections = document.querySelectorAll("section"), images = document.querySelectorAll(".bg"), outerWrappers = gsap.utils.toArray(".outer"), innerWrappers = gsap.utils.toArray(".inner"), currentIndex = -1, wrap = gsap.utils.wrap(0, sections.length), animating; gsap.set(outerWrappers, { yPercent: 100 }); gsap.set(innerWrappers, { yPercent: -100 }); function gotoSection(index, direction) { index = wrap(index); animating = true; let fromTop = direction === -1, dFactor = fromTop ? -1 : 1, tl = gsap.timeline({ defaults: { duration: 1.25, ease: "power1.inOut" }, onComplete: () => animating = false }); if (currentIndex >= 0) { gsap.set(sections[currentIndex], { zIndex: 0 }); tl.to(images[currentIndex], { yPercent: -15 * dFactor }) .set(sections[currentIndex], { autoAlpha: 0 }); } gsap.set(sections[index], { autoAlpha: 1, zIndex: 1 }); tl.fromTo([outerWrappers[index], innerWrappers[index]], { yPercent: i => i ? -100 * dFactor : 100 * dFactor }, { yPercent: 0 }, 0) .fromTo(images[index], { yPercent: 15 * dFactor }, { yPercent: 0 }, 0) currentIndex = index; } //Change ScrollTrigger ScrollTrigger.observe({ target: ".section-wrap", //Add type: "wheel,touch,pointer", wheelSpeed: -1, onDown: () => !animating && gotoSection(currentIndex - 1, -1), onUp: () => !animating && gotoSection(currentIndex + 1, 1), tolerance: 10, preventDefault: true }); gotoSection(0, 1); I think I need to re-array the sections,outerWrappers,innerWrappers per .section-wrap, any good ideas? Thank you in advance for your help.
  12. Hello! Glad to be back on this great forum with new questions. Recently, I stumbled upon a problem with my animation. I'm trying to combine a few sections with simple scrub animations, but one section in the middle uses an observer to stop scrolling and animate through a few slides. I was using some of the forum's insights from posts about combining ScrollTrigger and Observer. However, my issue is that I'm using the Lenis library for smooth scrolling. Instead of manually stopping scrolling and saving its position, I just call lenis.stop() and lenis.start(), which works like a charm. But I have a few anchor links on my site, and when I use the lenis.scrollTo() function to scroll to the needed section, I encounter a problem. When I try to scroll to the footer, which is below the section using the observer, my scroll just stops. I thought, "Okay, just disable Observer and ScrollTrigger, and after scrolling, enable them again." This leads to my final problem. It works, but when Lenis scrolls to the footer and onComplete enables ScrollTrigger, the scroll position resets to the top of the site, and when I scroll, it resets back to the section that uses the observer. I made a simple CodePen to try to fix that issue, but I'm stuck. Please help me! ?
  13. Hello there, I'm trying to do the scroll pin animation in reactjs. There I'm using swiper and gsap. My requirement is when scroll to section it need to pin and then swiper needs to be slide, untill end. I'm taking reference from below codepen. Js version: "https://codepen.io/snorkltv/pen/QWzwmjJ" Im trying to replicate the codepen example in reactjs, I have tried, but Im strucked in rendering issue. Here I have add the code on Stackbitz Reactjs: https://stackblitz.com/edit/vitejs-vite-rpn1iq?file=src%2FApp.jsx Can some please help me with that....
  14. Rohit Pathak

    Scroll animation on one scroll

    Hello, I'm new to GSAP and I'm trying some handy animation. Here is what I'm trying to achieve https://genevoism.com/. I know they have used different approach but I belief such animation are possible in GSAP too. I using combination of ScrollTrigger, ScrollTo, Observer and using timeline pause and play method to achieve one scroll animation effect. By one scroll I mean that each of animation would be trigger per scroll. Approach I took : > Firstly I have made different timeline for different animation per section. > Than I tried to get user scroll using observer's onUp and onDown methods. > Than after per scroll I play my desired timeline and as one of the tween of that timeline gets completed I pause my timeline, further when user will scroll again timeline play's and pause's again. > When all tweens in one timeline gets completed, I switch to other timeline by pausing the first one. > I have also used a forEach loop on scroollTrigger.create so that I can pin the particular section as animation are being performed. What I want: I want set of animation such that when my section comes in viewport or is already present in viewport( like hero or banner ) the animation should get started as the user scroll. Each and every animation or tween should start and end between two scroll of user. And as all the animation in a section get's completed it should slide up or down as per user's scroll 100% or 100vh. Please have a look into the below pen and guide me where I'm going wrong. Thank you... <script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>
  15. Hi there, I’m having an issue implementing a design where a vertical scroll transitions to a horizontal. The sticky horizontal scroll section is jumping when the transition happens. I have done a similar setup that doesn‘t include scroller: ".outer" where it does not occur, how ever this content will be loaded in a modal and from what I have ready I need to use scroller so it is not connected to the body container. You will see the first image jump upwards when rapidly scrolling. It seems to occur more on the first and last couple images. Any help would be greatly appreciated.
  16. Hi everyone. I'd like to create an animation that plays in a loop and also plays when I scroll. Animation: animates the css clip-path property of the images according to the current index. Currently, when the component is mounted, the animation plays correctly but remains stuck on the last image of the array. And when I scroll, nothing happens. Does anyone have a solution or know where to find the bug ? Thank you in advance Demo link : https://stackblitz.com/edit/gsap-react-basic-f48716-ebgh4d?file=src%2FApp.js I was inspired by the following examples: https://codepen.io/GreenSock/pen/wvZjeGN?editors=1010 https://codepen.io/GreenSock/pen/XWzRraJ?editors=1010
  17. LuLUE7775

    Horizontal slider with Observer

    Hi, I am building a slider based on this example https://codepen.io/andrei-savu/pen/BaPqzvX It works when it's alone on a page, https://yaojuilan.art/gsap While it isn't working when there is something else https://yaojuilan.art/system_of_conductors/field-walk#kinmen (the slider works sometime. it is unstable. ) I tried logging out the observer onChange, the event does trigger, but the items just would not do the horizontal transition. I am wondering if observer has some sort of limitation, or maybe observer listener is interfering with something? Sorry i did not create a codepen, because this component does works standalone. Here is the slider component export default async function Page() { const data= await getPageContent() return ( <div id='intro' className='relative h-auto w-full overflow-x-hidden'> <div className='h-[50vh] w-full'> some content </div> <Slider items={data?.carousel_img?.images} /> <div className='h-[200vh] w-full bg-red-100'> some content </div> </div> ) } export default function Slider({ items, section }) { useGSAP(() => { let loop = horizontalLoop(`.carousel-${section} li`, { repeat: -1 }) let slow = gsap.to(loop, { timeScale: 0, duration: 0.5 }) loop?.timeScale(0) Observer.create({ target: `.carousel-${section}`, type: 'pointer,touch,wheel', wheelSpeed: -1, preventDefault: true, onChange: (self) => { loop.timeScale(Math.abs(self.deltaX) > Math.abs(self.deltaY) ? -self.deltaX : -self.deltaY) // whichever direction is bigger slow.invalidate().restart() // now decelerate }, }) }) return ( <div className='absolute bottom-12 w-full cursor-grab overflow-hidden'> <ul className={`carousel-${section} carousel flex flex-nowrap pl-0`}> {items?.map((item, i) => ( <li key={i}> <Image alt={'collective of images'} src={item} width={150} height={150} sizes='100vw' className='pointer-events-none touch-none select-none ' /> </li> ))} </ul> </div> ) } function horizontalLoop(items, config) { items = gsap.utils.toArray(items) if (!items.length) return config = config || {} let tl = gsap.timeline({ repeat: config.repeat, paused: config.paused, defaults: { ease: 'none' }, onReverseComplete: () => tl.totalTime(tl.rawTime() + tl.duration() * 100), }), length = items.length, startX = items[0].offsetLeft, times = [], widths = [], xPercents = [], curIndex = 0, pixelsPerSecond = (config.speed || 1) * 100, snap = config.snap === false ? (v) => v : gsap.utils.snap(config.snap || 1), // some browsers shift by a pixel to accommodate flex layouts, so for example if width is 20% the first element's width might be 242px, and the next 243px, alternating back and forth. So we snap to 5 percentage points to make things look more natural totalWidth, curX, distanceToStart, distanceToLoop, item, i gsap.set(items, { // convert "x" to "xPercent" to make things responsive, and populate the widths/xPercents Arrays to make lookups faster. xPercent: (i, el) => { let w = (widths[i] = parseFloat(gsap.getProperty(el, 'width', 'px'))) xPercents[i] = snap((parseFloat(gsap.getProperty(el, 'x', 'px')) / w) * 100 + gsap.getProperty(el, 'xPercent')) return xPercents[i] }, }) gsap.set(items, { x: 0 }) totalWidth = items[length - 1].offsetLeft + (xPercents[length - 1] / 100) * widths[length - 1] - startX + items[length - 1].offsetWidth * gsap.getProperty(items[length - 1], 'scaleX') + (parseFloat(config.paddingRight) || 0) for (i = 0; i < length; i++) { item = items[i] curX = (xPercents[i] / 100) * widths[i] distanceToStart = item.offsetLeft + curX - startX distanceToLoop = distanceToStart + widths[i] * gsap.getProperty(item, 'scaleX') tl.to( item, { xPercent: snap(((curX - distanceToLoop) / widths[i]) * 100), duration: distanceToLoop / pixelsPerSecond }, 0, ) .fromTo( item, { xPercent: snap(((curX - distanceToLoop + totalWidth) / widths[i]) * 100) }, { xPercent: xPercents[i], duration: (curX - distanceToLoop + totalWidth - curX) / pixelsPerSecond, immediateRender: false, }, distanceToLoop / pixelsPerSecond, ) .add('label' + i, distanceToStart / pixelsPerSecond) times[i] = distanceToStart / pixelsPerSecond } function toIndex(index, vars) { vars = vars || {} Math.abs(index - curIndex) > length / 2 && (index += index > curIndex ? -length : length) // always go in the shortest direction let newIndex = gsap.utils.wrap(0, length, index), time = times[newIndex] if (time > tl.time() !== index > curIndex) { // if we're wrapping the timeline's playhead, make the proper adjustments vars.modifiers = { time: gsap.utils.wrap(0, tl.duration()) } time += tl.duration() * (index > curIndex ? 1 : -1) } curIndex = newIndex vars.overwrite = true return tl.tweenTo(time, vars) } tl.next = (vars) => toIndex(curIndex + 1, vars) tl.previous = (vars) => toIndex(curIndex - 1, vars) tl.current = () => curIndex tl.toIndex = (index, vars) => toIndex(index, vars) tl.times = times tl.progress(1, true).progress(0, true) // pre-render for performance if (config.reversed) { tl.vars.onReverseComplete() tl.reverse() } return tl }
  18. dgpapagian

    Observe touchscreen swipe

    Hello, I am using the GSAP Observer like this: Observer.create({ target: window, type: "wheel,touch", onUp: () => { maskTimeline.reverse(); }, onDown: () => { maskTimeline.play(); }, onChange: (self) => { totalScroll += self.deltaY; scrollPercentage = totalScroll / $(window).height(); if (scrollPercentage < 0) { totalScroll = 0 scrollPercentage = 0; } else if (scrollPercentage > 1) { totalScroll = $(window).height(); scrollPercentage = 1; } } }); The issue is that I also want it to work when someone drags on a touchscreen monitor. I know I could also use type pointer but I want it to activate only when swipe/drag is detected
  19. PixeledCode

    Detecting onWheelEnd while using Observer

    So I tried looking through docs but I couldn't find a way to detect when the wheel event ends when using Observer. Is it possible through GSAP or there needs to be a custom solution to detect when it ends? I only need the function to trigger when the scrolling ends, otherwise it will go to the end on a single wheel scroll. Thank You
  20. Hey there, I'd like to move an element horizontally using wheel and/or drag on desktop and touch and/scroll on mobile. I've set up Draggable for easiest possible scrolling with inertia, and Observer for wheel events. I can sort of update a target value for the element to tween to, but the back-and-forth of the respective x values won't quite work. Any tips? Best regards Constantin
  21. Hi, I have some trouble with my Observer. I used it to snap between 2 sections. I have a state for the open menu is isOpenedMenu and pass it to the navbar as props. But when I click many times it causes an error with the Observer. I'm going crazy over this because when stated in the navbar component it works normally. What's wrong with the Observer? Here is my codesanbox: Maximum call stack size exceeded by observer - CodeSandbox Please support me, Thank you so much
  22. Hi everyone, I have some trouble with my project. I'm trying to mix Observer and Scrolltrigger. I have a body with overflow: hidden to disable the native scroll of HTML. I am using a manual scroll with a Scrolltrigger. But I'm facing a problem when it becomes the manual scroll. It doesn't run onEnter and onEnterBack then using Observer to snap back. How can I make onEnter and onEnterBack run while keeping overflow: hidden in the body and the manual scroll?
  23. I have stuck to make a normal scroll with Observer. I have scroll snapped from sections 1 to 2 and from sections 2 to 4 scroll normally with Observer. The body has overflow: hidden that I can't remove. Currently, the normal scroll I make by increasing progress to test. I'm trying to make it scroll by translate y with the mouse or wheel scroll value. This is the code sandbox: https://codesandbox.io/s/scroll-rfjx9k How can I reach that? Please help me . Thanks so much
  24. Hey guys, sorry for no codepen this time...I wanted to check if it's possible first and ask if you know any demos that try this approach. I was trying to find any examples but from what I see no one tried to do it yet. While I wait for the answer I am working on a demo. I have a lottie animation - it's a 3d model being rotated 360 degrees. I want to be able to drag on x axis to "rotate" that 3d model, without using any UI element - just simple drag anywhere on the area to start rotating. So first of all, is it even possible to use draggable this way? Maybe there are some demos that show control of lottie with drag on mouse x? All codepens I saw were using scrolltrigger to control the animation, but I can't do that. Maybe observer is also an option?
  25. If you are an expert, hit me a message right now, please contact me right now I have a few hours of work today, it's urgent. If you have experience in the observer, that would be great otherwise, the scroll trigger will work, but I need premium quality of smoothness and finish in animation. Html is already ready you only have to apply the gsap code for animation. I need an expert who can apply the animation right away, not a beginner who needs days to create animations.
×
×
  • Create New...