UNPKG

fixed-react-data-grid-custom

Version:

Excel-like grid component built with React, with editors, keyboard navigation, copy & paste, and the like

136 lines (119 loc) 5.39 kB
import { getSize, getColumn, isFrozen } from '../ColumnUtils'; export const OVERSCAN_ROWS = 2; export const SCROLL_DIRECTION = { UP: 'upwards', DOWN: 'downwards', LEFT: 'left', RIGHT: 'right', NONE: 'none' }; const min = Math.min; const max = Math.max; const ceil = Math.ceil; export const getGridState = (props) => { const totalNumberColumns = getSize(props.columnMetrics.columns); const canvasHeight = props.minHeight - props.rowOffsetHeight; const renderedRowsCount = ceil((props.minHeight - props.rowHeight) / props.rowHeight); const rowOverscanEndIdx = min(props.rowsCount, renderedRowsCount * 2); return { rowOverscanStartIdx: 0, rowOverscanEndIdx, rowVisibleStartIdx: 0, rowVisibleEndIdx: renderedRowsCount, height: canvasHeight, scrollTop: 0, scrollLeft: 0, colVisibleStartIdx: 0, colVisibleEndIdx: totalNumberColumns, colOverscanStartIdx: 0, colOverscanEndIdx: totalNumberColumns, isScrolling: false, lastFrozenColumnIndex: 0 }; }; // No IE support for Array.findIndex export const findLastFrozenColumnIndex = (columns) => { let index = -1; columns.forEach((c, i) => { if (isFrozen(c)) { index = i; } }); return index; }; const getTotalFrozenColumnWidth = (columns) => { const lastFrozenColumnIndex = findLastFrozenColumnIndex(columns); if (lastFrozenColumnIndex > -1) { const lastFrozenColumn = getColumn(columns, lastFrozenColumnIndex); return lastFrozenColumn.left + lastFrozenColumn.width; } return 0; }; const getColumnCountForWidth = (columns, initialWidth, colVisibleStartIdx) => { const initialValue = { width: initialWidth, count: 0 }; return columns.slice(colVisibleStartIdx).reduce(({ width, count }, column) => { const remainingWidth = width - column.width; const columnCount = remainingWidth >= 0 ? count + 1 : count; return { width: remainingWidth, count: columnCount }; }, initialValue); }; export const getNonFrozenVisibleColStartIdx = (columns, scrollLeft) => { let remainingScroll = scrollLeft; const lastFrozenColumnIndex = findLastFrozenColumnIndex(columns); const nonFrozenColumns = columns.slice(lastFrozenColumnIndex + 1); let columnIndex = lastFrozenColumnIndex; while (remainingScroll >= 0 && columnIndex < getSize(nonFrozenColumns)) { columnIndex++; const column = getColumn(columns, columnIndex); remainingScroll -= column ? column.width : 0; } return Math.max(columnIndex, 0); }; export const getNonFrozenRenderedColumnCount = (columnMetrics, viewportDomWidth, scrollLeft) => { const { columns } = columnMetrics; if (getSize(columns) === 0) { return 0; } const colVisibleStartIdx = getNonFrozenVisibleColStartIdx(columnMetrics.columns, scrollLeft); const totalFrozenColumnWidth = getTotalFrozenColumnWidth(columnMetrics.columns); const viewportWidth = viewportDomWidth > 0 ? viewportDomWidth : columnMetrics.totalColumnWidth; const firstColumn = getColumn(columnMetrics.columns, colVisibleStartIdx); // calculate the portion width of first column hidden behind frozen columns const scrolledFrozenWidth = totalFrozenColumnWidth + scrollLeft; const firstColumnHiddenWidth = scrolledFrozenWidth > firstColumn.left ? scrolledFrozenWidth - firstColumn.left : 0; const initialWidth = viewportWidth - totalFrozenColumnWidth + firstColumnHiddenWidth; const { count } = getColumnCountForWidth(columnMetrics.columns, initialWidth, colVisibleStartIdx); return count; }; export const getVisibleBoundaries = (gridHeight, rowHeight, scrollTop, rowsCount) => { const renderedRowsCount = ceil(gridHeight / rowHeight); const rowVisibleStartIdx = max(0, Math.round(scrollTop / rowHeight)); const rowVisibleEndIdx = min(rowVisibleStartIdx + renderedRowsCount, rowsCount); return { rowVisibleStartIdx, rowVisibleEndIdx }; }; export const getScrollDirection = (lastScroll, scrollTop, scrollLeft) => { if (scrollTop !== lastScroll.scrollTop && lastScroll.scrollTop !== undefined) { return scrollTop - lastScroll.scrollTop >= 0 ? SCROLL_DIRECTION.DOWN : SCROLL_DIRECTION.UP; } if (scrollLeft !== lastScroll.scrollLeft && lastScroll.scrollLeft !== undefined) { return scrollLeft - lastScroll.scrollLeft >= 0 ? SCROLL_DIRECTION.RIGHT : SCROLL_DIRECTION.LEFT; } return SCROLL_DIRECTION.NONE; }; export const getRowOverscanStartIdx = (scrollDirection, rowVisibleStartIdx) => { return scrollDirection === SCROLL_DIRECTION.UP ? max(0, rowVisibleStartIdx - OVERSCAN_ROWS) : max(0, rowVisibleStartIdx); }; export const getRowOverscanEndIdx = (scrollDirection, rowVisibleEndIdx, rowsCount) => { const overscanBoundaryIdx = rowVisibleEndIdx + OVERSCAN_ROWS; return scrollDirection === SCROLL_DIRECTION.DOWN ? min(overscanBoundaryIdx, rowsCount) : rowVisibleEndIdx; }; export const getColOverscanStartIdx = (scrollDirection, colVisibleStartIdx, lastFrozenColumnIdx) => { const leftMostBoundIdx = lastFrozenColumnIdx > -1 ? lastFrozenColumnIdx + 1 : 0; return (scrollDirection === SCROLL_DIRECTION.LEFT || scrollDirection === SCROLL_DIRECTION.RIGHT) ? leftMostBoundIdx : colVisibleStartIdx; }; export const getColOverscanEndIdx = (scrollDirection, colVisibleEndIdx, totalNumberColumns) => { if (scrollDirection === SCROLL_DIRECTION.DOWN || scrollDirection === SCROLL_DIRECTION.UP) { return colVisibleEndIdx; } return totalNumberColumns; };