Skip to content

Commit

Permalink
Fix infinite scroll issue
Browse files Browse the repository at this point in the history
  • Loading branch information
unimonkiez committed Nov 8, 2016
1 parent f5b6b03 commit 0ee96ce
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 43 deletions.
45 changes: 29 additions & 16 deletions src/set-events-for-template-helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,43 @@ export const getIsElementScrollable = el => {
return el.clientHeight !== el.scrollHeight;
};

export const round = num => ((num * 2).toFixed() / 2);

export const scrollElementTo = (el, done, newScrollHeight = 0, scrollDuration = 300) => {
const stepSizeMs = 15;
const scrollHeight = el.scrollTop;
const scrollDiff = scrollHeight - newScrollHeight;
const scrollStep = Math.PI / (scrollDuration / 15);
const maxStep = Math.floor(scrollDuration / stepSizeMs);
const scrollStep = Math.PI / maxStep;
const cosParameter = scrollDiff / 2;
let scrollCount = 0;
let scrollMargin;
const round = num => (((scrollDiff > 0 ? Math.ceil : Math.floor)(num * 2)).toFixed() / 2);
let stepCount = 0;
let scrollMargin = 0;

const step = () => {
setTimeout(() => {
if (el.scrollTop !== newScrollHeight) {
requestAnimationFrame(step);
scrollCount = scrollCount + 1;
scrollMargin = round(cosParameter - cosParameter * Math.cos(scrollCount * scrollStep));
el.scrollTop = scrollHeight - scrollMargin;
} else {
done();
}
}, 15);
stepCount = stepCount + 1;
scrollMargin = round(cosParameter - cosParameter * Math.cos(stepCount * scrollStep));
return stepCount === maxStep;
};
const draw = () => {
el.scrollTop = scrollHeight - scrollMargin;
};

requestAnimationFrame(step);
// `Loop` runs on each call from `requestAnimationFrame`, will run `step` each 16ms id
let timeAccumulator = Date.now();
const loop = () => {
let finished = false;
const now = Date.now();
while (finished === false && (now - timeAccumulator) >= stepSizeMs) {
finished = step();
timeAccumulator += stepSizeMs;
}
draw();
if (finished) {
done();
} else {
requestAnimationFrame(loop);
}
};
requestAnimationFrame(loop);
};

const marginParam = 100 / categoryOrder.length;
Expand Down
42 changes: 15 additions & 27 deletions test/spec/set-events-for-template-helpers-spec.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getIsElementScrollable, round, scrollElementTo, slideToCategory } from 'src/set-events-for-template-helpers';
import { getIsElementScrollable, scrollElementTo, slideToCategory } from 'src/set-events-for-template-helpers';
import categoryOrder from 'src/category-order';
import { CATEGORY } from 'src/constant';

Expand All @@ -17,25 +17,6 @@ describe('`set-events-for-template-helpers`', () => {
})).toBeTruthy();
});
});
describe('has `round` function', () => {
it('that rounds up numbers', () => {
expect(round(1.77)).toBe(2);
});
it('that rounds down numbers', () => {
expect(round(1.12)).toBe(1);
});
describe('that rounds to half', () => {
it('when is half', () => {
expect(round(1.5)).toBe(1.5);
});
it('when is bellow half but closer to half than whole number', () => {
expect(round(1.32)).toBe(1.5);
});
it('when is higher than half but closer to half than whole number', () => {
expect(round(1.72)).toBe(1.5);
});
});
});
describe('has `slideToCategory` function', () => {
let panelVariables;
let slideEl;
Expand Down Expand Up @@ -79,13 +60,10 @@ describe('`set-events-for-template-helpers`', () => {
}
};
/**
* beforeEach sets resets array to empty, and each time raf or setTimeout is called, adds them to the array to be run by `runFuncArray`
* beforeEach sets resets array to empty, and each time raf called, adds them to the array to be run by `runFuncArray`
*/
beforeEach(() => {
funcArray = [];
spyOn(window, 'setTimeout').and.callFake(fn => {
funcArray.push(fn);
});
spyOn(window, 'requestAnimationFrame').and.callFake(fn => {
funcArray.push(fn);
});
Expand All @@ -100,12 +78,22 @@ describe('`set-events-for-template-helpers`', () => {
});
it('step function is called every 15ms', () => {
const animationTime = 310;
const timesStepShouldBeCalled = Math.ceil(animationTime / 15);
const timesStepShouldBeCalled = Math.floor(animationTime / 15) + 1;// Plus one for initial `requestAnimationFrame`
spyOn(Date, 'now').and.returnValues(...Array.from({ length: timesStepShouldBeCalled }).map((_, index) => 15 * index));

let doneCalled = false;
scrollElementTo({
scrollTop: 0
}, () => {}, animationTime);
}, () => {
doneCalled = true;
}, 1000, animationTime);
runFuncArray();
expect(window.setTimeout).toHaveBeenCalledTimes(timesStepShouldBeCalled);

if (doneCalled) {
expect(window.requestAnimationFrame).toHaveBeenCalledTimes(timesStepShouldBeCalled - 1);
} else {
fail('Expected done callback to be called');
}
});
});
});

0 comments on commit 0ee96ce

Please sign in to comment.