-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
when scroll with high speed miss tweens #145
Comments
Hi George, My suspicion is that it is the same problem as in these issues: #92 and #97 But as of yet I do not have any proper environment to reproduce and debug it. |
Hi Janpaepke, ok i will try to make a jsfiddle with all the code except my custom plugins. You can reproduce the error when click on the lowest section of the right navigation and when the scrolling is done click on the topest section of the navigation. You will see that thte sections are overlaping so some of the tweens which has opacity:0 was not triggered. If you extend the time to scrolling from the navigation to 10 sek it has normalize but sometime it has a issues with the same thing which i have writed above. |
Hi Janpaepke, here is one fiddle for experiment with : http://jsfiddle.net/GeorgeGeorgiev/56owtpf8/ It is not perfekt but you will see that it remakes the issue if you scroll down fast from the right menu and again scroll up with the right menu for 1 sek it overlaps some of the texts. |
Here is close copy: |
You can put onupdate on the scrollto event console.log to see how munch steps does it make. |
Ahh sorry for such a spamm but i want to make your job easier. Here is the full window view: http://jsfiddle.net/GeorgeGeorgiev/56owtpf8/2/embedded/result/ |
You are right the 92 and 97 are the same things i have search trough one of the sites and it makes the same thing http://kingofthehill.esfxtv.com/ . So the easiest way to reproduce the bug is enter on the site wait all the js to load and click on the end button then click on the home button you will see how the elements are missed the tween to hide them. See the same on my site. Click End button and then home. This is not from the other scripts. |
So I did some research on the matter.
So here's the problem: because all scene's get triggered at once, all tweens are started at the same time. It's really difficult to tell which has precedence over the other. The reason is that Scenes can be added in random order and their starting position can change at any time. I experimented with the As for the imminent problem I have found a solution that only works when the scene has a duration: At the moment I am at a loss as to how to address this issue.
Any notes and suggestions are highly appreciated. |
Hi jan. I have worked a lot with these too and make the same things. The overwrite property can make a difference but only in the one way :) So if you scroll back somewhere will be broke again. So for now the best way to work around is to have multiple DOM objects on one object :) To say the DOM structure of the elements is div#1>div#2 and you call first on the div#1 opacity:1 then you call on the div#2 the opacity:2. It this work around we can make a bypass for now. So see the result : http://ag.sitetester.biz/indexin.html Also i have tryed to kill the tweens great mistake ... It kills them and never fire again :) |
Well what I meant in #134 was to kill all and then fire only one tween (the appropriate one) whenever a scene is triggered. Your suggestion to use different objects does work, but of course is rather dirty and only works with opacity tweens. There has to be a better, more universal solution. I made a new version of the fiddle, that always checks for the tween with the highest precedence
I think the best solution would be this:
This however does currently not work as expected with GSAP. I have created another example that again doesn't use ScrollMagic, but just mimics the way the tweens would be called by ScrollMagic. So I guess this is as far as I can take this – I'll need some input from the GSAP folks now. |
From what I can tell, this is all expected behavior, but I can see why some if it appears odd or cryptic. Let me explain... Summary of how "auto" overwriting works: Why were there weird progress values?
So as expected, the progress of Tween 4 made it all the way to 1, whereas the progress of the first 3 tweens got halted after their first render. In what order will tweens render? How can I prevent overwriting? TweenLite.defaultOverwrite = false; Just remember, overwrite management is a unique feature of GSAP that is intended to help you and in most situations, it prevents unintended behavior by protecting you from conflicts that you created in your code. However, in this situation, since ScrollMagic wants/needs total control over everything and intends to take responsibility for managing things properly, it's fine to disable the built-in overwrite:"auto" behavior. You can also prevent an individual tween from overwriting others by setting overwrite:false in its vars/config object. Also, paused tweens are immune from overwriting, so you can use that as a management tool if you want. In other words, if you've got 4 tweens of the same object's properties, you can pause() them all and just play() the one you want. Why didn't all the tweens reverse() the way I expected? Why did things render a little differently each time I reloaded? If the next time you reload, the browser happens to execute that tick faster, at 18ms, you'd see those values change accordingly. Again, that's exactly what GSAP should be doing. Summary Does that answer your questions adequately? |
Hi Jack, thanks a lot for your very detailed and enlightening input. It also dawned on me that there was also a bit of a terminology misunderstanding as to what "overwrite" actually means. So from now on I will distinguish between When multiple tweens are called on the same object have conflicting properties I was expecting the tween that was called last to be rendered (for that particular property) and all previous to be ignored. This is because when they are called later one by one in reverse or forward they should still work as expected. I also can't pause() tweens I want to be ignored, because it may be the case that they contain animations for other properties, that should still have effect. So disabling overwrite does seem like the right way to go... But it raises the following questions:
In Summary: As of now the answer to the question "How can I tween the same property in multiple scenes?" is "Disable overwrite, use
|
Let me preface all of this by saying that the overwhelming priority for the architectural decisions was performance. I'll get into the nitty gritty later... 1) Is there a performance drawback from the conflicting properties and will the last called tween always have precedence? As far as doing "soft" vs. "hard" overwrites, that's another cost consideration. The current behavior is very fast - it runs the logic once at the start, kills any conflicting properties, and lets the tween rip through its renders. But to do a "soft" overwrite, we'd have to implement new logic that would retain the data for the conflicts, suspend them for only the current rendering cycle and then...when would it re-enable them? When they go all the way back to 0? When they reverse? When they play after having been paused? Any of these options imposes a file size and performance cost across ALL tweens. We can't just re-enable the conflicting properties after the other [conflicting] tween finishes because that'd lead to odd behavior, like imagine if a rollover tween is 2 seconds and animates the scale up to 2, and then a rollout tween animates scale back to 1 over the course of 1 second (shorter) - if the user rolls over and then off quickly, you'd see the scale return to 1 (correctly) and then suddenly jump to a larger value and end at 2 (probably not at all what the developer intended). As far as which one renders first/last, things on the root timeline render in the order they were created. The only exception is if a tween ends (or is killed) and then you re-enable it, like by calling play(0) or restart() in which case it gets added to the end of the rendering queue at that point. When playing all tweens you still see the box jump a bit. You touched the reason for this in your previous post. If I understand correctly it is because the previous tween is already in render phase, when the next one is being processed. Is there now way of checking for conflicting parameters before the tweens enter their render phase? Alternatively, we could retain the previous values on every render, then when a conflict is detected, it would force those values back to their prior state before killing, but that's pretty costly in terms of memory and execution. I don't know the exact number, but let's say it reduces performance by 20% just to accommodate an exceedingly rare edge case that may effect 0.001% of the user base, and it wouldn't even affect the final values, plus there are already ways around that if you run into it (use a fromTo() for example, or set overwrite:true). There isn't a way in the current public API to find and report conflicts, but you can use TweenLite.getTweensOf(yourTarget, true) to get all the active tweens of a particular object at any given time, and you can loop through that list and call tween.kill(target, otherTween.vars) to kill the overlapping properties. If I understand correctly the tweens save their start position the first time they are rendered and stick to it...But what would be much better is to keep the start position flexible, regardless of how often the tween is called. So is there a way to somehow always update the start position to the current position, when hitting play? That being said, you can simply call yourTween.invalidate() to tell a tween (or timeline) to flush its starting values, and then the next time it renders, it'll record the current ones and go from there. It sounds like that's what you're looking for. Does that clear things up? |
Hi Jack, thanks again for your detailed answer! 1. performance / precedence I took all this into consideration and implemented a lot of new features into the upcoming release of ScrollMagic. Among other things it updates the scenes in the order of their starting position.
|
It looks like you've done a fantastic job of wrapping your head around the mechanics, and I like your solution 2. The tricky thing here is that you're wanting two different behaviors in various spots - sometimes you're wanting the tweens to honor the current position as a starting point, and sometimes you're wanting to force them to particular values. So yes, I think the smoothest, most intuitive option would be to simply re-create a to() tween based on the context (or simply reuse the same tween, but invalidate() it). If they're scrolling backwards, you tween to the "from" vars. Otherwise you tween to the "to" vars. I haven't had a chance to dig into the source code of ScrollMagic, but for what it's worth, I envisioned the plumbing working like this:
But I haven't attempted to build a whole framework like you did, so perhaps the way I envisioned it has pitfalls that I hadn't thought of. In any case, it sounds like you've got a very good grasp of the dynamics involved here, how overwriting works, and how you can leverage the tools to get what you need. Good job! |
Hi Jack, But putting the whole site in one Timeline has huge drawbacks. If I push the responsibility to the user (namely using a callback-like-design-pattern) it would basically be exactly what is done in solution 2. So I guess the bottom line is: Still I'd love to have a way of at least pointing the user's nose to that by posting a warning to the console. Can you think of any way to scan for conflicting tweens, when one is added to ScrollMagic? regards, |
Are you asking about scanning ahead of time, like before the tweens render for the first time? Overwriting is much trickier than you may think because plugins may do some fancy things and create new properties that don't necessarily exist directly in the vars object. For example, think of a bezier tween that has "autoRotate:true" and you animate an HTML element. It'd end up creating a tween of the CSS "rotation" even though that word doesn't exist anywhere in the tween/vars. The same sort of thing could happen on a physics2D animation, where x and y are controlled and should therefore be overwritten even though there's no "x" or "y" mentioned in the vars at all. So ultimately you cannot truly "search" for overlaps until the tween instantiates and renders for the first time, thus giving plugins a chance to setup whatever they need to setup. Furthermore, it seems like in ScrollMagic, certain tweens may not overlap at all, or they may completely overlap based on how quickly the user scrolls, thus pre-searching for overlaps isn't all that helpful. Or perhaps I misunderstood your question. I am going to look at the feasibility of adding some sort of global callback like "TweenLite.onOverwrite" or something that'd give you the ability to call a function when an overwrite occurs. You could use that to do your console.log(), for example. Would that help? Feel free to suggest a particular API structure. My goal here, however, is to keep things small and fast, so I don't want to add a bunch of fancy bells and whistles, especially because this feature likely wouldn't be used by very many people. One think I'm trying to weigh is whether it makes more sense to do a global onKill() that'd get called anytime any part of a tween is killed (which could be an overwrite or it could be someone calling tween.kill(...), etc.), or if it should only report overwrites. Again, your (and anyone's) input is welcome. |
Yes this was exactly what I was asking for. But I love your idea of a sort of overwrite event. I do understand your urge to keep things simple and light, so this would probably be something that should only be implemented for TweenMax and TimelineMax. What do you think? regards, |
All right, guys, good news. Thanks to everyone involved to get to the bottom of this and special thanks to Jack, for implementing this great new feature. |
when scrolling fast scenes with conflicting tweens would cause problems. With GSAP 1.14.0 this can be detected and a warning is displayed, offering a solution. See here for more info: #145
If anyone is looking for a solution to this in 2020, here's what worked for me:
Essentially it forces previous timelines to their start or end position (depending on scroll direction) when each new trigger point is hit. Crucially it doesn't care about Timeline durations, so it will respond to fast scrolling in either direction. Here's a gist for easy copy/pasting: |
Hi,
when you scroll with high speed like scrollTo with the plugin of tweenMax for 1 sek it miss the tweens...
Here is the example : http://ag.sitetester.biz/indexscm.html . The superscrollarama do the same thing. I don't know why it miss some tweens.
The text was updated successfully, but these errors were encountered: