Elindo Posted August 31, 2021 Share Posted August 31, 2021 ** this is were the real thing begins... button interaction ** btna push the green rectangle from left to right - to x:200 in 5 seconds with a timeline to follow btnb push the green rectangle from right to left - to x:0 in 4 seconds with a timeline to follow. What if you push btna, and then push btnb before btna finish his timeline? What if kee pushing btna and btnb every 2 to 3 seconds before any of the time line finish? The problems is that the timelines are not recognizing the position of the green square to follow the timeline properly without jumping the green square into another place... the sequence of the red and blue squares opacity also goes out of place. How can you make the timelines recognize the position of the green square, so that the timelines can follow the movement of the green square from any location? See the Pen vYZLjJz by Elindo586 (@Elindo586) on CodePen Link to comment Share on other sites More sharing options...
Cassie Posted August 31, 2021 Share Posted August 31, 2021 Hey Elindo. Apologies but I think we're having a hard time following what it is that you're trying to achieve. Your demo is a little hard to follow as the naming conventions don't match what we're seeing visually. I've put together this template for you to try and ease the process. See the Pen 370d3b53e186b8924a1bcd3b190bbe6d by GreenSock (@GreenSock) on CodePen Could you possibly add the code you're struggling with in to this pen? It would also help if you stated alongside the code what you're expecting the result to be and what you perceive as the issue. If you could use minimal jargon that would also help ease the confusion. Let us figure out how to solve the problem. Just explain simply what the problem is. Maybe you could phrase it similarly to this? When I press button one I would like green square to do x 2 Link to comment Share on other sites More sharing options...
Elindo Posted August 31, 2021 Author Share Posted August 31, 2021 Button A pushes to the right Button B pushes to the left The problem is when you *alternate between pushing A and B the green rectangle starts to jump. If you do this: Click A (good so far) Click B (good so far) (push it before A finish his sequence) Click A again (before B finish his sequence) ... now the green rectangle jumps back to where it was with the A button, instead of picking the movement from where the B button left the green rectangle. I don't want the A button to make the green rectangle jump. I want the A button to pickup the movement at whatever place the B button left the green rectangle. Now, don't worry too much about the red and blue squares, those are only part of the timeline when you push A or B... if we can fix the green rectangle from jumping, then likely the timeline will fall in order and fix the sequence of the blue and red squares. 2 Link to comment Share on other sites More sharing options...
Elindo Posted August 31, 2021 Author Share Posted August 31, 2021 It would be easy to think you can put a "reverse" option to make the green rectangle go back, but for this animation when you take the green rectangle back, then I have a different set opacity settings that wouldn't work with the "reverse" coding.. I am trying to find a way to "reverse" the green rectangle, and play the proper set of opacities that go with the left and right movements. 1 Link to comment Share on other sites More sharing options...
Elindo Posted September 1, 2021 Author Share Posted September 1, 2021 I think I might have the solution, but I need to think on how to code it this other way.. IF gsap doesn't have a tool to make a tween pick up a move from a random location... ELSE.. (see what I did there ;)) I would need to split the tween.. I could add the green box in a single tween with push button A forward, and push button B reverse.. Then.. maybe I could add another set of separate tweens using some kind of IF/ELSE combination for proper set of opacities for each button based on the green box being < or > from position X . I would also need to make sure the A button hides the opacities from B, and that B hides the opacities from the A button. If I get this done, then I'll be half way through the hard parts for me... Link to comment Share on other sites More sharing options...
GreenSock Posted September 1, 2021 Share Posted September 1, 2021 @Elindo first of, all, thanks for joining Club GreenSock! 🙌 If I understand your question correctly, the problem is that you're only calling .play() every time but that only makes the playhead go forward from wherever it is at that moment. For example, let's say you've got a 5-second linear animation animating x from 0 to 500...and then after 4 seconds (x is now at 400), you pause() it and play a DIFFERENT timeline that makes x to back toward 0. Then, when x is at 200 you .invalidate() and .play() the first timeline... Since the playhead is still at 4 seconds, it will start playing from there! And since you called invalidate(), that flushes the recorded starting values (0) and set it to whatever it is now (200), thus that animation is now interpolating from 200 -> 500 over the course of 5 seconds (the duration). Therefore at a time of 4 (which is where the playhead is), x would need to be 440, hence the jump from 400 to 440. It's all working exactly as it should. The solution is simple: use .restart() instead of .play() so the playhead always starts at 0: See the Pen ZEyWbZz?editors=0010 by GreenSock (@GreenSock) on CodePen Does that clear things up for you? By the way, you can chain calls like animation.invalidate().restart() Also, I'm not sure what you were trying to do with the clear: self in the timeline vars but that's definitely wrong. 1 Link to comment Share on other sites More sharing options...
Elindo Posted September 1, 2021 Author Share Posted September 1, 2021 Thanks... indeed that solves much of the problem... Saaaayyy... Is there a way to link the animation to the position of X:0 and X:200????? If you see this code: var extend = gsap.timeline({paused:true }); extend.to("#Rod", {x:200, duration:5, ease: "none"}) .to("#P, #B1, #B2, #A2", {opacity:0, ease: "none"}, "<") .to("#A1", {opacity:1, ease: "none"}, "<") .to("#A1", {opacity:0, ease: "none"}, "+=0.1") .to("#A2", {opacity:1, ease: "none"}, "<") .to("#A2", {opacity:0, ease: "none"}, "+=1") .to ("#P", {opacity:1}, "<"); This part: .to("#A1", {opacity:0, ease: "none"}, "+=0.1") ^^ This, and the tweens after it, should be happening when "#rod" reached x:200 in 5 seconds. It works good if you start from x:0, or apparently any moment before x:200 ? But if you start from X:200, then the tween goes way back from the beginning taking another 5 seconds and previous opacities before the "+=0.1") code line. Also, if you push A several times it seems to increase the run time. Sooo... is there a way for the timeline to recognize the position of x, and play the opacities and timing of the tween according to the x position? And.. maybe not increase the time of the tween if you push A several times? (I am not sure if this is asking for the moon on technology) Link to comment Share on other sites More sharing options...
GreenSock Posted September 1, 2021 Share Posted September 1, 2021 1 hour ago, Elindo said: This part: .to("#A1", {opacity:0, ease: "none"}, "+=0.1") ^^ This, and the tweens after it, should be happening when "#rod" reached x:200 in 5 seconds. It works good if you start from x:0, or apparently any moment before x:200 ? I read this a few times and still don't understand, sorry. Again, please provide a minimal demo. @Cassie was kind enough to even create a template for you. It would be very nice if you used that. Your demos have been very difficult to follow, particularly because of the naming conventions and non-essential code. It's very difficult to clearly see what A1, A2, B1, B2, P, etc. are (there are no visual labels). 2 hours ago, Elindo said: But if you start from X:200, then the tween goes way back from the beginning taking another 5 seconds and previous opacities before the "+=0.1") code line. If I understand you correctly, that's because you have a 5-second tween at the beginning of your timeline that basically says "animate from whatever x is currently to x: 200 over the course of 5 seconds", so if it is ALREADY at 200 when you restart() that animation, of course tweening x from 200 to 200 over the course of 5 seconds will look like it's doing nothing (because no movement is necessary going from 200 to 200). I wonder if you expected GSAP to just totally delete that entire animation from the timeline if the destination value matches the current value (skipping the 5 seconds)(?) That would be a very bad thing, as it would mess up all the timing in that timeline. Plus what would you do if that animation had multiple values where some of them matched and some didn't? Of course you could add custom logic to accommodate whatever you want. It wouldn't be terribly difficult to dynamically build the timeline such that you wouldn't add in certain animations if the values are already there, for example. You could even adjust the duration according to how far it is away from 200 so that it's always a consistent speed: let x = gsap.getProperty("#Rod", "x"), speed = 40; // pixels per second if (x !== 200) { extend.to("#Rod", {x: 200, duration: Math.abs(200 - x) / speed, ease: "none"}); } As I recommended earlier, you would probably benefit from structuring your logic differently so that it's more dynamic instead of always calling .invalidate().restart() - just wrap your animation logic into a function that you call whenever you want to animate to a particular state: function goToState1() { let tl = gsap.timeline({defaults: {ease: "none"}), speed = 40; tl.to("#Rod", {x:200, duration:Math.abs(200 - gsap.getProperty("#Rod", "x")) / speed}) .to("#P, #B1, #B2, #A2", {opacity:0}, "<") .to("#A1", {opacity:1}, "<") .to("#A1", {opacity:0}, "+=0.1") .to("#A2", {opacity:1}, "<") .to("#A2", {opacity:0}, "+=1") .to ("#P", {opacity:1}, "<"); return tl; } Then whenever you need to animate to that state, you simply call that function. You can keep track of the currently-running timeline so that you can kill() it when you need to interrupt it to start a different one: let curAnimation; buttonA.onclick = () => { if (curAnimation) { curAnimation.kill(); } curAnimation = goToState1(); } buttonB.onclick = () => { if (curAnimation) { curAnimation.kill(); } curAnimation = goToState2(); } And just make sure that you always return the timeline from the function so you can store it as the curAnimation. Then you've got a clean function where you define the animation to each state. It modularizes your code too. 2 hours ago, Elindo said: And.. maybe not increase the time of the tween if you push A several times? (I am not sure if this is asking for the moon on technology) I covered that in the code above where you alter the duration according to the current position. Very possible, yes. It's all just logic in your JavaScript. The tools let you do almost anything I hope that helps. 1 Link to comment Share on other sites More sharing options...
Elindo Posted September 1, 2021 Author Share Posted September 1, 2021 Oh I am sorry.. you guys are too nice.. I will put labels on the boxes on future postings. Rod is the green rectangle... A1 and A2 are the set of squares to your left side of the screen, B1 and B2 are the squares on your right side of screen, and P are the two center squares.. If the tween starts at X:200 moving from your left to right, then you only need the set of on and off opacy sequence that comes after reaching x:200. I need to digest your info and test to see if I can make work.. Link to comment Share on other sites More sharing options...
Elindo Posted September 1, 2021 Author Share Posted September 1, 2021 Check this one.. I am getting a syntax error, but I am not sure why I got 2 functions with animations inside of of them. One function will play the entire sequence of the A button if #Rod < x:200 The second function will play the last few tweens of the entire sequence of the A button if #Rod == x:200 I am trying to do an if/ if else for button A... but apparently the code is wrong and I don't know why? I would do something similar for the B button.. btna.onclick = () => { if ("#Rod"< x:200) { animation.kill(); animation = stagea1(); } else if ("#Rod" == x:200) { animation.kill (); animation = stagea2(); } } Link to comment Share on other sites More sharing options...
Solution nico fonseca Posted September 1, 2021 Solution Share Posted September 1, 2021 @Elindo x:200 This syntax doesn't exist in Javascript, you can use the getProperty method to get the x value from your element: btna.onclick = () => { if (gsap.getProperty("#Rod","x") < 200) { if(animation)animation.kill(); animation = stagea1(); } else if (gsap.getProperty("#Rod","x") == 200) { if(animation)animation.kill(); animation = stagea2(); } } 4 Link to comment Share on other sites More sharing options...
Elindo Posted September 1, 2021 Author Share Posted September 1, 2021 @nico fonseca thanks!! it worked!! 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