Jump to content

Shrug ¯\_(ツ)_/¯

Advanced Stagger Positions

Warning: Please note

This thread was started before GSAP 3 was released. Some information, especially the syntax, may be out of date for GSAP 3. Please see the GSAP 3 migration guide and release notes for more information about how to update the code to GSAP 3's syntax. 

Recommended Posts

Hi all,


I’ve been wondering if currently there exists an easy way to target the 9 typical transform points of a box / grid with the new staggers?


TL - top left

TC- top center

TR - top right

ML - middle left

MC - middle center

MR - middle right

BL -bottom left

BC - bottom center

BR - bottom right


Those 9 reference points are common typical points of transforms. I see there is already various nifty calculations being done but is that 9 position logic also 'dynamically' possible even with reflow (like others) within the new advanced staggers?




Thanks everyone!

Link to comment
Share on other sites

I'm not sure I understand the question. Are you saying you've got 9 different elements, all arranged in a grid, and you want to animate each one but have the start times of each animation be based on their position in the grid? Or are you saying that there's ONE element, and you're trying to basically stretch/morph it by independently grabbing/animating key points on it (like top left, bottom right, etc.)? 


I think it'd help if you gave a little more detail about your end goal. Got a demo? 


It's very easy to do advanced staggers based on positions in a grid, yes. It is impossible to stretch/morph an individual element by animating key points on it (unless maybe you do some advanced work with canvas and a library like PIXI.js). 

  • Like 1
Link to comment
Share on other sites

Thanks for the reply, sorry I will try to clarify.


Meaning if you have a square / rectangle grid of any number of items (target elements) can you easily set the starting stagger point to trigger from one of those 9 positions mentioned above when invoking the stagger? I hope that makes more sense.


Like this:




I thought I read where the new advanced staggers had logic to update the index to know when the grid changes (rows/columns). That is what I mean by dynamically and including reflow in my initial post.


The question is can those 9 positions be targeted easily?

  • Like 1
Link to comment
Share on other sites

The from property accepts strings "start", "center" and "end" or the index of any element in your array.



So in your case you could use any number 0-8 and that would be the start point of the staggers. 


Happy tweening.

Link to comment
Share on other sites

24 minutes ago, PointC said:

So in your case you could use any number 0-8 and that would be the start point of the staggers. 


Hi @PointC, thanks for the response.


But wouldn't that be the case if there were only 9 items? When I mention 9 I'm speaking of those 9 positions mentioned in my original post, within a grid as mentioned in my follow up post, which I think I was in the process of updating when you responded.


@GreenSock, I am just wondering if the logic is already present in advanced staggers, or if I'll need to somehow calculate that myself.

Link to comment
Share on other sites

Okay, I understand now. I'm not aware of any logic in place to calculate that for you (yet ;)), but Jack can answer that or maybe he'll add that functionality.


For now I think you'd have to calculate the size of your grid and figure the index of each of those 9 positions.

Link to comment
Share on other sites

Here's a helper function I whipped up that'll spit back the appropriate index number: 


function findPositionIndex(elements, x, y) {
  if (typeof(elements) === "string") {
    elements = document.querySelectorAll(elements);
  var max = -Infinity,
      cols = 0,
      l = elements.length,
      factors = {center:0.5, bottom:1, right:1},
  while (max < (max = elements[cols++].getBoundingClientRect().left) && cols < l) { }
  rows = (l / cols) | 0;
  return Math.floor((factors[y] || 0) * rows) * cols + (Math.floor((factors[x] || 0) * cols + 0.5) || 1) - 1;


So you'd use it like this: 

tl.staggerTo(".box", 1, {
  stagger: {
    from:findPositionIndex(".box", "center", "top")


Here's a codepen: 

See the Pen BegYXV?editors=0010 by GreenSock (@GreenSock) on CodePen


Does that help? 

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



? Wow! 


Yes that helps tremendously what a cleaver approach and function! The only covet is to keep in mind the need for a grid with the right divisible rows and columns to have or retain those 9 positions - so I should be able to work with this.


Thanks so much that is truly awesome Jack. Thanks for graciously and so nonchalantly whipping that up along with the example! 


¯\_(ツ)_/¯  I don't know how you make it all look so easy.  :--)

  • Like 2
Link to comment
Share on other sites

Ah, you mean you'd need to make sure there are an odd number of rows/columns in order for things to be truly centered on an axis? Well that spurred an idea...


What if you could use normalized ratios in an array, like [0.5, 0] where the first number corresponds to the x-axis and the second to the y-axis? So [0.5, 0] would be center top, [1, 0.5] would be right center, etc.? This way, you'd get total freedom and you could literally use ANY decimal value between 0 and 1 for each. If we get enough interest, I'd consider adding this functionality to the next release. Here's a demo with the helper function: 


See the Pen 2b691d6b72f1f6a177922f42da38aa39?editors=0010 by GreenSock (@GreenSock) on CodePen


I made that so you could even use a normal decimal and it'd apply to both axis, so from:0.25 would be a quarter of the way across the x-axis and the y-axis. 


To be clear, all you've gotta do is wrap your normal advanced stagger object in this helper function and it'll work. No need to wait for the next release or anything (though if we add it to the next release, obviously you wouldn't NEED this helper function since it'd be baked-in). 


If anyone has suggestions for improving it, I'm all ears. 

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

? Wow, well done !


That is an outstanding modification as it appears it would work nicely even when needing to recalculate dynamically. That is some true awesomeness, thank you Jack ! Does the neuronal firing in your brain ever overheat ? Slow down fella. ?

  • Like 1
Link to comment
Share on other sites

32 minutes ago, Shrug ¯\_(ツ)_/¯ said:

it appears it would work nicely even when needing to recalculate dynamically.


Can you explain what you mean by "recalculate dynamically"? I just want to make sure I'm not missing something. I mean, it's not like if you did a staggered animation and THEN you resized the window and everything re-flowed, that it'd magically go back and alter all the staggers for you. That's way beyond the scope of this. But the whole grid:"auto" thing nicely accommodates figuring stuff out on-the-fly, like if you've got media queries in place that set things up differently (before the animation is created). Is that what you meant? 

Link to comment
Share on other sites

Thanks for the conversation!


In your comment, yes the latter functionality was what I was also inquiring about with my 'dynamic & reflow' reference even back to the OP. But I think even the former statement could be accomplished using the above approach, if reinitiating and recalculating things are taken into account before a tween is run again after completing, etc., (with some user logic as needed) ?

Link to comment
Share on other sites

Yep, absolutely. You could always seek(0) the timeline that has the staggered animation, kill() it, and re-create it so that the stagger logic runs again and factors in all the new positions. 




Does the proposed API makes sense? The array like [0.5, 1]? Does anyone have other suggestions? I thought about a string, but it's just didn't feel as clean that way, and it'd require a bit more code. I like keeping things as concise as possible. 

  • Like 2
Link to comment
Share on other sites

13 hours ago, GreenSock said:

Does the proposed API makes sense?


To me, I think that approach is the most logical and robust to traverse rows/columns via any percentage represented through 0-1.


Thanks again!

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