Jump to content
GreenSock

darkgr33n

Scroll Trigger - utils.onArray - changing the order of sections

Go to solution Solved by akapowl,

Recommended Posts

Hey all,

 

I'm stuck on an issue and just can't for the life of me work out what's going on.

 

I've created a cut-down version of one of my pages to illustrate.

 

So, I have about 10 pages. Each page can have a number of  'components'.

Each of these components have a variation on a basic wipe animation.

 

I have one js file, which I'm including in each page, and the basic idea is: we look at the page and see which, if any, of the components we have, and then set up the page accordingly.

 

I'm using gsap.utils.onArray to look through the page and see if there is one or more named components:

 

gsap.utils.toArray(".cmpnt--page-split").forEach(function(ps__section) {

 

 

The two components shown in the codepen demo i've called 'page split' and 'image coverup'.

 

As it currently stands, it works fine. I even celebrated with a cup of tea.

 

However, one of my pages needs to have these components in a different order. so I swapped the order in the HTML and the thing went bonkers 😕

 

If you look at the codepen that works, in the HTML there are three components, the first of which is commented out for demo purposes ;) 

 

<!-- # IMAGE COVERUP COMPONENT -->

<!-- PAGE SPLIT COMPONENT -->

<!-- IMAGE COVERUP COMPONENT -->

 

however, if you uncomment the first IMAGE COVERUP  and comment-out the last one, when you run it again all hell breaks loose when it tries to deal with the PAGE SPLIT component.

 

I'm not sure if its the way I'm using gsap.utils.toArray because if the order of the components in HTML matches the order in of the utilsonArray in the JS, it works, otherwise ... it don't. And I can't work out how its breaking.

 

I think I'm missing something really obvious, but am at a loss at the moment. 

 

Any idea what I'm doing wrong ?

 

Cheers

 

 

 

 

See the Pen NWRWQPv by darkgr33n (@darkgr33n) on CodePen

Link to comment
Share on other sites

Hey @darkgr33n

 

Since in that described setting, the ScrollTriggers would possibly (and in your demo scenario that is the case) not be created in the order they appear on the page anymore, the pinning (more exactly the pinSpacing) of that trouble-making image-reveal section couldn't be considered by ScrollTrigger when setting up, because the pin is in order of creation yet to be applied. Thus other ScrollTriggers below that would be in the wrong places.

 

I don't think what you are trying to do is wrong per se, but definitely not the most common thing to do.

There is a solution to scenarios like this, by setting a refreshpriority.

 

So you'd have to make some sort of function that checks against the position of the sections and applies the correct refreshPriority for each ScrollTrigger independently - if that is possible - it should/could be 🤔 But I can not tell you more on that, except give you this from the docs:

 

refreshPriority number - it's VERY unlikely that you'd need to define a refreshPriority as long as you create your ScrollTriggers in the order they'd happen on the page (top-to-bottom or left-to-right)...which we strongly recommend doing. Otherwise, use refreshPriority to influence the order in which ScrollTriggers get refreshed to ensure that the pinning distance gets added to the start/end values of subsequent ScrollTriggers further down the page (that's why order matters). See the sort() method for details. A ScrollTrigger with refreshPriority: 1 will get refreshed earlier than one with refreshPriority: 0 (the default). You're welcome to use negative numbers too, and you can assign the same number to multiple ScrollTriggers.

 

 

 

...and a basic demo for your scenario:

 

See the Pen 6e6c549ee256b8df236d8072188a6dfe by akapowl (@akapowl) on CodePen

  • Like 3
Link to comment
Share on other sites

@akapowl

 

Thanks for that, I must admit I hadn't looked for a solution within the docs, I just assumed I was doing something really stupid.

I would have thought what I was doing - creating reusable functions - would have been reasonably standard, but perhaps the "in any order on the page" is the uncommon thing here - but I'm glad I'm not a million miles away with my approach!

 

I'll give what you suggested a go and report back. I could see it was something to do with the pin-spacing but couldn't quite work out where it was going wrong.

 

Thanks again for your time

 

 

  • Like 1
Link to comment
Share on other sites

thinking out loud, as I won't know what order the components might be in, I can't set the refreshPriority beforehand, so I'll need to create something to look through the page and grab all possible components and then set the refreshPrioirty of each scrollTrigger according to the order so I think will need to look at the scrollTrigger.sort method. I think there are three or maybe four different components that I need to build, and sometimes one component may appear more than once. 

Link to comment
Share on other sites

ok, I think I've managed to make it work, although I'm not sure on its efficiency.

 

See the Pen ExgamYj by darkgr33n (@darkgr33n) on CodePen

 

I first looked at traversing the page via the parent section tags, building an array of each instance of the classnames I needed and then I was going to step through the array and do something :

 

var cmpnt__list = [];
// LOOP THROUGH EACH SECTION ELEMENT.
$('section').each(function () {
	if (this.querySelector('.cmpnt--page-split') !== null) {
		cmpnt__list.push("cmpnt--page--split");
	}
	if (this.querySelector('.cmpnt--image-coverup') !== null) {
   		cmpnt__list.push("cmpnt--image-coverup");
    }
});

 

....but it just seemed overcomplicated and I wasn't really sure what to do with the array after i'd got it.

 

In the end, rather than using my two gsap.utils.toArray , one for each component, I used the toArray on the parent <section> tags, and then look to see if they contain any of the classnames i'm looking for, and if it does, i create the scroll trigger right there, so it's always in the correct order. 

 

I'm sure i can optimise a little more but, for now, it seems to be working :) 

Many thanks for your help

 

Cheers!

  • Like 2
Link to comment
Share on other sites

 

Looping over the sections like that and applying the ScrollTriggers accordingly, totally makes sense now that you mention it.

 

I am by no means an expert on how to write efficient code, but I'm glad to hear you got it working to your liking.

 

And thanks for sharing your results.

 

  • Like 3
Link to comment
Share on other sites

I spoke a little too soon!

 

I think it needs a little tweak; because i was using random stock images I didn't pick up on it 😕

 

See the Pen ExgamYj by darkgr33n (@darkgr33n) on CodePen

 

In demo, the first instance of both of the two components works fine;

however, in both of the second instances of the components, the second image - which should scroll from the bottom over the top of the first image - is initially in view until the first image is pinned, and then it works as expected.

 

Something in the first instance of each component is adding something extra to the second instance, i'm not sure if its the pin-spacing or if it's a result of the some kind of timeline issue. I've just re-read the most common mistakes, and can't see anything obvious - but i'm almost sure it is. Like, setting the timeline to from(yPercent:100) is actually doubling on the second instance of the components.

 

Just in case anyone has spotted the error, I thought I'd reach out while I continue the struggle ;)

 

Cheers!

 

 

Link to comment
Share on other sites

yeah it does seem that when the first component is translating the first image, it is also effecting the second instance of the component -- at the point when the first instance of the component should unpins, it then moves the second components second image up before the scroll actually continues 


I'm looping through each <section> tag and then selecting the image using section., so i assumed it would be specific to the element within it's parent, but i've obviously missed something ...

 

// LOOP through the <section> tags
gsap.utils.toArray("section").forEach(function(section) {
	
	if (section.querySelector('.cmpnt--image-coverup') !== null) {
		// the <section> contains an element with the class cmpnt--image-coverup so set up the images
        imageTwo = section.querySelector(".ic__image--two");
      ---rest of code---
    }
});

 

Link to comment
Share on other sites

  • Solution

Hey @darkgr33n

 

Those problems you encounter are related to

 

1) not storing (is it the right word to use here?) your timelines in variables

2) setting your variables without var / const / let beforehand, thus they are set to global scope and are eventually being overwritten

 

Changing that accordingly results in where you wanted this to go.

 

See the Pen 0395b571f86229f4e22bd027648e49e5 by akapowl (@akapowl) on CodePen

 

 

Is that better?

 

 

P.S.:

Don't mind me changing your .from()-tweens to fromTo()-tweens - plus adding classes to your sections and checking for those classes on the sections. Those were shots in the dark, before I discovered the variable thing.

 

Addition:

Just to make sure, here's a pen, with the changes restricted to the variable handling mentioned above, only.

 

See the Pen e474a4826c24b99836a92389be4b4c68 by akapowl (@akapowl) on CodePen

 

  • Like 4
Link to comment
Share on other sites

Hey @akapowl

 

Many thanks for your help once again!!

 

That's brilliant; I hadn't yet thought that far ;) I've tinkered with JS for about 15 years but never really mastered it. 

I'll make those changes in the morning and report back when its fixed

 

Thanks for your time looking at this, much appreciated.

 

Cheers!

  • Like 2
Link to comment
Share on other sites

 

I wouldn't exactly call it brilliant, but thanks 😅

Brilliant is what we get given at hand with GSAP and ScrollTrigger (all the other good stuff not to mention).

 

But knowing some concepts regarding JS is key when things get a bit more complex.

I myself got to finally wrap my head around quite a bit, when working with ScrollTrigger.

 

  • Like 2
Link to comment
Share on other sites

13 hours ago, akapowl said:

 

 

Addition:

Just to make sure, here's a pen, with the changes restricted to the variable handling mentioned above, only.

 

 

Thanks for the additional confirmation as well!!

All appears to work fine now, many many thanks. Would you believe I had it like that to begin with, but as part of my attempts to fix the original issue, I had moved all the variable inits outside of the function 😕

I'd definitely call it brilliant and I'm sticking to that! I would still be struggling now without your help -- and I'm also learning a lot more working with scroll trigger, but more importantly, the community. Who knows, one day I may be able to help out someone too, that would good.

 

Cheers! 

  • Like 1
Link to comment
Share on other sites

1 hour ago, darkgr33n said:

Who knows, one day I may be able to help out someone too, that would good.

We'd love to see it! Some questions are easier to answer than others. Feel free to give answering a shot :) 

  • Like 1
Link to comment
Share on other sites

I have looked at a few questions over the last couple of weeks, but haven't been able to answer any yet, but will continue to look as it's also really great learning ;)

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