let tiles know when they become visible & load more tiles close to top

This commit is contained in:
Bruno Windels 2021-09-08 12:05:19 +02:00
parent f4b4638ea8
commit 7578bfa3d9
4 changed files with 61 additions and 6 deletions

View file

@ -236,6 +236,22 @@ export class TilesCollection extends BaseObservableList {
getFirst() { getFirst() {
return this._tiles[0]; return this._tiles[0];
} }
getTileIndex(searchTile) {
const idx = sortedIndex(this._tiles, searchTile, (searchTile, tile) => {
// negate result because we're switching the order of the params
return searchTile.compare(tile);
});
const foundTile = this._tiles[idx];
if (foundTile?.compare(searchTile) === 0) {
return idx;
}
return -1;
}
sliceIterator(start, end) {
return this._tiles.slice(start, end)[Symbol.iterator]();
}
} }
import {ObservableArray} from "../../../../observable/list/ObservableArray.js"; import {ObservableArray} from "../../../../observable/list/ObservableArray.js";

View file

@ -42,10 +42,41 @@ export class TimelineViewModel extends ViewModel {
const {timeline, tilesCreator} = options; const {timeline, tilesCreator} = options;
this._timeline = this.track(timeline); this._timeline = this.track(timeline);
this._tiles = new TilesCollection(timeline.entries, tilesCreator); this._tiles = new TilesCollection(timeline.entries, tilesCreator);
this._timeline.loadAtTop(50); this._startTile = null;
this._endTile = null;
this._topLoadingPromise = null;
this._bottomLoadingPromise = null;
} }
setVisibleTileRange(startTile, endTile) { setVisibleTileRange(startTile, endTile, isViewportFilled) {
// we should async batch things here?
// this will prevent a (small) inserted tile from being marked visible, won't it?
if (this._startTile === startTile && this._endTile === endTile) {
return;
}
// old tiles could have been removed from tilescollection once we support unloading
const oldStartIndex = this._startTile ? this._tiles.getTileIndex(this._startTile) : Number.MAX_SAFE_INTEGER;
const oldEndIndex = this._endTile ? this._tiles.getTileIndex(this._endTile) : Number.MIN_SAFE_INTEGER;
const newStartIndex = this._tiles.getTileIndex(startTile);
const newEndIndex = this._tiles.getTileIndex(endTile);
const minIndex = Math.min(oldStartIndex, newStartIndex);
const maxIndex = Math.max(oldEndIndex, newEndIndex);
let index = minIndex;
for (const tile of this._tiles.sliceIterator(minIndex, maxIndex)) {
const isVisible = index >= newStartIndex && index <= newEndIndex;
tile.setVisible(isVisible);
index += 1;
}
if (!isViewportFilled || (newStartIndex < 5 && !this._topLoadingPromise)) {
this._topLoadingPromise = this._timeline.loadAtTop(10).then(() => {
this._topLoadingPromise = null;
});
}
} }
get tiles() { get tiles() {

View file

@ -83,6 +83,10 @@ export class SimpleTile extends ViewModel {
return this._entry; return this._entry;
} }
compare(tile) {
return this.upperEntry.compare(tile.upperEntry);
}
compareEntry(entry) { compareEntry(entry) {
return this._entry.compare(entry); return this._entry.compare(entry);
} }
@ -119,6 +123,10 @@ export class SimpleTile extends ViewModel {
} }
setVisible(isVisible) {
}
dispose() { dispose() {
this.setUpdateEmit(null); this.setUpdateEmit(null);
super.dispose(); super.dispose();

View file

@ -86,7 +86,7 @@ export class TimelineView extends TemplateView<TimelineViewModel> {
tiles.style.setProperty("margin-top", `${missingTilesHeight}px`); tiles.style.setProperty("margin-top", `${missingTilesHeight}px`);
// we don't have enough tiles to fill the viewport, so set all as visible // we don't have enough tiles to fill the viewport, so set all as visible
const len = this.value.tiles.length; const len = this.value.tiles.length;
this.updateVisibleRange(0, len - 1); this.updateVisibleRange(0, len - 1, false);
} else { } else {
tiles.style.removeProperty("margin-top"); tiles.style.removeProperty("margin-top");
if (this.stickToBottom) { if (this.stickToBottom) {
@ -123,14 +123,14 @@ export class TimelineView extends TemplateView<TimelineViewModel> {
bottomNodeIndex = anchoredNodeIndex; bottomNodeIndex = anchoredNodeIndex;
} }
let topNodeIndex = findFirstNodeIndexAtOrBelow(tiles, scrollTop, bottomNodeIndex); let topNodeIndex = findFirstNodeIndexAtOrBelow(tiles, scrollTop, bottomNodeIndex);
this.updateVisibleRange(topNodeIndex, bottomNodeIndex); this.updateVisibleRange(topNodeIndex, bottomNodeIndex, true);
} }
private updateVisibleRange(startIndex: number, endIndex: number) { private updateVisibleRange(startIndex: number, endIndex: number, isViewportFilled: boolean) {
const firstVisibleChild = this.tilesView!.getChildInstanceByIndex(startIndex); const firstVisibleChild = this.tilesView!.getChildInstanceByIndex(startIndex);
const lastVisibleChild = this.tilesView!.getChildInstanceByIndex(endIndex); const lastVisibleChild = this.tilesView!.getChildInstanceByIndex(endIndex);
if (firstVisibleChild && lastVisibleChild) { if (firstVisibleChild && lastVisibleChild) {
this.value.setVisibleTileRange(firstVisibleChild.value, lastVisibleChild.value); this.value.setVisibleTileRange(firstVisibleChild.value, lastVisibleChild.value, isViewportFilled);
} }
} }
} }