Jump to content
Search Community

GSAP newbie - handling mouse events, tween killing, keyframes

KerryRuddock test
Moderator Tag

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

I'm a newbie to Web Development and in the process of learning if GSAP can fill my animation needs.

I am pretty sure it can.

 

This is my second post.  In my first post, I mention I am currently taking an E-course and I am in the middle

of creating a javascript reaction tester application:     

 

To view the codepen correctly, please change the View to Full Page.  Click Start.

A random sized and colored ball rotates around the screen based on a set of CSS keyframes: twirl    

This codepen is HTML, CSS and JS only, no GSAP just yet.  The code is a collection of tests in CSS and Javascript.

Not all of the code is used within my application, I am experimenting.  Apologies for any code read-ability issues.

 

I need to know if I can do the following with GSAP and perhaps a hint in the direction to go in.

 

In this topic, I use the word 'tweened' to cover any object that is the middle of animation, transition,

transform, keyframes, and any other time/movement speciality that I may have missed..

 

1) I will be changing the reaction tester animation to GSAP   I hope the switching over goes smooth.

    My goal is to have a 'tweened' object collision detection checking in real-time.  The collision may be

    against a border or perhaps another 'tweened' object.

 

   I need to perform real-time interval checks of the shapes x,y position of the object during a 'tween'.  Can I do this?

   On a mouse-event, ie. object.click(), I need to kill any tween any progress.  Can I do this?

   On a collision-event, I need to either be-able to either a) kill 1 or more tweens and start new tweens, or

    B) modify the existing tween that is currently running.  Am I able to do either a or b or both?

 

Thanks for your time, Looking forward to your feedback.

See the Pen rLJPkq by KerryRuddock (@KerryRuddock) on CodePen

Link to comment
Share on other sites

I'm not sure the demo was working as planned. I clicked the colored balls a bunch and nothing happened.

 

In short, all of that sounds possible. And using a library like GSAP will help reduce your code tremendously.

 

I think your best bet is to tap into Draggable's static hitTest() method.

 

Here is an example: http://codepen.io/GreenSock/pen/ZOayGO?editors=0010

 

Docs: http://greensock.com/docs/#/HTML5/Drag/Draggable/

 

TweenMax offers a variety of methods for killing tweens: http://greensock.com/docs/#/HTML5/GSAP/TweenMax/

  • Like 2
Link to comment
Share on other sites

Hi KerryRuddock :)

 

Welcome to the forums.

 

Looks like Carl gave you some good answers and I'll just add my 2 cents with some additional links to forum posts that should be helpful:

 

http://greensock.com/forums/topic/14235-about-irregular-collision-javascript/?hl=hittest#entry60402

http://greensock.com/forums/topic/14412-hittest-without-draggable/

http://greensock.com/forums/topic/14244-how-to-do-collision-detection-with-css-plugin/

 

Happy tweening and welcome aboard.

:)

  • Like 3
Link to comment
Share on other sites

  • 1 month later...

Hi guys,

 

Its been awhile since I posted this original question, but I have been busy honing my javascript skills and integrating GSAP

into my reaction tester application.  My original goal was:

 

  ... to have a 'tweened' object collision detection checking in real-time.  The collision may be

   against a border or perhaps another 'tweened' object. :-o

 

 

Not going with collision detection anymore, but I have simulated the object bouncing off the walls

by 'tweening' X and Y properties of the object independently and on different time scales.

 

This link: 

See the Pen grNLYQ by KerryRuddock (@KerryRuddock) on CodePen

 shows my latest work with GSAP

running the animations, I have a few questions I will ask in a moment.

 

What I create an object, I generate random X,Y coordinates as the top/left corner where I

want my object to appear.  This code in 'moveTarget' function sets and runs the tween

  // run animation on initial target path 
   tl.set(animTarget, {x:target.posX, y:target.posY })
     .to(animTarget, secY, {y:dirY, rotation:360}, "animTarget")
     .to(animTarget, secX, {x:dirX}, "animTarget");

Question 1: From my understanding of the position parameter, my .to methods are  ran asyncronously

                   based on the label I have set.  One of these methods will complete before the other.  How do

                   I kill the running method after the other method completes?, and are the X and Y properties

                   preserved? as I want to be able to start another tween with the X,Y values after the tween

                   method is killed.

 

