vscroll
Version:
Virtual scroll engine
260 lines • 9.57 kB
JavaScript
import { __extends, __read, __spreadArray } from "tslib";
import { BaseProcessFactory, CommonProcess, AdapterProcess, ProcessStatus } from './misc/index';
import { Direction } from '../inputs/index';
var PreFetch = /** @class */ (function (_super) {
__extends(PreFetch, _super);
function PreFetch() {
return _super !== null && _super.apply(this, arguments) || this;
}
PreFetch.run = function (scroller) {
var workflow = scroller.workflow, buffer = scroller.buffer, state = scroller.state;
var fetch = state.fetch, cycle = state.cycle;
fetch.minIndex = buffer.minIndex;
// set first and last indexes of items to fetch
PreFetch.setPositionsAndIndexes(scroller);
// skip indexes that are in buffer
PreFetch.skipBufferedItems(scroller);
if (scroller.settings.infinite) {
// fill indexes to include buffer if no clip
PreFetch.checkBufferGaps(scroller);
}
// add indexes if there are too few items to fetch (clip padding)
PreFetch.checkFetchPackSize(scroller);
// set fetch direction
PreFetch.setFetchDirection(scroller);
workflow.call({
process: PreFetch.process,
status: PreFetch.getStatus(scroller),
payload: { process: cycle.initiator }
});
};
PreFetch.setPositionsAndIndexes = function (scroller) {
PreFetch.setPositions(scroller);
PreFetch.setFirstIndex(scroller);
PreFetch.setLastIndex(scroller);
scroller.logger.fetch();
};
PreFetch.setPositions = function (scroller) {
var state = scroller.state, viewport = scroller.viewport;
var positions = state.fetch.positions;
var paddingDelta = viewport.getBufferPadding();
positions.before = viewport.scrollPosition;
positions.startDelta = PreFetch.getStartDelta(scroller);
positions.relative = positions.before - positions.startDelta;
positions.start = positions.relative - paddingDelta;
positions.end = positions.relative + viewport.getSize() + paddingDelta;
};
PreFetch.getStartDelta = function (scroller) {
// calculate size before start index
var buffer = scroller.buffer, viewport = scroller.viewport;
var offset = viewport.offset;
var startDelta = 0;
if (offset) {
startDelta += offset;
}
if (!buffer.defaultSize) {
return startDelta;
}
for (var index = buffer.finiteAbsMinIndex; index < buffer.startIndex; index++) {
startDelta += buffer.getSizeByIndex(index);
}
scroller.logger.log(function () { return __spreadArray([
"start delta is ".concat(startDelta)
], __read((offset ? [" (+".concat(offset, " offset)")] : [])), false); });
return startDelta;
};
PreFetch.setFirstIndex = function (scroller) {
var state = scroller.state, buffer = scroller.buffer;
var _a = state.fetch, positions = _a.positions, first = _a.first;
var start = positions.start;
var firstIndex = buffer.startIndex;
var firstIndexPosition = 0;
if (state.cycle.innerLoop.isInitial) {
scroller.logger.log('skipping fetch backward direction [initial loop]');
}
else if (!buffer.defaultSize) {
scroller.logger.log('skipping fetch backward direction [no item size]');
}
else {
var position = firstIndexPosition;
var index = firstIndex;
while (true) {
if (start >= 0) {
var size = buffer.getSizeByIndex(index);
var diff = position + size - start;
if (diff > 0) {
firstIndex = index;
firstIndexPosition = position;
break;
}
position += size;
index++;
if (index < buffer.absMinIndex) {
break;
}
}
if (start < 0) {
index--;
if (index < buffer.absMinIndex) {
break;
}
position -= buffer.getSizeByIndex(index);
var diff = position - start;
firstIndex = index;
firstIndexPosition = position;
if (diff <= 0) {
break;
}
}
}
}
first.index = first.indexBuffer = Math.max(firstIndex, buffer.absMinIndex);
first.position = firstIndexPosition;
};
PreFetch.setLastIndex = function (scroller) {
var state = scroller.state, buffer = scroller.buffer, settings = scroller.settings;
var fetch = state.fetch, cycle = state.cycle;
var firstVisible = fetch.firstVisible, positions = fetch.positions, first = fetch.first, last = fetch.last;
var relative = positions.relative, end = positions.end;
var lastIndex;
if (!buffer.defaultSize) {
// just to fetch forward bufferSize items if neither averageItemSize nor itemSize are present
lastIndex = buffer.startIndex + settings.bufferSize - 1;
scroller.logger.log('forcing fetch forward direction [no item size]');
}
else {
var index = first.indexBuffer;
var position = first.position;
lastIndex = index;
while (true) {
lastIndex = index;
var size = buffer.getSizeByIndex(index);
position += size;
if (isNaN(firstVisible.index) && position > relative) {
firstVisible.index = index;
if (!cycle.innerLoop.isInitial) {
firstVisible.delta = position - size - relative;
}
}
if (position >= end) {
break;
}
if (index++ > buffer.absMaxIndex) {
break;
}
}
}
last.index = last.indexBuffer = Math.min(lastIndex, buffer.absMaxIndex);
};
PreFetch.skipBufferedItems = function (scroller) {
var buffer = scroller.buffer;
if (!buffer.size) {
return;
}
var fetch = scroller.state.fetch;
var firstIndex = fetch.first.index;
var lastIndex = fetch.last.index;
var packs = [[]];
var p = 0;
for (var i = firstIndex; i <= lastIndex; i++) {
if (!buffer.get(i)) {
packs[p].push(i);
}
else if (packs[p].length) {
packs[++p] = [];
}
}
var pack = packs[0];
if (packs[0].length && packs[1] && packs[1].length) {
fetch.hasAnotherPack = true;
// todo: need to look for biggest pack in visible area
// todo: or think about merging two requests in a single Fetch process
if (packs[1].length >= packs[0].length) {
pack = packs[1];
}
}
fetch.first.index = Math.max(pack[0], buffer.absMinIndex);
fetch.last.index = Math.min(pack[pack.length - 1], buffer.absMaxIndex);
if (fetch.first.index !== firstIndex || fetch.last.index !== lastIndex) {
scroller.logger.fetch('after Buffer flushing');
}
};
PreFetch.checkBufferGaps = function (scroller) {
var buffer = scroller.buffer, state = scroller.state;
var fetch = state.fetch;
if (!buffer.size) {
return;
}
var fetchFirst = fetch.first.index;
var bufferLast = buffer.lastIndex;
if (fetchFirst > bufferLast) {
fetch.first.index = fetch.first.indexBuffer = bufferLast + 1;
}
var bufferFirst = buffer.firstIndex;
var fetchLast = fetch.last.index;
if (fetchLast < bufferFirst) {
fetch.last.index = fetch.last.indexBuffer = bufferFirst - 1;
}
if (fetch.first.index !== fetchFirst || fetch.last.index !== fetchLast) {
scroller.logger.fetch('after Buffer filling (no clip case)');
}
};
PreFetch.checkFetchPackSize = function (scroller) {
var buffer = scroller.buffer, state = scroller.state;
var fetch = state.fetch;
if (!fetch.shouldFetch) {
return;
}
var firstIndex = fetch.first.index;
var lastIndex = fetch.last.index;
var diff = scroller.settings.bufferSize - (lastIndex - firstIndex + 1);
if (diff <= 0) {
return;
}
if (!buffer.size || lastIndex > buffer.items[0].$index) {
// forward
var newLastIndex = Math.min(lastIndex + diff, buffer.absMaxIndex);
if (newLastIndex > lastIndex) {
fetch.last.index = fetch.last.indexBuffer = newLastIndex;
}
}
else {
var newFirstIndex = Math.max(firstIndex - diff, buffer.absMinIndex);
if (newFirstIndex < firstIndex) {
fetch.first.index = fetch.first.indexBuffer = newFirstIndex;
}
}
if (fetch.first.index !== firstIndex || fetch.last.index !== lastIndex) {
scroller.logger.fetch('after bufferSize adjustment');
PreFetch.skipBufferedItems(scroller);
}
};
PreFetch.setFetchDirection = function (scroller) {
var buffer = scroller.buffer, state = scroller.state;
var fetch = state.fetch;
if (fetch.last.index) {
var direction_1 = Direction.forward;
if (buffer.size) {
direction_1 =
fetch.last.index < buffer.items[0].$index ? Direction.backward : Direction.forward;
}
fetch.direction = direction_1;
scroller.logger.log(function () { return "fetch direction is \"".concat(direction_1, "\""); });
}
};
PreFetch.getStatus = function (scroller) {
var _a = scroller.state, cycle = _a.cycle, fetch = _a.fetch;
if (cycle.initiator === AdapterProcess.clip) {
scroller.logger.log(function () { return "going to skip fetch due to \"".concat(AdapterProcess.clip, "\" process"); });
return ProcessStatus.next;
}
if (fetch.shouldFetch) {
scroller.logger.log(function () { return "going to fetch ".concat(fetch.count, " items started from index ").concat(fetch.index); });
return ProcessStatus.next;
}
return ProcessStatus.done;
};
return PreFetch;
}(BaseProcessFactory(CommonProcess.preFetch)));
export default PreFetch;
//# sourceMappingURL=preFetch.js.map