UNPKG

react-flexigrid

Version:

A React table component designed to allow presenting millions of rows of data.

359 lines (299 loc) 8.95 kB
export function getColumnsWidth(columns: Array): Number { return columns.reduce((memo, column) => memo + column.width, 0) } function getContentWidth(columns: Array): Number { return columns.reduce((memo, { children, width }) => memo + ( children && children.length ? getContentWidth(children) : width ), 0) } function getFlexGrowCount(columns: Array): Number { return columns.reduce((memo, { children, flexGrow }) => memo + ( children && children.length ? getFlexGrowCount(children) : flexGrow || 0 ), 0) } function getFlexColumns(columns: Array): Array { const result = [] columns.forEach((column) => { const { children, flexGrow } = column if (children && children.length) { result.push(...getFlexColumns(children)) } else if (flexGrow) { result.push(column) } }) return result } function getColumnsFixed(columns: Array) { let fixed = false columns.some((column) => { if (column.fixed) { fixed = column.fixed return true } return false }) return fixed } function getLeftFixedEndIndex(columns: Array): Number { // get index of the last left fixed column for (let i = columns.length - 1; i >= 0; i -= 1) { const { fixed } = columns[i] if (fixed === true || fixed === 'left') { return i } } return -1 } function getRightFixedStartIndex(columns: Array): Number { // get index of the first right fixed column for (let i = 0, l = columns.length; i < l; i += 1) { const { fixed } = columns[i] if (fixed === 'right') { return i } } return -1 } function colneColumns( columns: Array, widthMap = {}, depth = 0, parent = null, ): Array { return columns.map(({ children, fixed, ...column }, index) => { column.depth = depth + 1 if (children && children.length) { column.children = colneColumns(children, widthMap, column.depth, column) column.width = getColumnsWidth(column.children) // calc group key column.key = column.children.map(({ key }) => key).join('-') fixed = getColumnsFixed(column.children) // eslint-disable-line } else { // fix column key if (!column.key) { column.key = column.dataIndex } if (widthMap[column.key]) { column.width = widthMap[column.key] } } column.isLastLeaf = index === columns.length - 1 column.isFirstLeaf = index === 0 if (fixed) { column.fixed = fixed } if (parent) { column.parent = parent } return column }) } function flattenColumns(columns: Array): Array { const cols = [] columns.forEach((column) => { if (column.children && column.children.length) { cols.push(...flattenColumns(column.children)) } else { cols.push(column) } }) return cols } function finalCalc(columns: Array, left: Number, fixed: Boolean) { let offsetLeft = left columns.forEach((column) => { column.left = offsetLeft let current = column let parent = current.parent while (parent && current.isFirstLeaf) { parent.left = current.left current = parent parent = current.parent } if (fixed && fixed !== column.fixed) { column.fixed = fixed parent = column.parent while (parent) { parent.fixed = fixed parent = parent.parent } } offsetLeft += column.width }) } function sortColumns(columns: Array, orderMap = {}): Array { let keys = Object.keys(orderMap) if (keys.length) { const orders = keys.map(key => orderMap[key]) const cache = {} const result = [] columns.forEach((column) => { const index = keys.indexOf(`${column.key}`) if (index >= 0) { cache[orders[index]] = column result.push(null) } else { result.push(column) } }) Object.keys(cache).forEach((order) => { const column = cache[order] result[order] = column delete orderMap[column.key] }) keys = Object.keys(orderMap) if (keys.length) { result.some((column) => { keys = Object.keys(orderMap) if (keys.length && column.children) { column.children = sortColumns(column.children, orderMap) } return keys.length === 0 }) } return result } return columns } export function shrinkColumnsWidth(columnData, exceedWidth) { const { growCount, leftFixedLeafColumns, scrollableLeafColumns, rightFixedLeafColumns, } = columnData const columnCount = leftFixedLeafColumns.length + scrollableLeafColumns.length + rightFixedLeafColumns.length const divideEqually = growCount === 0 const factor = exceedWidth / (divideEqually ? columnCount : growCount) const calc = (columns, unAssignedWidth, isLast) => { let assigned = 0 let unassigned = unAssignedWidth const length = columns.length columns.forEach((column, index) => { const grow = divideEqually ? 1 : column.flexGrow let growWidth = Math.round(factor * grow) if (unassigned - growWidth < 0) { growWidth = unassigned } if (isLast && index === length - 1) { growWidth = unassigned } if (growWidth && unassigned) { assigned += growWidth unassigned -= growWidth column.width -= growWidth let parent = column.parent while (parent) { parent.width -= growWidth parent = parent.parent } } }) return { assigned, unassigned, } } let { assigned, unassigned } = calc( leftFixedLeafColumns, exceedWidth, scrollableLeafColumns.length === 0 && rightFixedLeafColumns.length === 0, ) if (assigned > 0) { columnData.leftFixedColumnsWidth -= assigned } if (unassigned > 0) { const ret = calc(scrollableLeafColumns, unassigned, rightFixedLeafColumns.length === 0) assigned = ret.assigned unassigned = ret.unassigned } if (assigned > 0) { columnData.scrollableColumnsWidth -= assigned } if (unassigned) { const ret = calc(rightFixedLeafColumns, unassigned, true) assigned = ret.assigned } if (assigned > 0) { columnData.rightFixedColumnsWidth -= assigned } } export function parseColumns( columns: Array, { widthMap = {}, orderMap = {}, viewportWidth, }, ): Object { const contentWidth = getContentWidth(columns) const growCount = getFlexGrowCount(columns) if (contentWidth < viewportWidth && growCount) { const flexColumns = getFlexColumns(columns) let unsignedWidth = viewportWidth - contentWidth const factor = unsignedWidth / growCount const flexColumnsCount = flexColumns.length widthMap = { ...widthMap } // eslint-disable-line flexColumns.forEach(({ key, dataIndex, flexGrow, width }, index) => { const keey = key || dataIndex const addWidth = index === flexColumnsCount - 1 ? unsignedWidth : Math.round(factor * flexGrow) unsignedWidth -= addWidth if (!widthMap[keey]) { widthMap[keey] = width + addWidth } }) } columns = colneColumns(columns, widthMap) // eslint-disable-line const leftFixedIndex = getLeftFixedEndIndex(columns) const rightFixedIndex = getRightFixedStartIndex(columns) let leftFixedColumns = leftFixedIndex >= 0 ? columns.slice(0, leftFixedIndex + 1) : [] let rightFixedColumns = rightFixedIndex > 0 ? columns.slice(rightFixedIndex, columns.length) : [] let scrollableColumns = columns.slice( leftFixedIndex >= 0 ? leftFixedIndex + 1 : 0, rightFixedIndex > 0 ? rightFixedIndex : columns.length, ) const cachedOrderMap = { ...orderMap } leftFixedColumns = sortColumns(leftFixedColumns, cachedOrderMap) scrollableColumns = sortColumns(scrollableColumns, cachedOrderMap) rightFixedColumns = sortColumns(rightFixedColumns, cachedOrderMap) const leftFixedLeafColumns = flattenColumns(leftFixedColumns) const scrollableLeafColumns = flattenColumns(scrollableColumns) const rightFixedLeafColumns = flattenColumns(rightFixedColumns) finalCalc(leftFixedLeafColumns, 0, 'left') finalCalc(scrollableLeafColumns, getColumnsWidth(leftFixedColumns), null) finalCalc(rightFixedLeafColumns, 0, 'right') const depth = Math.max( Math.max(...leftFixedLeafColumns.map(column => column.depth)), Math.max(...scrollableLeafColumns.map(column => column.depth)), Math.max(...rightFixedLeafColumns.map(column => column.depth)), ) return { columns, leftFixedColumns, scrollableColumns, rightFixedColumns, leftFixedLeafColumns, scrollableLeafColumns, rightFixedLeafColumns, leftFixedColumnsWidth: getColumnsWidth(leftFixedColumns), scrollableColumnsWidth: getColumnsWidth(scrollableColumns), rightFixedColumnsWidth: getColumnsWidth(rightFixedColumns), growCount, depth, } }