Question 2: The x: and y: properties of this tween are fed from my object: target.posX and target.posY

                  How can I update update target.posX and target.posY while the tweens run?

 

Thank you so much guys.  The more I play with GSAP, the more I realize how I can use this platform to replace

a lot of CSS code.

Link to comment
Share on other sites

Sorry, I'm not understanding your question 1 very well and I can't try to figure out all the logic in your code.

A guess though is that you can run a condition to find the smaller value of secY and secX and use the smaller value as the position parameter of an addPause();

 

lets assume 

 

secX = 5

secY = 2

 

secY is smaller

tl.set(animTarget, {x:target.posX, y:target.posY })
     .to(animTarget, secY, {y:dirY, rotation:360}, "animTarget")
     .to(animTarget, secX, {x:dirX}, "animTarget");
     .addPause(secY)// pause the timeline at 2 seconds

for question 2 to modify values while a tween is running you can use the ModifiersPlugin

 

Blake made this cool mouse-follower demo: https://codepen.io/osublake/pen/ZOvvOX

 

I simplified it to have 1 circle and the y value changes based on mouse position

http://codepen.io/GreenSock/pen/RRzYAp?editors=1010

 

Watch the 1.19.0 release video to learn more about the ModifersPlugin: http://greensock.com/1-19-0/

  • Like 1
Link to comment
Share on other sites

Okay, Let me re-phrase Question 1:

 

In the chain of .to methods I displayed, 1 of the .to methods is going to complete before the other .to method completes as 1 method runs longer than the other method.  Is there something that I can add to the .to method that calls a function when the tween completes?

 

I am tweening X and Y coordinates asyncronously and it could be either the X tween or the Y tween that completes first. So upon completion I want to kill the other tween, preserve the X and Y values and feed them into a new tween as the starting X,Y coordinates.  Thanks for the links I will look at them now.

Link to comment
Share on other sites

It probably makes more sense to just put an onComplete on both tweens. The shorter tween will fire first and can handle pausing the timeline.

 

.to(animTarget, secY, {y:dirY, rotation:360, onComplete:killStuff}, "animTarget")
.to(animTarget, secX, {x:dirX, onComplete:killStuff}, "animTarget");
function killStuff() {
  tl.kill();
}

killing or pausing the timeline will preserve all the values at the time of the kill. New tweens will automatically start from those values.

 

If you need to see something working or need more help please provide a reduced test case that doesn't contain any of the other game logic, assets or animations.

  • Like 2
Link to comment
Share on other sites

Carl,

 

Took a while to put together a shorter codepen, apparently I was missing some code for the killStuff().

 

Based on what I am seeing, the .kill() method is not killing the tween completely.  As soon as the object

hits either the right wall or the bottom wall the tween should be killed, but it continues until both

.to methods have completed.  Not sure why, would you mind having a look?

 

 Here's the link 

See the Pen qNzLAb by KerryRuddock (@KerryRuddock) on CodePen

 

Thanks again. were almost there.

Link to comment
Share on other sites

I'm jumping into the middle of this conversation so I could be wrong, but shouldn't you be killing the timeline rather than the individual tween? The way you have your moveKill() function set up, it's only killing the x or the y tween while the other one is free to finish its animation. 

 

Have you tried:

tl.kill();
//instead of 
tween.kill();
//in your moveKill() function

Hopefully that helps.

 

Happy tweening.

:)

  • Like 1
Link to comment
Share on other sites

Hi Craig,

 

Thanks for jumping in.  I not sure if I set this up correctly, but I am passing in the timeline as a parameter and

I am seeing the same result.  Code below:

 // run animation on initial target path 
   tl.set(animTarget, {x:0, y:0 })    // x,y based on #myshape top/left
     .to(animTarget, secX, {x:500, onComplete:moveKill, onCompleteParams:["tl","x"]}, "animTarget")
     .to(animTarget, secY, {y:500, onComplete:moveKill, onCompleteParams:["tl","y"]}, "animTarget");
  }

function moveKill(tl, parm1) {
  console.log(tween, parm1);
  tl.kill();
}

Link to comment
Share on other sites

If I'm understanding your desired result correctly, you just want to kill() the timeline when either the x or y hits its wall first? I don't know that you need to pass anything to the function. You can just kill() the timeline.

 

See the Pen LkKqjQ by PointC (@PointC) on CodePen

 

Does that help or have I misunderstood something?

 

Happy tweening.

