Jump to content
GreenSock

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

updating code from v 1.19.0 to 3.5.1 setTimeout possible conflict with how duration is now handled?

Recommended Posts


So a few years ago I built a video player in TweenMax -v 1.19.0 and just now updating the javascript including GSAP to -v 3.5.1. Havent used JS in 3 years so Im rusty to say the least.

The biggest change I noticed was that the duration was inside the object like gsap.to('#thing', {duration:1, x: 20;});.


Let me describe the problem, in my video player there is the standard controls at the bottom with the play, pause, fullscreen, volume each with tweens set to their background and foreground images to change size and color. Then I have listeners listening for mouseover/out of the control bar to show it or hide once a setTimeout() has happened. I spent allot of time setting this up to get the right player behavior.

Here is a link to the video player in working order before updating from -v 1.19.0
video player

Here is a link to the player in not so functioning order. After 3.5.1.
broken player

I have updated all my tweens in the file to include the duration in the object and not as function parameters. Literally the only changes that were made to tweens were the duration's being included in the object.


The code below are the functions that are called. The crtl div is the actual div that holds all the player controls. The only change to the code is the placement of the duration inside the object as indicated by the original code being commented out right below the new gsap.to() calls.

function shoVidCtrl(){
    ctrlHidden = false;
    if(!video.paused){
        play.style.zIndex = '10';
        play.style.visibility = 'hidden';
        pause.style.zIndex = '12';
        pause.style.visibility = 'visible';
    }else{
        play.style.zIndex = '12';
        play.style.visibility = 'visible';
        pause.style.zIndex = '10';
        pause.style.visibility = 'hidden';
    }

    if(!video.muted){
        muteVid.style.zIndex = '10';
        muteVid.style.visibility = 'hidden';
        unMuteVid.style.zIndex = '12';
        unMuteVid.style.visibility = 'visible';
    }else{
        muteVid.style.zIndex = '12';
        muteVid.style.visibility = 'visible';
        unMuteVid.style.zIndex = '10';
        unMuteVid.style.visibility = 'hidden';
    }
    ctrl.style.visibility = 'visible';
  
    gsap.to(ctrl, {duration: 0.5, opacity:1});
    // TweenMax.to(ctrl, 0.5, {opacity:1});

    video.style.cursor = 'default';
}

function hideVidCtrl(){
    ctrlHidden = true;
  
    gsap.to(ctrl, {duration: 0.5, opacity:0, onComplete:function(){
    // TweenMax.to(ctrl, 0.5, {opacity:0, onComplete:function(){

        ctrl.style.visibility = 'hidden';
        play.style.visibility = 'hidden';
        pause.style.visibility = 'hidden';
        muteVid.style.visibility = 'hidden';
        unMuteVid.style.visibility = 'hidden';
        video.style.cursor = 'none';
    }});
}

Lines 1672-1750

below is a representation of how the above functions are called. There are a few places where a tween is called inside a setTimeout() and I was thinking that it might be conflicting with future events not handled? Im also bad at darts!

video.addEventListener('mousemove', function(){
    shoVidCtrl();
    clearTimeout(mouseIdel);
    mouseIdel = setTimeout(hideVidCtrl, setCtrl.hideCtrlsTime * 1000);
}, false);

video.addEventListener('mouseout', function(){
    video.removeEventListener('mousemove', shoVidCtrl);
    hideVidCtrl();
}, false);

ctrl.addEventListener('mouseover', function(){
    shoVidCtrl();
    clearTimeout(mouseIdel);
}, false);

ctrl.addEventListener('mouseout', hideVidCtrl, false);

Lines 747-780ish

I tried setting a variable in shared scope of the functions and using that variable to hold the different tween's for show and hide that are then triggered in the shoVidCtrl() hideVidCtrl() functions like so:


var cTween;

function shoVidCtrl(){
    ctrlHidden = false;
    
    if(!gsap.isTweening(ctrl)){
        if(!video.paused){
            play.style.zIndex = '10';
            play.style.visibility = 'hidden';
            pause.style.zIndex = '12';
            pause.style.visibility = 'visible';
        }else{
            play.style.zIndex = '12';
            play.style.visibility = 'visible';
            pause.style.zIndex = '10';
            pause.style.visibility = 'hidden';
        }

        if(!video.muted){
            muteVid.style.zIndex = '10';
            muteVid.style.visibility = 'hidden';
            unMuteVid.style.zIndex = '12';
            unMuteVid.style.visibility = 'visible';
        }else{
            muteVid.style.zIndex = '12';
            muteVid.style.visibility = 'visible';
            unMuteVid.style.zIndex = '10';
            unMuteVid.style.visibility = 'hidden';
        }
        ctrl.style.visibility = 'visible';
        cTween = gsap.to(ctrl, {duration: 0.5, opacity:1});
        // TweenMax.to(ctrl, 0.5, {opacity:1});
    }else{
        cTween.reverse();
    }

    video.style.cursor = 'default';
}

function hideVidCtrl(){
    ctrlHidden = true;

    if(!gsap.isTweening(ctrl)){
        cTween = gsap.to(ctrl, {duration: 0.5, opacity:0, onComplete:function(){
        // TweenMax.to(ctrl, 0.5, {opacity:0, onComplete:function(){

            ctrl.style.visibility = 'hidden';
            play.style.visibility = 'hidden';
            pause.style.visibility = 'hidden';
            muteVid.style.visibility = 'hidden';
            unMuteVid.style.visibility = 'hidden';
            video.style.cursor = 'none';
        }});
    }else{
        cTween.reverse();
    }
}

Tried defining the tween outside the functions and set paused:true, and tried to manipulate the play(), reverse(), kill().

I know you guys want a codepen but I started writing and three hours later and 300 lines of code I thought it was a total waste of my time as I have no Idea where to even start, as it was once working and now it's not with more or less the exact same code. I have no Idea how to address it in my code because I have no Idea how your code has changed.

I hope that everything I have said here makes sense.

Any ideas will be appreciated as I have run out and my next step is starting from scratch on the UI controls
 

 

Share this post


Link to post
Share on other sites

Ugh, sorry to hear about the trouble, @N1DAN. Sounds super frustrating. 

 

I'm not in a position to be able to wrap my head around 2500+ lines of code and debug it for you, but the only thing that came to mind is that perhaps you're creating conflicting tweens. Before version 3, GSAP used overwrite: "auto" as the default which means that it automatically tried to find competing tweens of the same properties of the same objects and killed any it finds. For some people that was a bit confusing, plus it cost CPU cycles so in version 3 there is no overwriting by default. You opt-in to ensure developers are more aware. Of course it's best to not create conflicting tweens to begin with, but try just adding this to the top of your file: 

 

gsap.defaults({overwrite: "auto"});

Does that resolve anything for you? 

 

Other than that, there really isn't anything I can think of that'd cause such simple tweens to behave differently in the newer version. Trust me - the new version is far more capable, plus the syntax is easier and the overall file size is significantly smaller. So you're making a good move by updating. I'm confident that once you get past this issue, you'll love working with GSAP 3. 

 

Let me know how that overwriting tweak goes. I have a sneaking suspicion it'll solve things for you based on what you described. 

  • Like 2
  • Thanks 1

Share this post


Link to post
Share on other sites

Yes that's exactly it. Thanks.

Now I have a starting point. I think it might be time to invest in doing things right and do a bit of a redesign. Is there a way to see what tweens are conflicting? Like assigning an id to a tween or something? Maybe I can do something in a onUpdate()? I really thought that it would only be the ones in the show/hide functions which is why I started wrapping them in if(gsap.isTweening('div')).

Thanks again.

Share this post


Link to post
Share on other sites

Yeah, it definitely looked like some refactoring was in order there :)

 

There is an onInterrupt() callback that'd tell you when something gets killed prematurely (like with an overwrite:"auto" kicking in). 

 

And for the record, overwriting isn't "bad" or anything - you just need to be aware of what you're doing. I've seen people creating a bunch of conflicting tweens due to logic in their code and then they wonder why they're running into performance problems or odd "glitches" (which aren't glitches at all, since GSAP is doing exactly what they're telling it to do). 

 

Example: create a 1-second rollover fade-in tween and a 0.5-second rollout fade-out tween that affects the same object...now rollover and immediately rollout. Without any overwriting, you've now got two tweens fighting over the opacity of the element, and the fade-out tween "wins" because it was created last...but it finishes after 0.5 seconds at which point the opacity JUMPS to something like 0.8 and goes up to 1. Some people are like "GSAP is broken"...but no, it's not. The fade-up tween still had about 0.5 seconds left to go, so as soon as the fade-out tween stopped overruling it on each tick, you see the fade-in finish. 

 

See the issue? 

 

It always makes me a little nervous when I see if (gsap.isTweening(...)) because it's almost always in the context of a bad UX decision like making the UI unresponsive until certain animations finish (a pet peeve of mine). Or someone is trying to mask a logic issue in their own code by slapping an .isTweening() condition on it. I'm not saying you're doing that - sometimes there are legitimate reasons to use .isTweening(), absolutely. Just be careful :)

 

Glad to hear the auto overwriting resolved things for you. Good luck with the port!

  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites
11 minutes ago, GreenSock said:

And for the record, overwriting isn't "bad" or anything - you just need to be aware of what you're doing. I've seen people creating a bunch of conflicting tweens due to logic in their code and then they wonder why they're running into performance problems or odd "glitches" (which aren't glitches at all, since GSAP is doing exactly what they're telling it to do). 


Thanks for the info. Since it is my opensource project and I want it to be as forward compatible and versatile for people that might not be using it in the same ways that I am now,  is overwrite:auto going to remain current or are things moving toward a more CPU friendly way of handling things? Also lets say that someone wanted to do a physics simulation behind the video player using GSAP would the overwrite:auto cause conflict?

About what you said about the isTweening, I think the isTweening might be the only way to tell tweening object to stop and change direction handled by multiple but similar events, like when you mouse over the player you need to see the cursor and the controls. It's the same for the controls but you no longer need the timeout to hide the controls and the cursor; but you want a timeout when leaving the controls to hide the controls and the cursor (especially if the video is playing) all of which need to be interrupted and overwritten by the last event in 1/10000000 of a second depending on how fast your kid(or me) is spasming the mouse around.  Im I right in my thinking if using isTweening in that scenario? If not Im thinking that im thinking about this entire redesign thing wrong then.

Thanks again Jack!

Share this post


Link to post
Share on other sites
1 hour ago, N1DAN said:

  is overwrite:auto going to remain current or are things moving toward a more CPU friendly way of handling things?

The default of overwrite: false is the most CPU-friendly option...it assumes you're responsible with the way you create your animations (not creating conflicts). 2nd fastest is overwrite: true because that doesn't have to care about which properties - it just obliterates any active tweens of the same object. 

 

We don't plan on changing any of those overwrite options if that's what you're asking. 

 

1 hour ago, N1DAN said:

let's say that someone wanted to do a physics simulation behind the video player using GSAP would the overwrite:auto cause conflict?

It won't cause a conflict, no - the whole purpose is to avoid conflicts ;) But I think it'd be rather strange to do physics animations with overwrite: "auto" but it's not wrong or anything. Frankly, you're not going to notice a performance difference unless you really push things hard and have hundreds/thousands of things initiating animations simultaneously. And remember, overwriting logic only runs ONCE for a tween (when it renders for the first time). It's not like it's constantly draining resources looking for things to overwrite. As you probably know, we put a lot of effort into making GSAP highly performant. 

 

1 hour ago, N1DAN said:

I think the isTweening might be the only way to tell tweening object to stop and change direction handled by multiple but similar events, like when you mouse over the player you need to see the cursor and the controls....am I right in my thinking if using isTweening in that scenario?

I may be misunderstanding but no, I don't see any reason to use isTweening() in that scenario. Here's some very basic pseudo code: 

 

// this replaces your setTimeout() logic. Just use a delayedCall - remember, it's just a tween with an onComplete, so you can pause()/restart() it. 
let hideControlsDelay = gsap.delayedCall(1, hideControls).pause();

function onPointerEnter() {
	hideControlsDelay.pause(); // don't hide controls when the pointer is over them
	gsap.to(controls, {autoAlpha: 1, overwrite: true}); // animate controls in
}

function onPointerLeave() {
	hideControlsDelay.restart(true);
}

function hideControls() {
	gsap.to(controls, {autoAlpha: 0, overwrite: true}); // animate controls out
}

hitArea.addEventListener('mouseenter', onPointerEnter);
hitArea.addEventListener('mouseleave', onPointerLeave);

I guess I don't really understand why isTweening() would be helpful. Maybe I'm missing something. 

 

Anyway, does that help? 

  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites

I guess I need to spend more time getting to know gsap api better. I would have naturally gravitated toward the isTweening but your psuedo code is defiantly cleaner than what I was imagining doing with isTweening. Thanks for the lesson!

And yes it does help. Allot.

  • Like 1

Share this post


Link to post
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.

×