UNPKG

@progress/kendo-angular-pivotgrid

Version:
129 lines (128 loc) 6.04 kB
/**----------------------------------------------------------------------------------------- * Copyright © 2025 Progress Software Corporation. All rights reserved. * Licensed under commercial license. See LICENSE.md in the project root for more information *-------------------------------------------------------------------------------------------*/ /** * @hidden */ export class ScrollableTable { element; handlers; options; startRow = 0; endRow; startCol = 0; endCol; renderedRows; renderedCols; total; totalCols; rtl; visibleRows; visibleCols; lastKnownScrollPosition = { top: 0, left: 0 }; offsetFirst = 0; stretcher; rect; constructor(element, handlers, options) { this.element = element; this.handlers = handlers; this.options = options; this.initialize(); } onNewData(recalculateSize = false) { this.offsetFirst = this.startRow * this.options.itemHeight; this.renderedRows = Math.min(this.options.renderedRows || Math.ceil(this.visibleRows * 3), this.total); this.endRow = this.startRow + this.renderedRows; this.renderedCols = Math.min(this.options.renderedCols || Math.ceil(this.visibleCols * 1.3), this.totalCols); this.element.querySelector('table').style.transform = `translateY(${this.offsetFirst}px)`; recalculateSize && this.recalculateSize(); } destroy() { this.element.removeEventListener('scroll', this.scrollHandler); this.element.removeEventListener('scrollend', this.scrollEndHandler); this.element.removeChild(this.stretcher); } initialize() { this.rtl = this.options.rtl; this.rect = this.element.getBoundingClientRect(); // visible rows and cols this.visibleRows = Math.ceil(this.rect.height / this.options.itemHeight); this.visibleCols = Math.ceil(this.rect.width / this.options.itemWidth); // current totals this.total = this.options.total; this.totalCols = this.options.totalCols; const totalHeight = this.total * this.options.itemHeight; const totalWidth = this.totalCols * this.options.itemWidth; // "page" size (rows and cols) this.renderedRows = Math.min(this.options.renderedRows || Math.ceil(this.visibleRows * 3), this.total); this.renderedCols = Math.min(this.options.renderedCols || Math.ceil(this.visibleCols * 1.3), this.totalCols); // start and end row/col this.startRow = 0; this.startCol = 0; this.endRow = this.startRow + this.renderedRows; this.endCol = this.startCol + this.renderedCols; // element that ensures correct scrolling dimensions of the container this.stretcher = document.createElement('DIV'); this.stretcher.style.height = `${totalHeight}px`; this.stretcher.style.width = `${totalWidth}px`; this.element.appendChild(this.stretcher); this.element.addEventListener('scroll', this.scrollHandler); this.element.addEventListener('scrollend', this.scrollEndHandler); } scrollHandler = () => { const verticalDir = this.element.scrollTop - this.lastKnownScrollPosition.top; const horizontalDir = Math.abs(this.element.scrollLeft) - this.lastKnownScrollPosition.left; if (this.options.rowVirtualization) { if (verticalDir > 0) { if (this.element.scrollTop > (this.renderedRows * this.options.itemHeight + this.offsetFirst - this.rect.height)) { this.startRow = Math.floor(this.element.scrollTop / this.options.itemHeight); this.rowVirtualizationUpdate(); } } else { if (this.element.scrollTop <= this.offsetFirst) { this.startRow = Math.max(0, Math.ceil(this.element.scrollTop / this.options.itemHeight) - Math.ceil(this.options.renderedRows / 3)); this.rowVirtualizationUpdate(); } } } if (this.options.columnVirtualization) { if (horizontalDir > 0) { if (Math.abs(this.element.scrollLeft) - (Math.max(this.startCol - 1, 0) * (this.options.colWidth || 200)) > (this.options.colWidth || 200)) { this.startCol = Math.min(Math.max(Math.floor(Math.abs(this.element.scrollLeft) / this.options.itemWidth) - 1, 0), this.totalCols - this.renderedCols); this.handlers.onScroll(); } } else { if (Math.abs(this.element.scrollLeft) <= (this.startCol + 1) * (this.options.colWidth || 200)) { this.startCol = Math.min(Math.max(Math.floor(Math.abs(this.element.scrollLeft) / this.options.itemWidth) - 1, 0), this.totalCols - this.renderedCols); this.handlers.onScroll(); } } } this.lastKnownScrollPosition = { top: this.element.scrollTop, left: Math.abs(this.element.scrollLeft) }; }; scrollEndHandler = () => { this.handlers.onScrollEnd(); }; recalculateSize() { const totalHeight = this.total * this.options.itemHeight; const totalWidth = this.totalCols * this.options.itemWidth; this.stretcher.style.height = `${totalHeight}px`; this.stretcher.style.width = `${totalWidth}px`; this.rect = this.element.getBoundingClientRect(); // visible rows and cols this.visibleRows = Math.ceil(this.rect.height / this.options.itemHeight); this.visibleCols = Math.ceil(this.rect.width / this.options.itemWidth); } rowVirtualizationUpdate() { this.endRow = Math.min(this.startRow + this.renderedRows, this.total); this.offsetFirst = this.startRow * this.options.itemHeight; this.element.querySelector('table').style.transform = `translateY(${this.offsetFirst}px)`; this.handlers.onScroll(); } }