:)

  • Like 3
Link to comment
Share on other sites

That is exactly what I was looking for.   Thank you.  

 

What I found interesting Craig,  is that you removed the var from the tl object and thereby

giving the timeline object global scope.  I was curious, and tried putting the tl object back

into local scope and then tried passing tl as well as the tween into moveKill, but this too failed

function moveTarget (animTarget) {

   TweenLite.defaultEase = Linear.easeNone;
   var tl = new TimelineLite();  // <-- moveKill() doesn't recognize tl even when passed in onCompleteParams
                                 //     the scope of tl needs to be global scope.

   // animTarget will be 'tweened' to x:500,y:500
   var secX = getRandomInteger(100,300)/100; // tween X  between 1 and 3 seconds
   var secY = getRandomInteger(100,200)/100; // tween Y  between 1 and 2 seconds
 
   // run animation on initial target path 
   tl.set(animTarget, {x:0, y:0 })    // x,y based on #myshape top/left
     .to(animTarget, secX, {x:500, onComplete:moveKill, onCompleteParams:["{self}","tl","x"]}, "animTarget")
     .to(animTarget, secY, {y:500, onComplete:moveKill, onCompleteParams:["{self}","tl","y"]}, "animTarget");
  }

function moveKill(tween, tl, parm1) {
  console.log(tween, parm1);
  tl.kill();
}

I will be posting a link of the finished product shortly in case anyone else is following

this thread.

Link to comment
Share on other sites

I really thought I was on my way after viewing Craig's example, but I am still struggling to figure

out a way how to get the value of x or y in the movekill() function.  Not the propertyName itself.

  // run animation on initial target path 
   tl.set(animTarget, {x:0, y:0 })    // x,y based on #myshape top/left
     .to(animTarget, secX, {x:500, onComplete:moveKill, onCompleteParams:["{self}","x"]}, "animTarget")
     .to(animTarget, secY, {y:500, onComplete:moveKill, onCompleteParams:["{self}","y"]}, "animTarget");
  }

function moveKill(tween, parm1) {
  console.log(tween, parm1);
 tl.kill();
}

I want the X or Y value in moveKill() not  "X" or "Y" . tween[parm1] is undefined.

 

 I spent 6 hours trying to hammer this one out myself, but had no success.

Link to comment
Share on other sites

If I understand your question correctly, you'd like the final x and y positions when the timeline is killed?

 

If so, you can do this:

console.log(tween.target[0]._gsTransform.x, tween.target[0]._gsTransform.y);

Does that help?

 

Happy tweening.

:)

  • Like 3
Link to comment
Share on other sites

Craig, 

 

Your code did eventually help me figure things out 

This worked when I plugged into your codepen, but didn't work when I plugged into my development code.

Turns out that tween.target[0][0]  is double-indexed on my side of things.

 

Thanks, Onwards we go.

Link to comment
Share on other sites

For bouncing objects, I would look into using the VelocityTracker and the ThrowPropsPlugin. They're free to use on CodePen. All you have to do is reverse the velocity of the direction you want to bounce. 

See the Pen 57f44ec67cc82f1166db185dcf5ff7f1?editors=0010 by osublake (@osublake) on CodePen

 

That same pattern could be expanded into a class or function that can be reused to create multiple objects that can bounce and even be thrown.

See the Pen 9b67c34586f62058091ed16829c58ed5?editors=0010 by osublake (@osublake) on CodePen

  • Like 2
Link to comment
Share on other sites

Thanks Blake,

 

As soon as I can complete my web development course and generate income I definitely plan to  become a member

and enjoy benefits such as using the VelocityTracker plugin. Very cool, but for now I am tracking velocity manually,

 

I love your bouncing ball codepen and although I am not playing with gravity in my simulation, I am currently trying to

simulate multiple bouncing balls in the "Rapid Fire" version of my reaction tester.

 

I have one problem remaining,  In the Rapid Fire version of my project,  each object (or ball) that I add to the array

of timelines seems to be affecting the previously added array object., in fact it become undefined.  The object doesn't

disappear from the screen, its just no longer in the array of timelines.

 

I don't warrant any further help... I know.  I am trying to figure this one out on my own.  However, I want this thread

to inspire other people taking my course or just other people learning javascript and found their way to this forum to

see that they too can create wonderful javascript animations with GSAP.

 

This

