Jump to content
Search Community

Horizontal Scroll with Draggable Bounds

James135 test
Moderator Tag

Go to solution Solved by GreenSock,

Recommended Posts

Hi, I did some research on this forum about GSAP's Draggable and horizontal scrolling, and I keep seeing this Pen (see below) brought up every time, but nobody seems to ask the obvious question about dragging past the end bound and how the view snaps up when you try to return to the draggable area. To recreate the behavior, try to drag past the end or before the beginning of the scrollable container.

 

I wondered, what is the professional way to resolve this? Maybe with Bounds?

 

So I tried it with the following bounds in my draggable instance declaration:

let scroll_container = document.querySelector(".scroll_container");
let scroll_container_width = <number>scroll_container.offsetWidth;
...
Draggable.create(".proxy", {
  ...
  inertia: true,
  bounds: {
    maxX: 0,
    minX: -(scroll_container_width - window.innerWidth),
  },

Outcome: the draggable sometimes goes before the start, but sometimes allows itself to go 1px past the end.

 

I looked more, found the following properties that I thought would help: 

edgeResistance: 1,
overshootTolerance: 0,

 

They didn't help much, it rarely ever goes 1px before the scroll start, but it sometimes goes 1px past the end. When it does, I hit refresh, and most of the time it stops itself at the end and it respects the bounds. I even ran a little survey just now, and I tried reloading and dragging past the end, it worked as expected until the 4th reload then it went 1px past the end, so annoying.

 

A temporary fix is below it never scrolls past the edge, but it's sloppy. 

let scroll_container = document.querySelector(".scroll_container");
let scroll_container_width = <number>scroll_container.offsetWidth;
...
Draggable.create(".proxy", {
  ...
  inertia: true,
  bounds: {
    maxX: 0,
    minX: -(scroll_container_width - window.innerWidth - 1),
  },

 

Why is this not addressed in the example Pen (below) that is always referenced? How can this be resolved?

 

Update 1: Problem is related to GSAP's ability to decide when the scroll progress reaches 100%, sometimes it decides it's 1px bigger than the container bounds. It's not related to DOM rendering either, you can create the draggable instance 10 seconds after the DOM renders, problem may or may not appear. It's a moody bug! Furthermore, @OSUblake tried to tackle this, and it didn't seem to be fruitful. 

 

Update 2: In my tests, I was able to find that the scroll value where the scroll progress is 100% is not calculated once with this draggable Pen, it's dynamically calculated and it's related to the inertia and how hard you drag it. If you drag it slow enough, it'll respect your boundary, if you drag it fast, it might go past it by 1, you can try it 100 times and each time it'll calculate a new value for scroll progress 100%. I'll fork a pen if I have the time. 

 

The solution I think would be most stable: when the scroll instance reaches let's say 1px from the end edge, stop the inertia completely and replace it with a scrollTo to the end edge.

 

I'll update as I go along, the problem is that it keeps changing all the time, it's hard to reproduce and isolate the problem..

See the Pen ZELQqeJ by GreenSock (@GreenSock) on CodePen

Link to comment
Share on other sites

It's really interesting how you clamped it, and you're getting closer to the actual and full fix for this problem.

 

Because my sloppy clamping method was this, but it was not stable, it would keep changing every 3rd or 4th time I hit refresh.

13 hours ago, James135 said:
let scroll_container = document.querySelector(".scroll_container");
let scroll_container_width = <number>scroll_container.offsetWidth;
...
Draggable.create(".proxy", {
  ...
  inertia: true,
  bounds: {
    maxX: 0,
    minX: -(scroll_container_width - window.innerWidth - 1),
  },

 

I'll try to combine your clamping method with this:

13 hours ago, James135 said:

The solution I think would be most stable: when the scroll instance reaches let's say 1px from the end edge, stop the inertia completely and replace it with a scrollTo to the end edge.

 

As soon as it hits horizontalScroll.end - 1, I'll tell it to scrollTo to the actual end to not have the ugly 1px on the left, hope it works, but it may not.

Link to comment
Share on other sites

Anyways so I was able to stitch together a function to bring it to 0 when it reaches the scroll position of 1, and another to bring it to the actual end of the container when it reaches end-1px.

 

The game changer was Greensock's solution which created stability between refresh/renders. It'll always stop 1px after the start and 1px before the end

 

Hope this helps 

  • Like 2
Link to comment
Share on other sites

  • 3 weeks later...
On 7/27/2022 at 9:09 PM, GreenSock said:

I have updated the demo to just clamp the scroll so it doesn't hit the very start or end (1px) and trigger unpinning/pinning. 

 

 

 

Does that help?

Had to modify line 25 (see below) to make it deploy without it telling me that "clamp is not a function at Draggable", I'm guessing it just needed a refresh to trigger the refresh event listener

 

if (clamp !== undefined) {
  horizontal_scroll.scroll(clamp(this.startScroll - (this.x - this.startX) * dragRatio));
} else {
  ScrollTrigger.refresh();
}

Really annoying bug

image.png

Link to comment
Share on other sites

Yeah, that must be something specific to the way you've got your app setup. My guess is that your code is executed after the "load" event fires on the window. I wouldn't put that check in the onDrag - I'd put it in the onPress for slightly better performance: 

onPress() {
  clamp || ScrollTrigger.refresh();
  ...
}

 

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