Search the Community
Showing results for tags 'observer'.
-
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
-
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!
-
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.
-
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!
- 3 replies
-
- scrolltrigger
- react
-
(and 1 more)
Tagged with:
-
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.
-
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.
-
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.
-
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! ?
-
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....
- 3 replies
-
- scrolltrigger
- observer
-
(and 1 more)
Tagged with:
-
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>
- 9 replies
-
- gsap
- scrolltrigger
-
(and 2 more)
Tagged with:
-
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.
- 6 replies
-
- scolltrigger
- observer
-
(and 4 more)
Tagged with:
-
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
-
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 }
-
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
-
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
-
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
-
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
-
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?
- 4 replies
-
- scrolltrigger
- reactjs
-
(and 2 more)
Tagged with:
-
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
-
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?
-
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.
- 1 reply
-
- observer
- scroll trigger
- (and 3 more)
-
Hi guys, I have set up horizontal scrolling page using scrollTrigger and that works just fine (Lenis smooth scroll is present if that in any case impacts the following issue at all). Horizontal scroll: let scrollTween = gsap.to(this.scroll, { xPercent: -100, x: () => "100vw", ease: "none", scrollTrigger: { pin: this.wrapper, trigger: this.wrapper, start: "left left", end: () => `+=${this.scroll.offsetWidth} bottom`, scrub: true, }, }); What I need to accomplish is if users on trackpads (macbook) scroll horizontally (swipe with two fingers in the horizontal direction on trackpad) scrollTrigger updates and everything works as a "normal" scroll. overscroll-behavior-x: none; is also added to body to prevent default gestures on trackpad — browser history back/forward. Is there a way Observer can come in to handle this and update scrollTween somehow? Thanks...
- 3 replies
-
- observer
- scrolltrigger
-
(and 1 more)
Tagged with:
-
hi @PointC @GSAP Helper I hope that you are doing great. I'm super new to Gsap Forum. I was wondering if its possible to use Observer with ScrollTrigger container animation? I'm trying to create a website with multiple horizontal sections. My main problem now is the animations on each section and I'm unable to trigger it properly. I know if I was using container-animation then it would be easy but with Observer how can I trigger different animations on different sections? Hopefully my question is clear. Thanks, Kamran
- 2 replies
-
- containeranimation
- scrolltrigger
-
(and 1 more)
Tagged with:
-
hello everyone, thanks for reading. i want to navigate to section by clicking dot Indicator. i have tried to change the Observer code but couldn't Understand the Logic to Sync Both. please Give Me your guidance. thank you very much.