See the Pen OXKYKZ by KerryRuddock (@KerryRuddock) on CodePen

  is my latest version of my reaction tester.  We're almost there.

Link to comment
Share on other sites

There's no gravity in my animation. I'm just slowing it's speed down on each bounce. Look at the code. The plugins aren't important. What is important is that I'm making the ball the subject and not the tween. I don't even keep a reference to the tween because that is not important as it will be overwritten. Focus on the balls.

 

Thousands of bouncing objects, driven by a simple update method starting on line ~86. That's it. Less than 25 lines of code using no tweens. The tweens you see in the code are for things that aren't dynamic, like the scaling, rotation, and opacity.

See the Pen vNwRdO?editors=0010 by osublake (@osublake) on CodePen

  • Like 3
Link to comment
Share on other sites

Hi Blake, 

 

 

That same pattern could be expanded into a class or function that can be reused to create multiple objects that can bounce and even be thrown.

See the Pen 9b67c34586f62058091ed16829c58ed5?editors=0010 by osublake (@osublake) on CodePen

I do appreciate the example that you provided,   Maybe I dismissed this too quick, but

 

I saw that you were pushing the ball objects to the end of your array.

I want my ball objects placed at  an array indice that makes it  easier to track for when

I need to kill off my object during my click handler event.

 

The codepen required JS Babel...  I read JS Babel is based on ecmascript6.

 

This in itself pushed me away from the codepen.  If I had more experience with class based languages

such as java and C++ or C#, I would have taken a harder look, but this was a little too much to learn for me

at this point .

 

Javascript, OOP, and GSAP ... all were foreign concepts to me a 3 months ago.

Now if you ever need a program written in CADOL, I'm your man.:)

 

I want to close off this thread.  I have the Rapid Fire working.  Therel are still a few issues:

an occasional ball appearing in two places at once or getting stuck and my click handler seems

lagging and unable to keep up GSAP.

 

Here is my final codepen for those following this thread 

See the Pen amoEOX by KerryRuddock (@KerryRuddock) on CodePen

 

Thanks again to everyone providing me with their input and helping me achieve my goal.

It has been a fantastic learning process.

Link to comment
Share on other sites

Nice! Glad you got it working. Just out of curiosity, what e-course is this from? 

 

I completely understand why you dismissed that example, so let me clarify a few things as other people might find this useful.

 

First, I was pushing objects on an empty array, which is the same thing as setting the index like you did. If you run this code you'll see that the values and order are the same in both arrays.

var array1 = [];
var array2 = [];

for (var i = 0; i < 10; i++) {
  array1[i] = i;
  array2.push(i);
}

The reason I said focus on the balls and not the tweens is because GSAP is already managing them for you. And GSAP can query an object for animations, much like jQuery can query the DOM for elements. To kill all the animations for a target, you can use .killTweensOf().

 

Check out this demo. Notice how I'm using mousedown. That should help with your click issues.

See the Pen 2e8fcffb1b6d5243fb87ed71aae383dd?editors=0010 by osublake (@osublake) on CodePen

 

About Babel, a lot of people get confused by that. Babel is not a language, and all the code I wrote is valid JavaScript. ECMAScript is a standard, it's the specification that is implemented by JavaScript, so they're the same thing. ECMAScript 6, ES6, ES2015, etc, is like the version of JavaScript. Yes, it can be confusing.  

 

The reason I used Babel is to ensure compatibility with older browsers. As of today, my example should run just fine in Chrome, Opera, Firefox, and Edge without Babel. It will fail in IE and Safari without it. Go ahead and test it out. I created a fork without Babel.

See the Pen 2845d310d9a219d207c7fdf55c82b7c7?editors=0010 by osublake (@osublake) on CodePen

 

All that weird syntax you see me using is just syntactic sugar. So the new class syntax is not a real class like in Java, C++, C#, etc. It's just cleaner way to create objects using prototype inheritance, like your Shape class. These do the same thing.

var Shape = function(shape, shapeId) {
  this.id = "#shape" + shapeId;
  this.index = shapeId;
  ...
}

Shape.prototype.clickHandler = function(target) {
  ...
};

// Using the class syntax 
class Shape {
  constructor(shape, shapeId) {
    this.id = "#shape" + shapeId;
    this.index = shapeId;
  }
  
  clickHandler(target) {
    ...
  }
}

So in the end, most of what I was doing is what you were already doing.  :shock:

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