Files

120 lines
3.4 KiB
TypeScript

import {List} from './list';
export class ListVirtualScroll {
content;
viewContainer;
viewportHeight;
virtualHeight;
viewportScrollHeight;
itemsPerScreen;
list: List;
itemHeight: number = 60;
shownItems = {};
enteringItems = [];
leavingItems = [];
constructor(list: List) {
this.list = list;
this.content = this.list.content;
this.viewportHeight = this.content.height();
this.viewContainer = this.list.itemTemplate.viewContainer;
// Compute the initial sizes
setTimeout(() => {
this.resize();
// Simulate the first event to start layout
this._handleVirtualScroll({
target: this.content.scrollElement
});
})
this.content.addScrollEventListener((event) => {
this._handleVirtualScroll(event);
});
}
resize() {
this.viewportHeight = this.content.height();
this.viewportScrollHeight = this.content.scrollElement.scrollHeight;
this.virtualHeight = this.list.items.length * this.itemHeight;
this.itemsPerScreen = this.viewportHeight / this.itemHeight;
console.debug('VIRTUAL: resize(viewportHeight:', this.viewportHeight,
'viewportScrollHeight:', this.viewportScrollHeight, 'virtualHeight:', this.virtualHeight,
', itemsPerScreen:', this.itemsPerScreen, ')');
}
_handleVirtualScroll(event) {
let item;
let shownItemRef;
let st = event.target.scrollTop;
let sh = event.target.scrollHeight;
let topIndex = Math.floor(st / this.itemHeight);
let bottomIndex = Math.floor((st / this.itemHeight) + this.itemsPerScreen);
let items = this.list.items;
// Key iterate the shown items map
// and compare the index to our index range,
// pushing the items to remove to our leaving
// list if they're ouside this range.
for (let i in this.shownItems) {
if (i < topIndex || i > bottomIndex) {
this.leavingItems.push(this.shownItems[i]);
delete this.shownItems[i];
}
}
let realIndex = 0;
// Iterate the set of items that will be rendered, using the
// index from the actual items list as the map for the
// virtual items we draw
for (let i = topIndex, realIndex = 0; i < bottomIndex && i < items.length; i++, realIndex++) {
item = items[i];
console.debug('Drawing item', i, item.title);
shownItemRef = this.shownItems[i];
// Is this a new item?
if (!shownItemRef) {
let itemView = this.viewContainer.create(this.list.itemTemplate.protoViewRef, realIndex);
itemView.setLocal('\$implicit', item);
itemView.setLocal('\$item', item);
shownItemRef = new VirtualItemRef(item, i, realIndex, itemView);
this.shownItems[i] = shownItemRef;
this.enteringItems.push(shownItemRef);
}
//tuple.view = viewContainer.create(protoViewRef, tuple.record.currentIndex);
}
while (this.leavingItems.length) {
let itemRef = this.leavingItems.pop();
console.debug('Removing item', itemRef.item, itemRef.realIndex);
this.viewContainer.remove(itemRef.realIndex);
}
console.debug('VIRTUAL SCROLL: scroll(scrollTop:', st, 'topIndex:', topIndex, 'bottomIndex:', bottomIndex, ')');
console.debug('Container has', this.list.getNativeElement().children.length, 'children');
}
cellAtIndex(index) {
}
}
class VirtualItemRef {
constructor(public item, public index, public realIndex, public view) {}
}