Jump to content
GreenSock

Search In
  • More options...
Find results that contain...
Find results in...
shaunhurley

Callback Scope defintions

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

All,

 

In the Draggable docs at https://greensock.com/docs/Utilities/Draggable there is reference under the "onThrowComplete" property to a "onThrowCompleteScope" that can change the scope of what is being passed to the onThrowComplete function.

 

"By default, the scope of the onThrowComplete is the Draggable instance itself, but you may define an onThrowCompleteScope if you prefer, just like any other TweenLite or TweenMax."

 

Presumably this can be used in the same fashion as the TweenLite/Max onCompleteScope, onStartScope, onUpdateScope, etc. settings.

 

Maybe I'm missing the obvious, but I cannot for the life of me find any documentation or examples of using this mechanism - apart from passing it an empty object as '{}' - anywhere, including the TweenLite / TweenMax documentation, and would greatly appreciate a simple example of what the format for defining a scope to be passed to one of these functions looks like. Any suggestions or a pointer to any documentation I've missed would be hugely appreciated.

 

Specifically, I want the onThrowComplete "this" context to refer to the target element, rather than the default draggable instance.  I know I can get the target from within the draggable instance, hoewever I'm to have a single onUpdate function which I would also be calling directly based on other (non-draggable) actions.

 

Many thanks!

Link to comment
Share on other sites

Hi @shaunhurley

 

The callback system for Draggable works just like the one TweenLite/Max and TimelineLite/Max. If figuring out how to set the scope isn't obvious, then it's probably due to how your code is written.

 

My guess is that you're doing something like this, which is what all the examples in the docs do. There is a way to set the callback scope to the target when you create draggables like that, but I'm not going to get into that because it requires more work.

 

Draggable.create(".elements", {
  ...
});

 

To set the callback scope to the target, you should be working at the element level, creating one draggable at a time. This may require you to use some sort of loop if you want to create more than one.

 

var draggable = new Draggable(theElement, {
  throwProps: true,
  onThrowComplete: update
  onThrowCompleteScope: theElement
});

 

And knowing how to bind a function can simplify how you define callbacks in GSAP, or any library for the matter. Consider the following. You want to use a scoped callback for different actions, and want to pass in a couple of parameters to that callback. Pretty messy, right?

 

var animation = TweenLite.to(theElement, 1, {
  onUpdate: update,
  onUpdateParams: [100, 500],
  onUpdateScope: theElement,
  ...
});

var draggable = new Draggable(theElement, {
  throwProps: true,
  onDrag: update,
  onDragParams: [100, 500],
  onDragScope: theElement,
  onThrowUpdate: update,
  onThrowUpdateParams: [100, 500],
  onThrowUpdateScope: theElement
});

function update(min, max) {
  console.log("this", this); // => theElement
  console.log("min", min); // => 100
  console.log("max", max); // => 500  
}

 

 

Instead of specifying each scope separately, you can use "callbackScope", but it's still kind of messy. We were only able to get rid of 1 line of code.

 

var animation = TweenLite.to(theElement, 1, {
  onUpdate: update,
  onUpdateParams: [100, 500],
  callbackScope: theElement,
  ...
});

var draggable = new Draggable(theElement, {
  throwProps: true,
  onDrag: update,
  onDragParams: [100, 500],
  onThrowUpdate: update,
  onThrowUpdateParams: [100, 500],
  callbackScope: theElement
});

 

 

This is where creating a bound function might be useful. You can combine everything into a single, reusable function. The first parameter is the scope. Any additional parameters will be passed into the callback.

 

var boundUpdate = update.bind(theElement, 100, 500);

var animation = TweenLite.to(theElement, 1, {
  onUpdate: boundUpdate,
  ...
});

var draggable = new Draggable(theElement, {
  throwProps: true,
  onDrag: boundUpdate,
  onThrowUpdate: boundUpdate
});

 

Much, MUCH cleaner!

  • Like 7
Link to comment
Share on other sites

On 12/16/2017 at 5:20 AM, OSUblake said:

 

Hi @shaunhurley

 

The callback system for Draggable works just like the one TweenLite/Max and TimelineLite/Max. If figuring out how to set the scope isn't obvious, then it's probably due to how your code is written.

 

My guess is that you're doing something like this, which is what all the examples in the docs do. There is a way to set the callback scope to the target when you create draggables like that, but I'm not going to get into that because it requires more work.

 


Draggable.create(".elements", {
  ...
});

 

To set the callback scope to the target, you should be working at the element level, creating one draggable at a time. This may require you to use some sort of loop if you want to create more than one.

 


var draggable = new Draggable(theElement, {
  throwProps: true,
  onThrowComplete: update
  onThrowCompleteScope: theElement
});

 

@OSUblake

 

Thank you for this excellent explanation!  It was indeed a case of how our code is laid out, although we are using the <var draggable = new ...> approach, I had a mental disconnect thinking of the callback scope in terms of what was available at the time the callback was being *invoked* versus what was available at the time it was being *constructed*.  Total newb mistake.

 

While superficially familiar with bound functions, I certainly hadn't extrapolated to using them in this context - planning to experiment and can definitely see how it will provide a much cleaner solution.

 

In the meantime I had implemented a very ugly workaround using an inline function definition so I could progress:

 

Many thanks for the detailed and extremely clear explanation!

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