Jump to content


  • Posts

  • Joined

  • Last visited

Everything posted by nonoumasy

  1. Thank you! That works! I'm going to update all my react app with this new selector util.
  2. Thanks for the tip on the selector util. Is that new? At any rate, I got the scrollytelling thing to work: https://codesandbox.io/s/elegant-meninsky-hwvu5?file=/src/App.js It's a bit hacky. In particular, the only way to get the lat and lon values is to add them as a div elements. I might have to use something like the intersection observer to make it cleaner. If thats the case, I wouldn't need scrollTrigger. Btw, I was able to create the array of items by mapping the q('.card). I didn't see that in the documentation so it took awhile to figure it out. useEffect(() => { q(".card").map((item) => { ScrollTrigger.create({ trigger: item, start: "top center+=150", end: "top center", toggleActions: "start reverse none start", onEnter: () => myEnterFunc(item), onLeave: myLeaveFunc, onEnterBack: () => myEnterFunc(item), onLeaveBack: myLeaveFunc, markers: "true", scrub: "true" }) }) }, [])
  3. https://codesandbox.io/s/elegant-meninsky-hwvu5?file=/src/App.js Essentialy, I'm trying to create a scrollyTelling feature. I would like to trigger a flyTo function on the map using scrollTrigger rather than a click. I want to pass arrayItem objects(which has latitude, longitude values) to the Scrolltiger.create onEnter property so that it can pass these values to the actual flyTo() function which moves the map around. Since scrollTrigger is the one triggering each event based on an item on the array, I figure you somehow need to involve it. Still trying to figure this out. Thanks for any help. I'm using useRef in react to get a reference to the card div so it can create an array of refs for scrollTrigger. const revealsRef = useRef([]) const data = [ { id: "foo1", title: "lorem ipsum", latitude: 38, longitude: -118 }, { id: "foo2", title: "lorem", latitude: 39, longitude: -119 }, { id: "foo3", title: "lorem", latitude: 37, longitude: -117 } ] revealsRef.current = [] const addToRefs = (item) => { if (item && !revealsRef.current.includes(item)) { revealsRef.current.push(item) } } {data.map((item, index) => ( <div className="card" key={index} ref={addToRefs} style={{ cursor: "pointer" }} onClick={() => flyTo({ data, id: item.id })} > <div>{item.title} </div> <div>{item.latitude} </div> <div>{item.longitude} </div> </div> ))} ... I tried logging mapped items from these revealCurrents. I get this: <div class="card" style="cursor: pointer;"> <div>lorem </div> <div>37 </div> <div>-117 </div> </div> so I can probably do some querySelector to get that lat and lon values from this and pass this to the flyTo function. However, I was wondering if there was a more elegant way to do this with ScrollTrigger. I apologize if this is more of a React/javascript thing more than a scrollTrigger, but just thought I would ask. ps. just adding this. Would it be better not to include scrollTrigger to trigger the flyTo() function. Maybe I can just listen to when the card div hits a scrollPosition Y and then call the flyTo() and pass the lat and lon that way?
  4. Yes! Thank you so much. I was missing the 'querySelector' as a way to reference the elements I wanted to animate. Also, yes the timeline is much cleaner to work with. I have refactored my code and updated the CSB. 😀
  5. https://codesandbox.io/s/gsap-story-with-text-yhb9w I'm revealing each card one by one using scrollTrigger. Sometimes I would like to render different elements from a .map one after another instead of the same time. I would like to have a different animation for each one, eg image, title, description. However, I only have access to the 'item' object which the ref contains. How would I seperate these? I tried destructuring the object but that didn't work. I also tried combining item with 'div' and other combinations. Cheers and thanks in advance for any help. n
  6. https://codesandbox.io/s/travel-conditions-wj96q?file=/src/components/GridComponent.js I used the same code for a Nextjs however it doesn't seem to work for this React app. If I save, then it will (sort of) work until a refresh. The GSAP part is in the component/GridComponent
  7. Here is the code I used that worked with NextJS: (however, this didn't work for me in a React app)...any ideas? import { gsap } from "gsap"; import { ScrollTrigger } from "gsap/dist/ScrollTrigger"; gsap.registerPlugin(ScrollTrigger); import data from '../data' export default function ReactComponent () { //GSAP section const revealsRef = useRef([]); revealsRef.current = []; useEffect(() => { revealsRef?.current.map((el, index) => { gsap.fromTo( el, { autoAlpha: 0 }, { duration: 1, autoAlpha: 1, ease: "power2", scrollTrigger: { id: `section-${index + 1}`, trigger: el, start: "top center+=300", end: "bottom top", toggleActions: "restart none none reverse", // markers: "true", scrub: "true" } } ); }); }, []); const addToRefs = (el) => { if (el && !revealsRef.current.includes(el)) { revealsRef.current.push(el); } }; //end of GSAP section return ( <> {data.map((item) => { return ( <div ref={addToRefs} key={item.id}> ... </div> ) } </> ) ) }
  8. Finally got this scrollTrigger to work. Demo: https://oocbl.sse.codesandbox.io/
  9. I tried both. I added gsapAnim to fetchData which was called in useEffect. That didnt work so I just added it after fetchData in the useEffect. and that didnt work either, well sometimes it did, but not consistent. Then when I added the useTimeout, it did work.
  10. I did add it last. The only way i could make it work was to add a little timeout. useEffect(() => { fetchData() setTimeout(()=> { gsapAnim() }, 1000); }, []) const fetchData = async () => { const db = firebase.firestore() const data = await db.collection('trips').doc(id).get() const item = await data.data() const data2 = await db.collection('trips').doc(id).collection('chapters').get() const item2 = await data2.docs.map(doc => (doc.data())) await setJournal(item) await setChapters(item2) // await gsapAnim() } const gsapAnim = () =>{ gsap.from(headerRef.current, { autoAlpha: 0, ease: 'none', delay: 1 }); revealRefs?.current?.map((el, index) => { gsap.fromTo(el, { autoAlpha: 0 }, { duration: 1, autoAlpha: 1, ease: 'power2', scrollTrigger: { id: `section-${index + 1}`, trigger: el, start: 'top center+=0', end: 'bottom top', toggleActions: 'restart none none reverse', // markers: 'true', scrub: 'true', } }); }); }
  11. Ok, i finally fixed this with useEffect(() => { fetchData() setTimeout(()=> { gsapAnim() }, 1000); }, []) so that 1 second gave it just enough time to fetch the data. still not sure if the array had more items if this trick would work.
  12. That was exactly it. I added the gsap() function after setChapters() in the fetchData function and now it works some of the time. Can you pls take a look at : https://tripmap.netlify.app/journals/gGKrNrmT8JAYDSqBBt0X Sometimes the section has more height sometimes less. Is this still part of the problem of not waiting for the fetched data? I added awaits on most of the fetching stuff so I'm not sure what else I can do to make sure the state is finished before calling the GSAP function. FYI, on mobile its not that bad. the sections end in the right place. thanks.
  13. I used this as a guide for ScrollTrigger and React with dynamic data being mapped. https://ihatetomatoes.net/react-and-greensock-tutorial-for-beginners/ So it sort of works. Sort of. My code is pretty much the same as the demo above except I'm fetching data from Firebase Firestore with a useEffect to fetch the data and then to invoke the GSAP animation. A Couple of things: 1) just like the demo, my headerRef does animate (and that is using the fetched data) but only that. The array of items that is mapped from the fetched data doesn't get the animation. 2)also, something wierd, if I make a change and save my React app, this will actually make the animation work, but as soon as I hit refresh on the browser, it goes back to not working. I've turned the markers on and I only see them at this time. 3)I would have added a CodePen but since this requires a Firebase and React, I thought I would just paste the relevant code below: Hope someone can help. const DetailScreen = ({ }) => { const headerRef = useRef(null); const { id } = useParams() const [journal, setJournal] = useState([]) const [chapters, setChapters] = useState([]) const revealRefs = useRef([]); revealRefs.current = []; const addToRefs = el => { if (el && !revealRefs.current.includes(el)) { revealRefs.current.push(el); } }; useEffect(() => { fetchData() gsapAnim() }, []) const fetchData = async () => { const db = firebase.firestore() const data = await db.collection('trips').doc(id).get() const item = data.data() const data2 = await db.collection('trips').doc(id).collection('chapters').get() const item2 = data2.docs.map(doc => (doc.data())) setJournal(item) setChapters(item2) } const gsapAnim = () => { gsap.from(headerRef.current, { autoAlpha: 0, ease: 'none', delay: 1 }); chapters && revealRefs.current.map((el, index) => { gsap.fromTo(el, { autoAlpha: 0 }, { duration: 1, autoAlpha: 1, ease: 'none', scrollTrigger: { id: `section-${index + 1}`, trigger: el, start: 'top center+=100', toggleActions: 'play none none reverse', markers: 'true' } }); }); } return ( <div className={"detailContainer"}> <div ref={headerRef} className={"headerSection"}> <img className={"journalImage"} src={journal.journalImage} alt='' /> <h2 className={"title"}>{journal.title}</h2> <h4 className={"author"}>{journal.author}</h4> <div className={"tagsSection"}> {journal.tags && journal.tags.map(tag => (<Tags tag={tag} />))} </div> <div className={"summarySection"}> <div style={{ fontSize: 24, fontWeight: 'bold' }}>Summary:</div> <div className={"summary"}> {journal.summary} </div> </div> </div> <div className={"entrySection"} style={{ marginTop: 120, }} > {chapters.map(item => ( <div key={item.id} ref={addToRefs}> <Entry item={item} /> </div> ))} </div> </div> ) }
  14. thanks. good to know. I might just do smaller animations like these at first.
  15. Thanks for the clarification. It helps put it in context. 'tweening engine' is a good mental model. I assume thats its core feature or do the other plugins offer different tooling that make it interactive , etc. It's good to know it can be done albeit with a different workflow and toolset. cheers
  16. Hi, Just getting into GSAP for many different use cases. One of which is I would like to make some animations you would normally do in After Effects but with code. Is that a fair comparison? Basically, can I make an animation like this in GSAP? Or would it make more sense to use a couple of tools like AE with GSAP. The reason why I was thinking of using GSAP is for: file size, mobile responsiveness since its part of the DOM, I can make it interactive later on which you can't really do using AE. N
  17. Thanks Zach. Your answer is very helpful. It confirmed that it's possible to do this. Also, good to know which modules to use. I agree the UI is pretty complex. I think I won't have anything complex like an actual timeline, ala AE but keep it as simple as text. I just wanted to know if there was a way to store a keyframe for each SVG element and save that. It seems with this Flip plugin, it's possible. That was the missing piece I think for me. Then I would just have a play button in presentation mode(vs editor mode) to playback the battle animation. Cheers N
  18. Hello, I've been thinking of creating an MERN app that will let users create Battle Maps that recreate historical/fictional battles. User can add SVG elements like polygon(rectangles), text, etc on a map, position it, and then create a keyframe for it. User can keep adding and once finished, the User can save and share this Battle Map. Other Users can either hit a play button and the map will animate and they can also step thru each keyframe. I created a rough mock to show the general idea. My question is how would you do this with GSAP.