Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

One-direction tweens #141

Closed
outring opened this issue Aug 11, 2014 · 17 comments
Closed

One-direction tweens #141

outring opened this issue Aug 11, 2014 · 17 comments

Comments

@outring
Copy link

outring commented Aug 11, 2014

Now it's very hard to create different tweens for different scroll directions (forward/backward). It could very useful, when you want to use, for example, different easings for different directions. Now there is two options:

  1. Update tween of scene after scene finished or before it's start. To be honest, I had no success with that option, I had tried all events (enter, leave, start, end) with tween changes using TweenMax.updateTo and ScrollScene.setTween. It looks very complex, unfriendly and hacky.

  2. Play forward/backward tweens manually on ScrollScene enter event

    new ScrollScene({
        triggerElement: this._$appSlide,
        triggerHook: "onLeave",
        duration: 0,
        offset: 200
    })
        .on("enter", function (e) {
            if (e.scrollDirection === "FORWARD") {
                reverseTween.stop();
                forwardTween.play(0);
            }
            else {
                forwardTween.stop();
                reverseTween.play(0);
            }
        });
    

    Second one works great, but it doesn't respect ScrollScene.destroy(). It could be handled with destroy event, but it's not the perfect solution, I think. It doesn't mean, that destroy event not needed, it's presence seems quite logical to me, according to demos, where some external work done inside event handlers.
    Perfect solution, I think, is to add scrollDirection option to scene, which works only with tweens and have three values: both (default), forward and backward.

@janpaepke
Copy link
Owner

Hi and thanks for your input.
I actually also thought of a similar feature, as outlined here: https://github.com/janpaepke/ScrollMagic/blob/master/js/jquery.scrollmagic.js#L24

So far I haven't done it, because I wasn't really sure how I want to implement it.
I think it's a good thing that there can only be one tween attached to a scene.

Your approach would enforce that, while also enabling users to add a separate scene, for the reverse animation.

I really like it and I will think about it some more and then implement it in the next release.

The question is though, if that makes the "reverse" option obsolete...

regards,
J

@janpaepke
Copy link
Owner

One thing though: in your solution you also ´.stop()´ the respective tween for the other scroll direction.
If we would really implement something like your "scrollDirection" option this would mean that the respective tweens wouldn't know about each other.
So if the starting of one required the stopping of the other it would still need to be done using custom events. (Like the scene's event or the onStart callback of the scene).

Also it would raise the question of what is start and what is end for the scene. Would the duration for a "backward" scene be counted upwards? I guess it must be...
This would also mean the start event is at the bottom and the end is at the top.

@outring
Copy link
Author

outring commented Aug 11, 2014

  1. Yep, I had kept single-tween-per-scene limitation in mind, when thought about that
  2. Yes it definitely makes reverse option obsolete, but provides new way to implement non-reversable tweens.
  3. I've used .stop() because of some strange behavior I don't remember :) I'll dig into it to find out if it's really needed.
  4. Questions about duration and events are interesting. I think, that timing should be inverted, but events left intact, because we already have scrollDirection in the event object which allows to handle all types of scenes uniformly, without knowledge about theirs direction. If there is no conflict in some internal logic, of course.

@outring
Copy link
Author

outring commented Aug 11, 2014

3 Okay, I found the problem. In my case, when animation is scroll-independent, it's important to stop previous animation or to wait until it runs to the end. Otherwise both tweens will animate the same object properties of the same object and will fail. It means, that such animations should not animate the same properties of the same objects simultaneously if scene is scroll-dependent or previous animation should be stopped before current if scroll-independent using events and explicit tween variable declaration. Sounds bad. What about destroy event? :D

@janpaepke
Copy link
Owner

I'm just thinking about how this would affect pins...
how would they behave if our option was set to backward.
If it behaves like an inversion of the reverse option it would mean that it would only have any visible effect, if the pin has been played forward at least once. Otherwise it would be already at is starting position, when scrolling up.

Unless of course we invert the duration logic for reverse scenes.
I thought to agree with your 4. but then I thought about tweens linked to the duration.
Would their progress be 100% at the end of the scene or 0%, which would be inverted behaviour.

Then there's the issue you mentioned, that there may be conflicting tweens.

there's still tons of stuff to think about.

Could you provide a real life example of where this feature is actually useful? Like your above code in a jsfiddle?

@outring
Copy link
Author

outring commented Aug 11, 2014

Or what if we'll use two tweens in one scene somehow like that:

new ScrollScene().setTween({ forward: forwardTween, backward: backwardTween })

So we would be able to stop corresponding tweens when needed. But partially it breaks one-tween-one-scene rule. Partially means, that scene will contain two tweens, but in one moment would be active only one.

@janpaepke
Copy link
Owner

Well that was my original thought when I wrote that TODO note.
But I still don't think this is a good idea.
Especially since you don't know that a tween should be stopped. This is user logic...

@outring
Copy link
Author

outring commented Aug 11, 2014

Yep. destroy event still looks the best solution now :D
I'll provide an example tomorrow. But the main reason of all these hacks for me is Elastic easing - it looks ugly, when reversed :)

@outring
Copy link
Author

outring commented Aug 12, 2014

Here it is: http://jsfiddle.net/outring/9z49rLb9/5/

@janpaepke
Copy link
Owner

awesome, very good demo, thanks!
I'll look into the unit tests (other issue) and this will be the next feature I will tackle. :)

@janpaepke
Copy link
Owner

