Skip to content

Commit

Permalink
fix(): Scroll position precision to be based on client/scroll diff
Browse files Browse the repository at this point in the history
  • Loading branch information
ykadosh committed Aug 1, 2021
1 parent f7613d1 commit 5aa271a
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 2 deletions.
5 changes: 3 additions & 2 deletions src/components/Scrollable/Scrollable.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import React from 'react';
import classNames from 'classnames';
import {copyComponentRef, findChildByType} from 'utility/react';
import {isEqual} from 'utility/object';
import {normalizeScrollPosition} from './Scrollable.utils';
import ResizeObserver from 'tools/ResizeObserver';
import {VerticalScrollbarPlaceholder, HorizontalScrollbarPlaceholder, VerticalScrollbar, HorizontalScrollbar} from './components';
import Context from './Scrollable.context';
Expand Down Expand Up @@ -93,8 +94,8 @@ export default class Scrollable extends React.PureComponent {
const scrollLeft = Math.ceil(sl);

return {
top: Math.min(1, scrollTop / Math.max(1, scrollHeight - clientHeight)),
left: Math.min(1, scrollLeft / Math.max(1, scrollWidth - clientWidth)),
top: normalizeScrollPosition(scrollHeight, clientHeight, scrollTop),
left: normalizeScrollPosition(scrollWidth, clientWidth, scrollLeft),
scrollTop,
scrollLeft,
scrollHeight,
Expand Down
12 changes: 12 additions & 0 deletions src/components/Scrollable/Scrollable.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react';
import {mount} from 'enzyme';
import sinon from 'sinon';
import Scrollable from './Scrollable';
import {normalizeScrollPosition} from './Scrollable.utils';
import {SCROLLING_CLASS_REMOVAL_DELAY} from './Scrollable.constants';

const waitFor = delay => new Promise(resolve => setTimeout(resolve, delay));
Expand Down Expand Up @@ -124,4 +125,15 @@ describe('<Scrollable/>', () => {
expect(s.updateScrollbars.callCount).toEqual(2);
});
});

describe('Utils', () => {
it('normalizeScrollPosition()', () => {
expect(normalizeScrollPosition(100, 100, 0)).toEqual(0);
expect(normalizeScrollPosition(101, 100, 0.5)).toEqual(0.5);
expect(normalizeScrollPosition(200, 100, 0)).toEqual(0);
expect(normalizeScrollPosition(200, 100, 50)).toEqual(0.5);
expect(normalizeScrollPosition(200, 100, 33)).toEqual(0.33);
expect(normalizeScrollPosition(2000, 1000, 333)).toEqual(0.333);
});
});
});
36 changes: 36 additions & 0 deletions src/components/Scrollable/Scrollable.utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* Copyright (c) 2020, Amdocs Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {decimals} from 'utility/number';

/**
* This function normalizes the scroll position to a number between 0 and 1.
* The precision of the returned value is relative to the difference between the scrollLength
* and the clientLength.
*
* @param scrollLength
* @param clientLength
* @param scrollOffset
* @returns {number}
*/
export const normalizeScrollPosition = (scrollLength, clientLength, scrollOffset) => {
const diff = Math.max(1, scrollLength - clientLength); // Enforce a min value of 1 to avoid division by 0
const normalized = Math.min(1, scrollOffset / diff); // Avoid a ratio greater than 1
// The returned value number of decimals is based on the number of digits in 'diff'.
// For example, if normalized = 0.123456 and diff = 100, then the returned
// value will be 0.123 (since diff has 3 digits). This is done to avoid have over precised
// numbers, which may cause the scrollbars to be glitchy.
return decimals(normalized, Math.floor(Math.log10(diff)) + 1);
}

0 comments on commit 5aa271a

Please sign in to comment.