Jump to content
Search Community

How can I animate the odd and even columns / Rows of a grid with GSAP.To?

momo12 test
Moderator Tag

Go to solution Solved by GreenSock,

Recommended Posts

  • Solution

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. 

  • Like 3
  • Haha 1
Link to comment
Share on other sites

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

  • 2 months later...
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

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

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!

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...