import { DomContainerProps, DerivedRowOptions, LayoutType, LayoutDensityType } from '../public-api/interfaces'; import { DEFAULT_ROW_HEIGHT, DENSITY_TO_PX_MAP, LayoutObject, CardLayout, VizRecordDomainConfig, PaginationState } from '../globals/helpers/helpers'; interface ScrollInputConfig { lazyRendering: boolean, dataLength: number, domContainer: DomContainerProps, rowConfig: DerivedRowOptions, stores: any } interface DomUpdateState { prevVizStartPx: number, prevVizEndPx: number } interface HorizontalScrollConfig { lazyRendering: boolean, layoutType: LayoutType, dataLength: number, vizStartRowPx: number, vizEndRowPx: number, vizStartRowBufferPx: number, vizEndRowBufferPx: number, lazyRenderingHeight: number, rowConfig?: DerivedRowOptions, cardConfig?: CardLayout, layoutObject: LayoutObject, prevDomUpdateState: DomUpdateState, autoHeight: boolean } interface StoreUnsubscribeFn { vizRecDomainUnsub: Function, layoutObjectUnsub: Function, autoHeightUnsub: Function } let scrollCounter = 0; class InfiniteScrollManager { private hScrollConfig: HorizontalScrollConfig; private storeUnsubscribeFn: StoreUnsubscribeFn = {}; private vizRecDomain: VizRecordDomainConfig = {}; private _paginationEnabled: boolean; private _stores: any; constructor(config: ScrollInputConfig) { let hScrollConf = this.hScrollConfig = { prevDomUpdateState: {} }, rowConf = config.rowConfig, rowHeight: number = (rowConf.pxRowHeight|| DEFAULT_ROW_HEIGHT) + 2 * DENSITY_TO_PX_MAP[LayoutDensityType.Default], headerHeight: number = (rowConf.pxHeaderRowHeight || DEFAULT_ROW_HEIGHT) + 2 * DENSITY_TO_PX_MAP[LayoutDensityType.Default], rowConfig: DerivedRowOptions = { pxRowHeight: rowHeight, pxHeaderRowHeight: headerHeight }; this._paginationEnabled = false; this._stores = config.stores; this.vizRecDomain = { start: 0, end: 0, bodyTransLateY: 0 }; this._stores.paginationState.subscribe((state: PaginationState)=>{ this._paginationEnabled = state.enable; if (typeof this._paginationEnabled !== 'undefined' && !this._paginationEnabled){ this._stores.vizRecordDomain.update((tmpVizRecDomain:VizRecordDomainConfig) => { tmpVizRecDomain.start = 0; tmpVizRecDomain.end = this.getEndRow(); return tmpVizRecDomain; }); } }); this.storeUnsubscribeFn.vizRecDomainUnsub = this._stores.vizRecordDomain.subscribe((tmpVizRecDom: VizRecordDomainConfig) => { this.vizRecDomain = tmpVizRecDom; }); this.storeUnsubscribeFn.autoHeightUnsub = this._stores.autoHeight.subscribe((tmpAutoHeight: boolean) => { this.hScrollConfig.autoHeight = tmpAutoHeight; }); this.storeUnsubscribeFn.layoutObjectUnsub = this._stores.layoutObject.subscribe( (tmpLayoutObject:LayoutObject) => { hScrollConf.layoutObject = tmpLayoutObject; if (tmpLayoutObject.layout.type !== 'card') { if (tmpLayoutObject.layout.density && tmpLayoutObject.layout.density !== LayoutDensityType.Default) { rowConfig = { pxRowHeight:(rowConf.pxRowHeight|| DEFAULT_ROW_HEIGHT) + 2 * DENSITY_TO_PX_MAP[tmpLayoutObject.layout.density], pxHeaderRowHeight: (rowConf.pxHeaderRowHeight|| DEFAULT_ROW_HEIGHT) + 2 * DENSITY_TO_PX_MAP[tmpLayoutObject.layout.density] }; } hScrollConf.rowConfig = rowConfig; } else { hScrollConf.cardConfig = tmpLayoutObject.layoutState.cardLayout; } if ((hScrollConf.layoutType !== tmpLayoutObject.layout.type )&& !this._paginationEnabled) { if ((tmpLayoutObject.layout.type !== 'card' && tmpLayoutObject.layoutState.rowLayout) || tmpLayoutObject.layoutState.cardLayout) { hScrollConf.layoutType = tmpLayoutObject.layout.type!; // dataLength has to be provided, 1 is set just to avoid NaN calculations. hScrollConf.dataLength = config.dataLength || 1; hScrollConf.lazyRendering = config.lazyRendering; hScrollConf.vizStartRowBufferPx = hScrollConf.vizStartRowPx = 0; hScrollConf.lazyRenderingHeight = config.domContainer.height - (rowConfig.pxHeaderRowHeight || headerHeight); hScrollConf.vizEndRowPx= 2 * hScrollConf.lazyRenderingHeight; // when lazy rendering is set true if (hScrollConf.lazyRendering && !hScrollConf.autoHeight) { hScrollConf.vizEndRowBufferPx = hScrollConf.vizEndRowPx + config.domContainer.height; // intial prevDom update state setting hScrollConf.prevDomUpdateState = { prevVizStartPx: hScrollConf.vizStartRowPx, prevVizEndPx: hScrollConf.vizEndRowPx }; } else { // TO-DO, to be replaces by default row height decided // when lazy rendering is not required hScrollConf.vizEndRowBufferPx = hScrollConf.dataLength * (rowConfig.pxHeaderRowHeight || rowHeight); this.calculateStartEndRow(); } this._stores.vizRecordDomain.update((tmpVizRecDomain:VizRecordDomainConfig) => { tmpVizRecDomain.bodyTransLateY = 0; tmpVizRecDomain.start = 0; tmpVizRecDomain.end = this.getEndRow(); return tmpVizRecDomain; }); } } }); } // updates scroll property on scroll, also recalculate visible rows updateHScrollProps = (e: Event) => { let hScrollConf = this.hScrollConfig, prevDomUpdateState = hScrollConf.prevDomUpdateState; scrollCounter++; // To-Do add hscroll check if (e.target) { let targtEle = e.target; hScrollConf.vizStartRowPx = targtEle.scrollTop; hScrollConf.vizEndRowPx = targtEle.scrollTop + hScrollConf.lazyRenderingHeight; hScrollConf.vizStartRowBufferPx = (hScrollConf.vizStartRowPx - hScrollConf.lazyRenderingHeight > 0) ? hScrollConf.vizStartRowPx - hScrollConf.lazyRenderingHeight : 0; hScrollConf.vizEndRowBufferPx = hScrollConf.vizEndRowPx + (2 * hScrollConf.lazyRenderingHeight); scrollCounter--; // To-DO, set hScrollConf.vizEndRowBufferPx as hidden div's height } if (hScrollConf.layoutObject.layout.type !== 'card' && hScrollConf.rowConfig) { if((hScrollConf.vizStartRowPx >= prevDomUpdateState.prevVizEndPx) || (hScrollConf.vizEndRowPx <= prevDomUpdateState.prevVizStartPx)) { hScrollConf.prevDomUpdateState = { prevVizStartPx: hScrollConf.vizStartRowPx, prevVizEndPx: hScrollConf.vizEndRowPx }; // calculate update state end row if(scrollCounter === 0 && !this._paginationEnabled) this.calculateStartEndRow(); // update update state end row } } else { if (hScrollConf.vizStartRowPx >= prevDomUpdateState.prevVizEndPx) { prevDomUpdateState.prevVizStartPx = hScrollConf.vizStartRowPx; prevDomUpdateState.prevVizEndPx = hScrollConf.vizEndRowPx; if(scrollCounter === 0 && !this._paginationEnabled) this.calculateStartEndRow(); } } } getEndRow (): number { let hScrollConf = this.hScrollConfig; if (hScrollConf.layoutObject.layout.type !== 'card') { if (hScrollConf.rowConfig && hScrollConf.rowConfig.pxRowHeight){ return Math.min(Math.floor(hScrollConf.vizEndRowBufferPx / hScrollConf.rowConfig.pxRowHeight), hScrollConf.dataLength - 1); } } else if (hScrollConf.layoutObject.layout.type === 'card' && hScrollConf.cardConfig) { return Math.min(Math.floor((hScrollConf.vizEndRowBufferPx / hScrollConf.cardConfig.height) * hScrollConf.cardConfig.numCards), hScrollConf.dataLength - 1); } return (hScrollConf.dataLength - 1); } // calculates row start and end calculateStartEndRow () { let hScrollConf = this.hScrollConfig; if (hScrollConf.layoutObject.layout.type !== 'card') { if (hScrollConf.rowConfig && hScrollConf.rowConfig.pxRowHeight) { this.vizRecDomain.end = Math.min(Math.floor(hScrollConf.vizEndRowBufferPx / hScrollConf.rowConfig.pxRowHeight), hScrollConf.dataLength - 1); if (this.vizRecDomain.end < hScrollConf.dataLength - 1) { this.vizRecDomain.hiddenDivHeight = hScrollConf.vizEndRowBufferPx; this.vizRecDomain.bodyTransLateY = hScrollConf.vizStartRowBufferPx; this.vizRecDomain.start = Math.max(Math.floor(hScrollConf.vizStartRowBufferPx / hScrollConf.rowConfig.pxRowHeight), 0); } } } else { if (hScrollConf.cardConfig) { this.vizRecDomain.start = 0; this.vizRecDomain.end = Math.min(Math.floor((hScrollConf.vizEndRowBufferPx / hScrollConf.cardConfig.height) * hScrollConf.cardConfig.numCards), hScrollConf.dataLength - 1); } } this._stores.vizRecordDomain.update( (tmpVizRecDomain: any) => this.vizRecDomain); } setDatalength (val: number) { this.hScrollConfig.dataLength = val; } } export default InfiniteScrollManager;