Jump to content
Search Community

gsap.to inside a while loop

cnapsys test
Moderator Tag

Recommended Posts

hey all,

I just recently stumbled upon a project that I created a long time ago in flash. I used Tweenlite at that time in AS and everything worked perfectly.

About a week ago I decide it to rewrite the entire code in js (which is practically almost the same).

Upon googling and seeing that tweenlite and tweenmax are now gsap, I thought it would work the same.

However, I'm having a bit of an issue understanding why gsap behaves differently...

The problem is inside a while loop:

 

function mySpin() {
  var totstrip = 0;
  var wrap = gsap.utils.wrap(125, 0);
  
  while (totstrip < 3) {

    var newNumber = randomNumber(0, 39) * 125 + 10000;
    
    gsap.to(strips[totstrip], {y: newNumber, duration: 0.5+(totstrip*0.5), modifiers: {y: gsap.utils.unitize(wrap)}, onComplete:chkResult, onCompleteParams:[totstrip,newNumber]});
    totstrip++;
  }
}

While the animation works ok, and onComplete() receives each Param for every iteration... the problem I'm getting is that the y: newNumber seems to be the same for all 3 strips as if gsap used the first number generated for all 3 iterations.

 

Any pointers are greatly appreciated.

Link to comment
Share on other sites

Welcome to the wonderful world of JavaScript (from ActionScript). 🙌

 

It's very difficult to troubleshoot without a minimal demo (like a CodePen), but my guess is that your randomNumber() function is the problem. Perhaps it's always returning the same thing? You didn't provide that code so we can't check, thus I'm totally guessing. Also, wrap() should have the smaller number first (minimum, maximum). 

 

If you still need some help, you'll definitely increase the chances of getting a solid answer if you slap together a quick minimal demo. Here's a starter CodePen that loads all the plugins. Just click "fork" at the bottom right and make your minimal demo

See the Pen aYYOdN by GreenSock (@GreenSock) on CodePen

Link to comment
Share on other sites

Hey GS, thanks for taking the time to reply.

I'll see if I have the time to whip up a minimize codepen today. I really want to get to the bottom of this.

As for the random number you can see it defined in the code I posted initially:

var newNumber = randomNumber(0, 39) * 125 + 10000;

The randomNumber function is defined like this:

function randomNumber(param1,param2) {
  //console.log(Math.floor(Math.random() * (1 + param2 - param1) + param1))
  return Math.floor(Math.random() * (1 + param2 - param1) + param1);
}

When I send that as a parameter with onCompleteParams:[totstrip,newNumber], I can console.log it just fine.

Each time the while iterates totstrip++ console log posts the newNumber generated: E.g.  0:14000; 1:13250; 2:11625

So newNumber does get a new value per each iteration, but I have the feeling that gsap gets the first number and applies that for all 3 iterations.