Hi!
So I thought a little more about it and still think including a seperate reverse tween into scrollmagic is problematic.
The reason is that it should work with the same logic both for autoplay tweens and scroll-bound tweens. Now imagine a tween that should have different easing methods depending on scroll direction.
Now what happens if I change the scroll direction during the tween?
The position of the tweened element would be different at the same point in time, depending on the easing method.
But I also experimented a little more to find an easy solution to have different easing for autoplay animations: http://jsfiddle.net/xd2dkode/3/
What do you think?

@outring
Copy link
Author

outring commented Aug 19, 2014

Hi
Yes, I see problems in implementation logic.
Your solution looks good, but it lacks direction semantic. I had tried to do something similar, but had subscribed to ScrollScene events instead of TweenMax. With no luck, unfortunately :D
I see no solution without magic .progress(1), .stop() and .play(0) now :(

@janpaepke
Copy link
Owner

Yes, I know what you mean.
When I thought of it I was thinking only to use "updateTo".
But for some reason it also resets the progress to 0.
I'll talk to Jack (from Greensock) about it. But first I'll address this other nasty bug, which causes tweens to be skipped.
I'll let you know as soon as I know more.

@janpaepke
Copy link
Owner

Hi!
So I'd like to update you on what I have decided.
I have decided NOT to implement reverse-only tweens as a feature.
The reasoning behind it is this:

  • Regardless which solution one would use (adding two tweens to a scene, creating a 'direction' option) one problem would always be an issue: Once a tween was played it would never be reset to its starting position. The only way to do that would be to reset the progress, which is why you needed to call tween.stop(). in your workaround. This however is not really nice, as it always causes the tween to start from the beginning and if the user changes the scroll direction multiple times while the tween is running, this would look very jerky.
  • When opting for the 'direction' option this would mean there would also be pins that only work when scrolling upwards. This would mean, that they start at the bottom and then only pin, when the user scrolls up. This would mean a lot of changes to the pin routine and I really can't imagine any use case where this would even be practical or desired, since pages always start at the top.
    So even if you have a setup where right on page load you jump to the end and then only scroll up a regular pin would work perfectly, because when the scroll jump is initiated the pin position would automatically be at the very end.

So much for my reasoning.

Don't be disappointed though! There is a silver lining:
In the upcoming ScrollMagic release I changed the trigger event logic of zero duration scenes.

Before, when a zero duration scene was triggered it viewed the end to be the same as the start.
So the events were triggered at the same time in this order:
enter, start, progress, end, leave when scrolling down
and
enter, end, progress, start, leave when scrolling back up

While this does make sense for scenes with duration (where the closing events would be at a later point in time and not at the same time) I figured this is kind of unexpected for zero duration scenes.

So in the upcoming release zero duration scenes will be regarded as "open end" and the trigger events will be fired like this:
enter, start, progress when scrolling down
and
progress, start, leave when scrolling back up

This makes it both easier to attach actions to the respective event and also more intuitive as to when it is triggered.

So as a special treat for you I prepared a solution for the multi direction conundrum using the alpha version of the upcoming release here:
http://jsfiddle.net/xd2dkode/5/

It is the best solution yet, because it will always bounce out, even if you scroll quickly forward and backward over the scene trigger. Plus due to the new event logic it's also quite intuitive to use.

I hope this helps you.

best regards,
J

P.S.: In the future I plan to make a tutorial about this...
P.P.S: I hope to release ScrollMagic 1.1.0 within the next 2 weeks.

@PizzaBrandon
Copy link

I'm currently working on a site design that starts the visitor at the bottom and requires they scroll up. I forked the code and added a new option to ScrollScene called invert that lets the start be below the end and, coupled with the reverse option, allows for tweens that run only when scrolled up. It also appropriately describes the direction of the tween so you don't have to write them backwards to make this work.

I haven't yet tested how this works with pins since it's not in my use case, but I'd be willing to work on it and submit a pull request. The code to implement invert is very straight-forward and allows for this use case with very little effort and keeps it opt-in for the consumer.

@outring
Copy link
Author

outring commented Aug 28, 2014

@janpaepke it looks great! Thank you! But the last thing: what do you think about destroy event, to reset these animations on controller/scene destroy.

@janpaepke
Copy link
Owner

@PizzaBrandon Thank you for your help and thanks a lot for the contribution offer!
I actually also thought about adding an invert option and dismissed it but actually this issue is about something different:
The desire was to have tweens that only run when scrolling up. While you are correct that this behavior can be achieved with having an invert option and reverse disabled this means by definition that it will only happen the first time the user scrolls up. And this is exactly what I described (granted not very clearly) in the first bullet point of my last post: "Once a tween was played it would never be reset to its starting position."
So even with an invert option you would not be able to achieve something like this.

Furthermore: Apart from your (programmatically undoubtedly the most elegant) solution users can also achieve the same effect with the current version of ScrollMagic by either adding the tweens in reverse (tweening from 200 to 0 instead of 0 to 200) or by using the progress event and then updating the tween progress to 1-e.progress.
I'm not sure but it might even work to define a tween as reversed using tween.progress(1).reversed(true) and then adding it to a new timeline and then add that timeline to the ScrollScene.

That being said I think that scrolling from bottom to top is a VERY rare usecase at best and I decided NOT to add this feature to ScrollMagic, as it would cause more confusion and code bloating than it benefits users.

@outring I see your point. I guess it does make sense to be able to reset positions when a scene is destroyed. Okay - I will add a destroy event for scenes. Doesn't really make sense for controllers though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants