Skip to content

Inertia fix #238

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

Merged
merged 6 commits into from
Apr 8, 2020
Merged

Inertia fix #238

merged 6 commits into from
Apr 8, 2020

Conversation

dhilt
Copy link
Member

@dhilt dhilt commented Mar 28, 2020

Relates to issue #205.

The problem

The update of the scroll position made programmatically can be overridden by the inertia scrolling process, which is handled by the browser internally.

Depends on inertia implementation (Device + OS + Browser).

Irregular, can't be 100%-reproduced.

Details

We have two processes: inertia scrolling (A) and manual scroll position update (B). They may conflict if B happen during A:

Good Bad
100, A 100, A
92, A 92, A
88, A 88, A
84, A 84, A
200, B 200, B
197, A 81, A
195, A 79, A
194, A 78, A

During A process Browser calculates the layout iteratively. Next state is based on previous one. B happens between two phases of A. The result depends on A implementation. A developer don't have access to A implementation. Nut sure about specification, but speaking of timing, this is a kind of black box. So A can override B and continue its next phase based on previous A phase, not on B. See Bad scenario.

Solution

The phases of the inertia scrolling process correlate with Browser repaint cycles. To provide right timing, which will not depend on the environment, the code dedicated to update the scroll position can be invoked with the requestAnimationFrame method.

So, basically the fix could be just

 requestAnimationFrame(() => viewport.scrollTop(newPosition));

This produces an additional asynchronicity, so I decided to provide some optimization and not postpone scrollTop change in case it is not necessary. For this purpose I store the value I want to be a new scroll position:

  viewport.synthetic = { position: newPosition };
  viewport.scrollTop(newPosition);

and then I re-adjust scroll position on the scroll event handler if current (handled) scroll position is not equal to expected one, which can happen if the inertia process is running:

  if (viewport.synthetic && viewport.scrollTop() !== viewport.synthetic.position) {
    requestAnimationFrame(() => {
      viewport.scrollTop(position);
      viewport.synthetic = null;
    });
  }

This produces an asynchronicity, but only in case the inertia does really break the synthetic scrollTop update.

Addition

New attribute had been added: handle-inertia. It is responsible for enabling/disabling inertia processing. The default value is "true". To disable inertia scroll processing the value should be set to "false":

<div ui-scroll="item in datasource" handle-inertia="false">

This attribute is not going to be documented.

@dhilt dhilt merged commit a957d07 into master Apr 8, 2020
This was referenced Apr 8, 2020
@dhilt dhilt deleted the inertia-fix branch October 2, 2020 15:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant