Jump to content
GreenSock

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

Call function as a parameter

Recommended Posts

Basically, every time a tween is called in my timeline, I want to recheck the value to be tweened by. `generateValue` seems to be only called once. When I resize the window every time the tween is called it uses the value it first generated.

 

Help would be very much appreciated!

 

function generateValue() {
  var value;
                             
  // if window is smaller than 520px
  if (Modernizr.mq('(max-width: 520px)')) {
    value = $window.width();
  } else {
    value = 420;
  }
  
  return value;
}

TweenMax.to($myElement, .2, [x: generateValue});

 

Link to comment
Share on other sites

Tweens cannot be modified, you will have to regenerate the tween on resize.

  • Like 1
Link to comment
Share on other sites

How would I go about doing that considering it is part of a nested timeline?

 

This is a rough example of what my setup is like:

 

function generateValue() {
  var value;
                             
  // if window is smaller than 520px
  if (Modernizr.mq('(max-width: 520px)')) {
    value = $window.width();
  } else {
    value = 420;
  }
  
  return value;
}

function createTimelineOne() {
  var tl = new TimelineMax({ paused: true });

  tl
    .to($myElement, .3, {x: generateValue})
    .to($myElement2, .2, {x: generateValue});

  return tl.play();
}

var timelineOne = createTimelineOne();

var masterTL = new TimelineMax({ paused: true });

masterTL
  .add(timelineOne);

function playTimeline() {
  masterTL.play();
}

$myButton.on('click', playTimeline);

 

Link to comment
Share on other sites

Are you suggesting recalling the timeline every time the window is resized? I'm concerned about the performance implications of that.

 

Also, I'm not really seeing what this has to do with my example. Can you demo with the example I provided please? Or something closer, with a timeline and a click event?

 

Thanks!

Melissa

 

 

Link to comment
Share on other sites

Here is the demo with timeline, for future queries please post a codepen demo, that way it is a lot easier to answer. Also, in some cases it makes a lot more sense to animate classes, in other cases you can use this method.

 

See the Pen MORErx?editors=0010 by Sahil89 (@Sahil89) on CodePen

 

  • Like 1
Link to comment
Share on other sites

I think Sahil's way is quite good. When you get new values, rebuild all the animations.

For performance and optimization reasons tweens record starting and ending values so that they don't have to keep checking on repeats / restarts.

 

It would probably be good to throttle or debounce the resize event as they can fire many times a second. In the real world I don't think users spend a lot of time resizing their browser windows when they are viewing a site. 

 

Below is a technique I haven't tried before and its a bit crude. Basically it taps into the ModifiersPlugin which allows you to hijack the values a tween was going to set and lets you modify them. You can run the "normal" values through any function or operation you like.

 

In the demo below I multiply the progress() of the tween by the dynamic "end value" which allows you to change the end value mid-tween by clicking the button.

 

Read more about ModifiersPlugin here: https://greensock.com/1-19-0/

 

I don't think is the best solution for everything... but it gets the job done in this case.

 

 

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

 

  • Like 4
Link to comment
Share on other sites

Thanks a lot to both of you! Makes a lot of sense.

 

I'll make sure to upload CodePens going forward.

 

Have a nice day

Melissa

Link to comment
Share on other sites

On 12/5/2017 at 1:42 PM, Carl said:

It would probably be good to throttle or debounce the resize event as they can fire many times a second. In the real world I don't think users spend a lot of time resizing their browser windows when they are viewing a site. 

 

I don't have any data to back this up, but I'm pretty sure that the only people who resize a browser window are developers. On top of that, resizing a window is somewhat limited to Mac users. Yes, you can resize stuff in Windows, but the UI is designed to snap the window into certain sizes, making resizes a lot less common. And then you have mobile devices, where resizes only happen when you rotate the device.

 

Depending on the browser and device, events like resize, scroll, keydown, mousemove, touchmove, and pointermove will fire constantly, so you never want to do any work in those event handlers. Move the work to another function, and limit how often that function can be called. A common approach is to throttle or debounce the event, but there are problems with those approaches.

 

With throttle, the last call may never happen. And with debounce, it may delay the call for too long. For most animation and UI related stuff, using requestAnimationFrame (rAF) is probably the best approach. That will ensure that any work you do will happen on the next screen render. Not too soon, not too late, just right.

 

Here's how that might look.

 

var requestId = null;

window.addEventListener("resize", function() {
  if (!requestId) {
    requestId = requestAnimationFrame(update);
  }
});

function update() {
  
  // run your update
  
  requestId = null;
}

 

The trick with using requestAnimationFrame is to make sure you don't call it more than once per animation frame. Doing so will add any additional calls to a queue, creating all sorts of problems.

 

That's what the if statement inside the resize handler checks for. When you call requestAnimationFrame, it returns the id of the request. The first id will be 1, the next id will be 2, and so on. If you know your truthy values, every number except 0 will evaluate as true, so using the id is the same as setting a flag to true. When update gets called, do your work, and then set the requestId to null, allowing the next resize event to call requestAnimationFrame.

 

If you're wondering why I'm using the id instead of a true/false flag for the if statement, it's because sometimes you may need to cancel a request. To do that, you have to pass in the id into cancelAnimationFrame.

 

  • Like 4
Link to comment
Share on other sites

And after writing all that, I noticed you were checking for a media query. That is not the same as a resize event. You should use a media query listener instead. It will only fire when the media changes, and not on every resize.

 

https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Testing_media_queries

https://docs.microsoft.com/en-us/microsoft-edge/dev-guide/css/media-query-listeners

 

 

 

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