diff --git a/packages/dx-grid-core/src/utils/virtual-table.test.ts b/packages/dx-grid-core/src/utils/virtual-table.test.ts index 1d0060adb3..659617f7ed 100644 --- a/packages/dx-grid-core/src/utils/virtual-table.test.ts +++ b/packages/dx-grid-core/src/utils/virtual-table.test.ts @@ -504,7 +504,7 @@ describe('VirtualTableLayout utils', () => { const result = [ { column: { type: TABLE_STUB_TYPE, key: `${TABLE_STUB_TYPE.toString()}_0_0` }, colSpan: 1 }, - { column: columns[1], colSpan: 6 }, + { column: columns[1], colSpan: 4 }, { column: columns[3], colSpan: 1 }, { column: columns[4], colSpan: 1 }, { column: columns[5], colSpan: 1 }, @@ -555,6 +555,36 @@ describe('VirtualTableLayout utils', () => { expect(getCollapsedCells(columns, spanBoundary, boundaries, getColSpan)) .toEqual(result); }); + + it('should not recalculate colSpan when it is not needed', () => { + const columns = [ + { key: 'Symbol(detail)', colSpan: 1 }, + { key: 'Symbol(group_1)', colSpan: 5 }, + { key: 'Symbol(data_1)', colSpan: 1 }, + { key: 'Symbol(data_2)', colSpan: 1 }, + { key: 'Symbol(data_3)', colSpan: 1 }, + ]; + const spanBoundary = [[0, 5]]; + const boundaries = [ + [0, 0], + [1, 1], + [2, 2], + [3, 3], + [4, 4], + ]; + const getColSpan = column => column.colSpan; + + const result = [ + { column: columns[0], colSpan: 1 }, + { column: columns[1], colSpan: 5 }, + { column: columns[2], colSpan: 1 }, + { column: columns[3], colSpan: 1 }, + { column: columns[4], colSpan: 1 }, + ]; + + expect(getCollapsedCells(columns, spanBoundary, boundaries, getColSpan)) + .toEqual(result); + }); }); describe('#getCollapsedGrid', () => { @@ -582,6 +612,9 @@ describe('VirtualTableLayout utils', () => { columnsVisibleBoundary: [[1, 3]], totalRowCount: 9, offset: 0, + getColSpan: () => 1, + getColumnWidth: column => column.width, + getRowHeight: row => row.height, }; const result = getCollapsedGrid(args); @@ -612,6 +645,8 @@ describe('VirtualTableLayout utils', () => { columnsVisibleBoundary: [[0, 1]], totalRowCount: 0, offset: 0, + getColumnWidth: column => column.width, + getRowHeight: row => row.height, }; const result = { columns: args.columns, @@ -671,6 +706,8 @@ describe('VirtualTableLayout utils', () => { }, totalRowCount: 5, offset: 0, + getColumnWidth: column => column.width, + getRowHeight: row => row.height, }; const result = getCollapsedGrid(args); @@ -683,11 +720,55 @@ describe('VirtualTableLayout utils', () => { ]); expect(result.rows[0].cells.map(cell => cell.colSpan)) - .toEqual([1, 2, 1, 1, 3, 1, 1]); + .toEqual([1, 2, 1, 1, 2, 1, 1]); expect(result.rows[1].cells.map(cell => cell.colSpan)) - .toEqual([1, 6, 1, 1, 1, 1, 1]); + .toEqual([1, 5, 1, 1, 1, 1, 1]); expect(result.rows[2].cells.map(cell => cell.colSpan)) - .toEqual([9, 1, 1, 1, 1, 1, 1]); + .toEqual([7, 1, 1, 1, 1, 1, 1]); + }); + + it('should return correct cells for second row', () => { + const args = { + rows: [ + { key: 'Symbol(group_1)', height: 40 }, + { key: 'Symbol(group_2)', height: 40 }, + ], + columns: [ + { key: 'Symbol(group_3)', width: 40 }, + { key: 'Symbol(group_4)', width: 40 }, + { key: 'Symbol(select)', width: 40 }, + { key: 'Symbol(data_3)', width: 40 }, + { key: 'Symbol(data_4)', width: 40 }, + { key: 'Symbol(data_5)', width: 40 }, + { key: 'Symbol(data_6)', width: 40 }, + { key: 'Symbol(data_7)', width: 40 }, + { key: 'Symbol(data_8)', width: 40 }, + { key: 'Symbol(data_9)', width: 40 }, + { key: 'Symbol(data_10)', width: 40 }, + ], + rowsVisibleBoundary: [0, 1], + columnsVisibleBoundary: [[5, 10]], + getColSpan: (row, column) => { + if (row.key === 'Symbol(group_1)') return 1; + if (row.key === 'Symbol(group_2)' && column.key === 'Symbol(group_4)') return 11; + return 1; + }, + totalRowCount: 2, + offset: 0, + getColumnWidth: column => column.width, + getRowHeight: row => row.height, + }; + + const result = getCollapsedGrid(args); + + result.rows[1].cells.forEach((cell, index) => { + if (index === 1) { + expect(cell.colSpan).toEqual(11); + expect(cell.column.key).toEqual('Symbol(group_4)'); + } else { + expect(cell.colSpan).toEqual(1); + } + }); }); }); diff --git a/packages/dx-grid-core/src/utils/virtual-table.ts b/packages/dx-grid-core/src/utils/virtual-table.ts index 17f5dda548..996a0e5dcc 100644 --- a/packages/dx-grid-core/src/utils/virtual-table.ts +++ b/packages/dx-grid-core/src/utils/virtual-table.ts @@ -11,6 +11,7 @@ import { GetSpecificRenderBoundaryFn, GetRenderBoundaryFn, GetRowsVisibleBoundaryFn, + TableRow, } from '../types'; import { TABLE_FLEX_TYPE, intervalUtil } from '..'; @@ -233,10 +234,24 @@ export const getCollapsedCells: GetCollapsedCellsFn = ( acc || (spanBoundary[0] <= boundary[0] && boundary[1] <= spanBoundary[1])), false); if (isSpan) { const column = columns[boundary[0]]; - collapsedCells.push({ - column, - colSpan: getColSpan(column), - }); + const realColSpan = getColSpan(column); + if (realColSpan + index - 1 !== columns.length) { + const realColSpanEnd = (realColSpan + boundary[0]) - 1; + const colSpanEnd = boundaries.findIndex( + colSpanBoundary => colSpanBoundary[0] + <= realColSpanEnd && realColSpanEnd + <= colSpanBoundary[1], + ); + collapsedCells.push({ + column, + colSpan: (colSpanEnd - index) + 1, + }); + } else { + collapsedCells.push({ + column, + colSpan: realColSpan, + }); + } index += 1; } else { collapsedCells.push({ @@ -257,9 +272,9 @@ export const getCollapsedGrid: GetCollapsedGridFn = ({ columns, rowsVisibleBoundary, columnsVisibleBoundary, - getColumnWidth = (column: any) => column.width, - getRowHeight = (row: any) => row.height, - getColSpan = () => 1, + getColumnWidth, + getRowHeight, + getColSpan, totalRowCount, offset, }) => { @@ -272,13 +287,15 @@ export const getCollapsedGrid: GetCollapsedGridFn = ({ const boundaries = rowsVisibleBoundary || [0, rows.length - 1 || 1]; + const getSpanBoundaryByRow = (row: TableRow) => getSpanBoundary( + columns, + columnsVisibleBoundary, + column => getColSpan(row, column), + ); + const rowSpanBoundaries = rows - .slice(boundaries[0], boundaries[1]) - .map(row => getSpanBoundary( - columns, - columnsVisibleBoundary, - column => getColSpan(row, column), - )); + .slice(boundaries[0], boundaries[1] + 1) + .map(row => getSpanBoundaryByRow(row)); const columnBoundaries = collapseBoundaries( columns.length, columnsVisibleBoundary, @@ -301,11 +318,7 @@ export const getCollapsedGrid: GetCollapsedGridFn = ({ getRowHeight, row => getCollapsedCells( columns, - getSpanBoundary( - columns, - columnsVisibleBoundary, - column => getColSpan(row, column), - ), + getSpanBoundaryByRow(row), columnBoundaries, column => getColSpan(row, column), ), @@ -361,7 +374,7 @@ export const getCollapsedGrids: GetCollapsedGridsFn = ({ }); const headerGrid = getCollapsedGridBlock( - headerRows, getRenderRowBounds(viewport.headerRows, headerRows.length), + headerRows, getRowsRenderBoundary(headerRows.length, viewport.headerRows), ); const bodyGrid = getCollapsedGridBlock( bodyRows, @@ -371,8 +384,9 @@ export const getCollapsedGrids: GetCollapsedGridsFn = ({ totalRowCount || 1, loadedRowsStart, ); + const footerGrid = getCollapsedGridBlock( - footerRows, getRenderRowBounds(viewport.footerRows, footerRows.length), + footerRows, getRowsRenderBoundary(footerRows.length, viewport.footerRows), ); return { @@ -382,18 +396,11 @@ export const getCollapsedGrids: GetCollapsedGridsFn = ({ }; }; -const getRenderRowBounds: PureComputed<[VisibleBoundary, number], number[]> = ( - visibleBounds, rowCount, -) => getRowsRenderBoundary( - rowCount, - visibleBounds, -); - const adjustedRenderRowBounds: PureComputed<[VisibleBoundary, number, number], number[]> = ( visibleBounds, rowCount, loadedRowsStart, ) => { - const renderRowBoundaries = getRenderRowBounds( - visibleBounds, loadedRowsStart + rowCount, + const renderRowBoundaries = getRowsRenderBoundary( + loadedRowsStart + rowCount, visibleBounds, ); const adjustedInterval = intervalUtil.intersect( { start: renderRowBoundaries[0], end: renderRowBoundaries[1] },