Jump to content
Search Community

Event Tween - Feature Request

ElliotGeno 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

One thing I always find myself doing over and over again is using a query selector to access elements that aren't going to be accessed by any other code. Pair this with additional for loops for adding logic to multiple elements, and you add a lot of additional code. I am tired of typing all this!

 
It would be great to be able to trigger a tween based on a click or other event without having to break out of the TweenMax selector engine style.
 
For example, lets say I want add a drop down menu, normally my code would look like this at it's simplest...
 
var button = document.getElementById("myButton");
var close = document.getElementById("myClose");
button.addEventListener("click",open);
close.addEventListener("click",close);
function open(e){
   TweenMax.to("#menu",.5,{top:100});
}
function close(e){
   TweenMax.to("#menu",.5,{top:0});
}
 
What if tween max could chain an event callback to a tween method for you? The code could use the same selector engine, and just add a callback or a tween like this:
 
The resulting code would be identical to the code functionality above:
TweenMax.eventTo("#myButton","click", "#menu", .5, {top:100});
TweenMax.eventTo("#myClose","click", "#menu", .5, {top:0});
 
Things could get really interesting if you could accept arrays:
TweenMax.eventTo(["#button1","#button2"],"click",["#object1","#object2","#object3"],{top:100});
 
Or even callbacks!
TweenMax.eventCall(["#button1","#button2"],"click", open, someArguments);
 
 
So the basic signature would be as follows:
TweenMax.eventTo(event dispatchers, event string, targets, tween properties);
TweenMax.eventCall(event dispatchers, event string, callback, optional arguments);
 
 
You could even trigger the event dispatcher as the target itself:
var buttonList=["#button1","#button2","#button3"];
TweenMax.eventTo(buttonList,"mouseover","_self",{opacity:1});
TweenMax.eventTo(buttonList,"mouseout","_self",{opacity:.5});
 
 
Other tween types could be created too, for example:
TweenMax.eventFrom
TweenMax.eventFromTo
TweenMax.eventStaggerTo
TweenMax.eventSet
  • Like 2
Link to comment
Share on other sites

Hi Elliot,

 

Thanks for the suggestion. I appreciate how well thought out it is and explained.

 

I give you extra points for the clever API recommendation, I thought the following was quite practical:

TweenMax.eventTo("#myButton","click", "#menu", .5, {top:100});
TweenMax.eventTo("#myClose","click", "#menu", .5, {top:0});

You make a strong case for that syntax being more concise than the vanilla or even jQuery alternatives.

 

