momo12 Posted November 29, 2022 Share Posted November 29, 2022 Hi, I have encountered a question. How can I animate even or odd Columns (Rows) with the help of the GSAP to library? P.S: I don't know how to target the imaginery columns! :)) I know the rest ... See the Pen oNyMJQQ by emdesigner-or (@emdesigner-or) on CodePen Link to comment Share on other sites More sharing options...
Cassie Posted November 29, 2022 Share Posted November 29, 2022 Hey there! There's not really a specific way to target grid elements based on their position. You can use the nth-child selector to target specific elements. What are your limitations here? Could you add a class? Do you know how many rows or columns there will be? See the Pen YzvOzpN by GreenSock (@GreenSock) on CodePen 1 Link to comment Share on other sites More sharing options...
Solution GreenSock Posted November 30, 2022 Solution Share Posted November 30, 2022 This was a fun chance for me to whip up a helper function that lets you dynamically figure out the rows/columns as well as further refine those with "odd" or "even" ones: function getGrid(selector) { let elements = gsap.utils.toArray(selector), bounds, getSubset = (axis, dimension, alternating, merge) => { let a = [], subsets = {}, onlyEven = alternating === "even", p; bounds.forEach((b, i) => { let position = Math.round(b[axis] + b[dimension] / 2), subset = subsets[position]; subset || (subsets[position] = subset = []); subset.push(elements[i]); }); for (p in subsets) { a.push(subsets[p]); } if (onlyEven || alternating === "odd") { a = a.filter((el, i) => !(i % 2) === onlyEven); } if (merge) { let a2 = []; a.forEach(subset => a2.push(...subset)); return a2; } return a; }; elements.refresh = () => bounds = elements.map(el => el.getBoundingClientRect()); elements.columns = (alternating, merge) => getSubset("left", "width", alternating, merge); elements.rows = (alternating, merge) => getSubset("top", "height", alternating, merge); elements.refresh(); return elements; } Usage: let grid = getGrid(".grid-i"), // first get the grid which is actually an Array of all the elements rows = grid.rows(), // all rows evenRows = grid.rows("even"), // just the even ones oddColumns = grid.columns("odd"); // just the odd columns It returns an Array with an Array for each column/row. You can even pass in true as the 2nd parameter to have it merge them all into a flat Array. Demo: See the Pen KKexgWp?editors=0010 by GreenSock (@GreenSock) on CodePen I hope that's useful. 3 1 Link to comment Share on other sites More sharing options...
Cassie Posted November 30, 2022 Share Posted November 30, 2022 Jack casually swinging in with the big guns 💪✨ 1 Link to comment Share on other sites More sharing options...
momo12 Posted November 30, 2022 Author Share Posted November 30, 2022 12 hours ago, GreenSock said: This was a fun chance for me to whip up a helper function that lets you dynamically figure out the rows/columns as well as further refine those with "odd" or "even" ones: function getGrid(selector) { let elements = gsap.utils.toArray(selector), bounds, getSubset = (axis, dimension, alternating, merge) => { let a = [], subsets = {}, onlyEven = alternating === "even", p; bounds.forEach((b, i) => { let position = Math.round(b[axis] + b[dimension] / 2), subset = subsets[position]; subset || (subsets[position] = subset = []); subset.push(elements[i]); }); for (p in subsets) { a.push(subsets[p]); } if (onlyEven || alternating === "odd") { a = a.filter((el, i) => !(i % 2) === onlyEven); } if (merge) { let a2 = []; a.forEach(subset => a2.push(...subset)); return a2; } return a; }; elements.refresh = () => bounds = elements.map(el => el.getBoundingClientRect()); elements.columns = (alternating, merge) => getSubset("left", "width", alternating, merge); elements.rows = (alternating, merge) => getSubset("top", "height", alternating, merge); elements.refresh(); return elements; } Usage: let grid = getGrid(".grid-i"), // first get the grid which is actually an Array of all the elements rows = grid.rows(), // all rows evenRows = grid.rows("even"), // just the even ones oddColumns = grid.columns("odd"); // just the odd columns It returns an Array with an Array for each column/row. You can even pass in true as the 2nd parameter to have it merge them all into a flat Array. Demo: I hope that's useful. Thanks a lot!!! Link to comment Share on other sites More sharing options...
IndM Posted February 8, 2023 Share Posted February 8, 2023 On 11/30/2022 at 6:38 AM, GreenSock said: This was a fun chance for me to whip up a helper function that lets you dynamically figure out the rows/columns as well as further refine those with "odd" or "even" ones: function getGrid(selector) { let elements = gsap.utils.toArray(selector), bounds, getSubset = (axis, dimension, alternating, merge) => { let a = [], subsets = {}, onlyEven = alternating === "even", p; bounds.forEach((b, i) => { let position = Math.round(b[axis] + b[dimension] / 2), subset = subsets[position]; subset || (subsets[position] = subset = []); subset.push(elements[i]); }); for (p in subsets) { a.push(subsets[p]); } if (onlyEven || alternating === "odd") { a = a.filter((el, i) => !(i % 2) === onlyEven); } if (merge) { let a2 = []; a.forEach(subset => a2.push(...subset)); return a2; } return a; }; elements.refresh = () => bounds = elements.map(el => el.getBoundingClientRect()); elements.columns = (alternating, merge) => getSubset("left", "width", alternating, merge); elements.rows = (alternating, merge) => getSubset("top", "height", alternating, merge); elements.refresh(); return elements; } Usage: let grid = getGrid(".grid-i"), // first get the grid which is actually an Array of all the elements rows = grid.rows(), // all rows evenRows = grid.rows("even"), // just the even ones oddColumns = grid.columns("odd"); // just the odd columns It returns an Array with an Array for each column/row. You can even pass in true as the 2nd parameter to have it merge them all into a flat Array. Demo: I hope that's useful. @GreenSock How do I use this but with a scrolltrigger? I need to animate items per row, but it seems that when I use the row as a trigger it doesn't work. This is what I added to it: ``` rows.forEach((GridItems) => { let tl = gsap.from(GridItems, {opacity: 0, yPercent: 80, stagger: 0.05, duration: 0.7, overwrite: true}); ScrollTrigger.create({ trigger: GridItems, start: 'top 70%', end: 'bottom bottom', markers: true, onEnter: () => tl.play(), onEnterBack: () => tl.restart(), onLeaveBack: () => tl.pause(0), }); }); Link to comment Share on other sites More sharing options...
Rodrigo Posted February 8, 2023 Share Posted February 8, 2023 Hi, Using the original example Jack created it should be as simple as this: See the Pen BaPeYdM by GreenSock (@GreenSock) on CodePen Hopefully this helps. If you keep having issues please remember to include a minimal demo of what you have. Happy Tweening! 1 Link to comment Share on other sites More sharing options...
IndM Posted February 8, 2023 Share Posted February 8, 2023 Hi @Rodrigo, thanks for the response! This code works great, but only when you have the full grid displayed in the viewport. When you have a long grid that not fully fits the viewport, the animation shouldn't play on the elements that aren't visible. Only animate those when you scroll to the element in the viewport. I made a little demo: See the Pen NWBVYqG by indy-meermans (@indy-meermans) on CodePen Link to comment Share on other sites More sharing options...
Rodrigo Posted February 8, 2023 Share Posted February 8, 2023 Hi, Maybe you should take a look at ScrollTrigger's batch method: https://greensock.com/docs/v3/Plugins/ScrollTrigger/static.batch() Here is a live example: See the Pen NWGPxGZ by GreenSock (@GreenSock) on CodePen In the case of your last codepen example it would be as simple as this: gsap.registerPlugin(ScrollTrigger); gsap.set(".grid-i", {y: 50, opacity: 0}); ScrollTrigger.batch(".grid-i", { onEnter: batch => gsap.to(batch, {opacity: 1, y: 0, stagger: 0.15, overwrite: true}), }); Hopefully this helps. Let us know if you have more questions. Happy Tweening! 1 1 Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now