The reason I say that is... that each strip should move on the Y axis the value of newNumber, but they all land on the same spot each time. (on continuous spins as well.

Link to comment
Share on other sites

Yeah, that looks like just a logic issue in your code - you're generating a random value that's always a multiple of 125 and you set up a gsap.utils.wrap() that alters the tweened value to between 0 and 125, thus it will always land at 0 (well, a multiple of 125 which is the wrapping point back to 0).

 

Here's a fork that logs things for you to see: 

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

Link to comment
Share on other sites

I see what you're saying. How do I go about it then? I thought I need the wrap in order to make sure the strips will repeat once they transition down more than their heights.  Or what values do I need to wrap around?

Thanks again for taking the time to look at this.

 

I guess I don't understand how gsap.utils.wrap() works

Link to comment
Share on other sites

I don't really understand your question, sorry. From what I can tell, GSAP is doing everything exactly as it's supposed to. 

 

gsap.utils.wrap() lets you set a minimum and maximum value (like 0 and 125) and then any number you feed into that resulting function will get wrapped accordingly. So if you feed in 126, for example, that is BEYOND the maximum (125), so it wraps back around on the other end (starting at 0), so it would return 1. Feed in 127 and you'd get 2. Same in the other direction - if you feed in a value of -5, for example, that's less than the minimum, so it wraps around the other end, so in this case that'd be 120 (because 5 less than 125 is 120). 

 

Does that clear things up? 

 

I think the fundamental problem is in your custom random code: 

randomNumber(0, 39) * 125 + 10000;

Your randomNumber() is coded to return a whole number. So any whole number multiplied by 125 will give you a perfect multiple of 125 (duh) and you're adding 1000 which is just 125*80, thus it is also a multiple of 125. So you're ALWAYS going to get a multiple of 125 and then you set up your gsap.utils.wrap() to also wrap at exactly 125, so you coded it so that no matter what, your value will always land at exactly 0 with that wrap logic. It's completely unrelated to GSAP. 

 

If you still need help, you'll greatly increase your chances of getting a quick/accurate answer if you provide a much more reduced minimal demo (not 400 lines of HTML/CSS/JS). 

Link to comment
Share on other sites

Fair enough, let me try to explain my logic a little bit and please feel free to chip in at any point.

In all honesty I had no idea how the wrap function worked and was just shooting in the dark plugging in numbers.

 

Each strip has 40 elements in an array. Each item is an image with a width and height of 125px. Thus each strip has a height of 5000px

What I'm trying to do is move each strip down on the Y a specific number (newNumber). The reason newNumber is always a multiple of 125 + 10000 is because I'm trying to make sure that each strip "rolls" down at least 2x full turns. Also, by multiplying newNumber with 125 and adding 10k it makes it easier to return at the end the winning position on each strip by doing a modulo to kind of reverse the original operation:

win1 = 40-((strip1.y % 5000)/125);
win1 = win1 == 40 ? 0 : win1;
if (win1 < 39) {
  win1 = win1 + 2;
} else {
  win1 = 0;
}

About 10 yrs ago when I initially built this in AS3 with tweenlite and blitmask this kind of logic worked well.

I guess I'm having a bit of a hard time making this work the same way with js and css.

 

By all means if this is all wrong please point me in the right direction. Or how would you go about, accomplishing this.

Any help is greatly appreciated.

Link to comment
Share on other sites

simplified codepen + slowed down the animation and removed blur.

So here's what I'm trying to do... as soon as a strip scrolls down and the top image reaches the top of the visible area I would like the strip to wrap around to that next position which is -125px from the visible area. If the spin is longer, I would like to wrap the strip on top of the previous one so that no white spaces show up.

I apologize in advance if I'm making this sound more confusing... I'm still a complete noob and trying to figure things out.

Imagine a real life casino slot reel. when position 10 passes by, position 1 follows it.

The reason I found the wrap function confusing was that it seems to be working in pixels not array elements in this case.

thank you again for your time and patience with me.


See the Pen zYaLweV by cnapsys (@cnapsys) on CodePen

Link to comment
Share on other sites

There are many ways you could set this up. I spent a bunch of time building a seamless looping helper function (you can find it in the docs), so I converted it to work vertically for you: 

 

See the Pen MWXPgKm?editors=1010 by GreenSock (@GreenSock) on CodePen

 

What's super cool about this is: 

  • It has Draggable functionality baked-in (you can skip that and avoid even loading Draggable if you want, but it's there if you need it)
  • It even has inertia-flicking and automatically lands at whole index values (so you don't land part-way between elements). 
  • It uses yPercent so that it's responsive.
  • You can just pick an index value and animate there, with full control over the ease, duration, etc. 
  • I added a "revolutions" feature, so you can do revolutions: 2 to make it add an extra two whole revolutions.
  • It's just a timeline, so you have full control over everything.
  • There are several methods that are all based on simple index values so you don't have to mess around with a bunch of math and figuring out, for example, that if you want it to animate to the 4th element, you'd have to animate things to 4 * element.offsetHeight or whatever. Just feed in the index value to the .toIndex(...) method, give it a configuration object to control the duration, ease, etc., and BOOM, you're done.  

So all you'd have to do is create one verticalLoop() for each wheel and then you can spin() each one whenever you want. It's much more object-oriented and modularized. 

 

This is waaaay more full-featured than you were initially requesting, but given the fact that you struggled for 3 days on this, I wanted to jump in and help. Normally we can't provide such advanced solutions like this to address all the logic challenges, etc. but this was a fun little project for me and I assume it'll help others down the road too. 

 

I hope that gets you moving in the right direction. Enjoy!

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

OMG! that is insane...

I have to be honest I wasn't expecting that.

You sir... are a ROCK STAR. While I was hoping to get a little bit of guidance and steering in the right direction... you have literally blown my mind.

This is bananas. I need to pay you something for the time you spent on this.

I do have to admit that I will probably spend the next 300 days trying to actually understand that entire code :))

 

Couple of things that I wanted to ask...

 

The .toIndex(...) method, as of right now, gets a randomIndex from the array on each spin and spins to that. However, on the screen the position of that index seems to be random as well. Meaning, that .toIndex(4...) might not be in the visible area of the #wheel_1 div. Is there a way to make sure the index that the wheel spins to is always positioned in the middle of the 3 visible items?

Also, keep in mind I'm still a complete noob and at a first glance I could not see a clear way to change the direction of the spin (from upwards -> downwards). And would it be possible to set this up as a variable so the direction of the spin for each wheel could be randomized? (up/down)

 

Ok, I just realized I'm getting a bit ridiculous with these requests. I apologize.

I need to buy you a beer first for the time you already wasted on my silly little project. 👍

 

  • Like 2
Link to comment
Share on other sites

  • 2 weeks later...
On 12/1/2022 at 11:31 AM, cnapsys said:

The .toIndex(...) method, as of right now, gets a randomIndex from the array on each spin and spins to that. However, on the screen the position of that index seems to be random as well. Meaning, that .toIndex(4...) might not be in the visible area of the #wheel_1 div. Is there a way to make sure the index that the wheel spins to is always positioned in the middle of the 3 visible items?

I think you might be misunderstanding. Things are based on the initial position that you set up your HTML in. I have added the index number in each block here: 

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

 

Now click the spin button and look in the Dev Tools console to see what the random index number is that was chosen. That'll always be in the top spot. Were you expecting something else? 

 

As for spinning the other direction, you could just use a negative "revolutions" number. Currently it's 2, but you could use -2 for example. 

 

Does that help? 

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