Ultimately this will come down to how much of a priority something like this (as opposed to core animation features that we're working on) and how far down this "event management" path we are willing to travel. 

 

FWIW we have been kicking around the idea of building some sort of canned effects classes so its super easy to do jQuery-ish things like show(), hide(), slideIn() or effects like wiggle, bounce, spin3D or whatever. Perhaps this easy event assignment stuff would marry well with that.

 

I know that Jack is swamped right now so it may take some time for him to weigh in. All I can tell you now is that I appreciate the recommendation and agree it has merit. 

 

I would be interested in hearing what other community members think, too

Link to comment
Share on other sites

i think that just have Down side for GSAP Core and unnecessary extra code weight , since you can handle that easily with a simple function , something like this :

function TweenHandler( handler , Ev , target , type , dur , Vars1 , Vars2 ){
  var handler = document.getElementById(handler);
  handler.addEventListener(Ev,function(){
    type( target=='_self' ? handler : target  , dur , Vars1 , Vars2 );
  });
};

TweenHandler("ToBtn","click","#myObj",TweenMax.to,1,{x:100,y:20});
TweenHandler("FromToBtn","mouseover",'_self',TweenMax.fromTo,3,{x:0,y:400,opacity:0},{x:0,y:0,opacity:1,ease:Elastic.easeOut}); 

or

function TweenHandler( handler , Ev , target , type , dur , Vars1 , Vars2 ){
  var handler = document.getElementById(handler);
  handler.addEventListener(Ev,function(){
    TweenMax[type]( target== '_self' ? handler : target , dur , Vars1 , Vars2);
  });
};

TweenHandler("ToBtn","click","#myObj","to",1,{x:100,y:20});
TweenHandler("FromToBtn","mouseover","_self","fromTo",3,{x:0,y:400,opacity:0},{x:0,y:0,opacity:1,ease:Elastic.easeOut}); 

pls check this out : 

See the Pen MYRrje by MAW (@MAW) on CodePen

  • Like 3
Link to comment
Share on other sites

I tend to agree with Diaco on this one, although I totally see why it'd be convenient to have this functionality baked in. Every time someone requests a feature, we have to weigh the cost/benefit ratio. Not only would this bloat the file size more (a cost that we'd be making EVERYONE pay, even those who don't use/want it), but we're expanding the API surface area quite a bit as well (looks like roughly 7 exposed methods).

 

Another factor is the messiness of dealing with events in various browsers. And if someone wants a "click" to trigger something, do we assume that means they want it touch-enabled as well? Touch events are totally different on Microsoft devices than iOS, and Android has quirks as well. And what about the future and the events that may get added to browsers later - we'd have to be committed to supporting all those.

 

This feature would also bind the core engine more and more to the DOM whereas our original design intent was to avoid that. In other words, what if you're using a canvas library or something else that has a completely different way of handling "events". Would eventTo() just not work (and all those other methods)? Is that intuitive?

 

So biting off this "feature" would entail a pretty heavy cost and commitment. The fact that it's so relatively easy to just write your own function in this case to accomplish the task makes me heavily inclined to just encourage folks to do that instead of baking it into the core of GSAP. 

 

Again, I'm not saying it's a "bad" idea at all, and I totally see why you'd request it. I just don't think the benefits outweigh the costs right now. I'll keep it on the radar, though. 

  • Like 3
Link to comment
Share on other sites

What if we took a different approach? What if you did something like TimelineMax does instead? Create a method chained way of adding tweens to events so you don't have to create method for each type...

 

TweenMax.event().to();

 

The original example becomes this:
TweenMax.event("#myButton","click").to("#menu",.5,{top:100});
TweenMax.event("#myClose","click").to("#menu",.5,{top:0});
 
Because event() would return a reference to TweenMax, you could chain any existing TweenMax method to this event. You might need to also add a conditional to check if an event is triggering the tween versus calling the tween outright.
 
As for touch events, I wouldn't worry about them...  generic events could cover a vast majority of the events you encounter. If someone is handling touch events or needs to tie the handler to the event details any closer... they are likely building something a bit more involved anyway.
Link to comment
Share on other sites

What about just exposing some version of the EventDispatcher GSAP uses? From what I can tell, it looks very similar to the event system used in Backbone and Angular to pub/sub. While it may not be what Elliot was looking for, it could still be a nice way to send out messages to any listeners, and this way the events aren't bound to a certain type of object.

 

The syntax could be...

// Trigger, dispatch, signal, etc. an event
TweenMax.broadcast("color-changed", someData);

// Subscribe
TweenMax.on("color-changed", someCallback);

// Unsubscribe
TweenMax.off("color-changed", someCallback);

See the Pen 9e5abfa4f97deefa4333f155fb171f15 by osublake (@osublake) on CodePen

 

Link to comment
Share on other sites

Blake, are you suggesting that GSAP itself would dispatch various events like color-changed? I think that could turn into a nightmare both in terms of performance and maintenance. Remember, one must factor plugins into the equation. So if GSAP was going to dispatch an event every time a color is changed, it'd affect all plugins that could change any colors. In addition, it'd have to get injected into the main rendering queue to fire off these events at the appropriate times which would have a pretty significant effect on performance. And if we did this for colors, I suspect folks would want to be notified for other types of changes too (position? rotation? etc.) Wouldn't it be cleaner to just use an onUpdate if you're wanting to get notified like that? Maybe I totally misunderstood your point though :)

 

Elliot, I'm struggling to decide why this:...

TweenMax.event("#myButton","click").to("#menu",.5,{top:100});

is significantly better than this:...

$("#myButton").click( function() {
    TweenMax.to(this, 0.5, {top:100});
});

?

 

I think the 2nd one reads better anyway, and there's a cleaner separation of concerns. I also think it's more flexible and accommodates various scenarios because quite often you might want to do other things when a particular event happens (beyond tweening), like maybe set an "isOpen" variable or toggle something else on the screen or whatever - that's easy to tuck into the function in the 2nd example above but it'd be virtually impossible to do if everything is internalized inside the tweening engine. I guess I'm just struggling to figure out the ultimate objective here and how baking it into the tweening engine itself is superior. 

 

I don't mean to sound argumentative or negative at all with either of you - I welcome the discussion and kicking around ideas. 

  • Like 2
Link to comment
Share on other sites

No. color-changed was just what I copied over from my demo, and would not be called every time the color actually changes. In my demo when you press the color button, it raises the color-changed event, and there are 2 listeners that do something when its called. These are just generic events/messages/signals, whatever you want to call them. Isn't this the same concept used by GSAP's EventDispatcher? So I could re-write the code above like this, and the same thing would happen.

TweenMax.broadcast("something-cool-happened");

TweenMax.on("something-cool-happened", someCallback);
Link to comment
Share on other sites

I think I see what you mean, but perhaps my confusion had to do with what the intent was with GSAP specifically - were you suggesting that something be added to GSAP's core? Did you want to use TweenLite and/or TweenMax as a centralized event dispatcher instead of creating one like you did? 

  • Like 1
Link to comment
Share on other sites

Right. I wasn't suggesting that something should be added to the core, like what Elliot proposed... although I do I like his idea. 

 

My idea was just to use GSAP as a centralized event dispatcher, nothing more. Since most events are tied to the UI, and GSAP is core to the UI, having a fast, lightweight dispatcher built-in seems only natural.

 

I created the dispatcher used in that demo to avoid having to use ones provided by frameworks like Angular, which can be slow due to all the overhead involved in doing stuff like dirty checking. Having one built into GSAP would definitely help streamline the development process, and would probably offer a performance gain in apps that rely heavily on events.

Link to comment
Share on other sites

  • 1 month later...

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