vscroll
Version:
Virtual scroll engine
98 lines • 3.42 kB
JavaScript
import { BaseProcessFactory, CommonProcess, ProcessStatus } from './misc/index';
import { Direction } from '../inputs/index';
export default class Scroll extends BaseProcessFactory(CommonProcess.scroll) {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
static run(scroller, payload) {
const { workflow, viewport } = scroller;
const position = viewport.scrollPosition;
if (Scroll.onSynthetic(scroller, position)) {
return;
}
Scroll.onThrottle(scroller, position, () => Scroll.onScroll(scroller, workflow));
}
static onSynthetic(scroller, position) {
const { scroll } = scroller.state;
const synthPos = scroll.syntheticPosition;
if (synthPos !== null) {
if (scroll.syntheticFulfill) {
scroll.syntheticPosition = null;
}
if (!scroll.syntheticFulfill || synthPos === position) {
scroller.logger.log(() => [
'skipping scroll', position, `[${scroll.syntheticFulfill ? '' : 'pre-'}synthetic]`
]);
return true;
}
scroller.logger.log(() => [
'synthetic scroll has been fulfilled:', position, position < synthPos ? '<' : '>', synthPos
]);
}
return false;
}
static onThrottle(scroller, position, done) {
const { state: { scroll }, settings: { throttle }, logger } = scroller;
scroll.current = Scroll.getScrollEvent(position, scroll.previous);
const { direction, time } = scroll.current;
const timeDiff = scroll.previous ? time - scroll.previous.time : Infinity;
const delta = throttle - timeDiff;
const shouldDelay = isFinite(delta) && delta > 0;
const alreadyDelayed = !!scroll.scrollTimer;
logger.log(() => [
direction === Direction.backward ? '\u2934' : '\u2935',
position,
shouldDelay ? (timeDiff + 'ms') : '0ms',
shouldDelay ? (alreadyDelayed ? 'delayed' : `/ ${delta}ms delay`) : ''
]);
if (!shouldDelay) {
if (scroll.scrollTimer) {
clearTimeout(scroll.scrollTimer);
scroll.scrollTimer = null;
}
done();
return;
}
if (!alreadyDelayed) {
scroll.scrollTimer = setTimeout(() => {
logger.log(() => {
const curr = Scroll.getScrollEvent(scroller.viewport.scrollPosition, scroll.current);
return [
curr.direction === Direction.backward ? '\u2934' : '\u2935',
curr.position,
(curr.time - time) + 'ms',
'triggered by timer set on',
position
];
});
scroll.scrollTimer = null;
done();
}, delta);
}
}
static getScrollEvent(position, previous) {
const time = Number(new Date());
let direction = Direction.forward;
if (previous) {
if (position === previous.position) {
direction = previous.direction;
}
else if (position < previous.position) {
direction = Direction.backward;
}
}
return { position, direction, time };
}
static onScroll(scroller, workflow) {
const { state: { scroll, cycle } } = scroller;
scroll.previous = Object.assign({}, scroll.current);
scroll.current = null;
if (cycle.busy.get()) {
scroller.logger.log(() => ['skipping scroll', scroll.previous.position, '[pending]']);
return;
}
workflow.call({
process: Scroll.process,
status: ProcessStatus.next
});
}
}
//# sourceMappingURL=scroll.js.map