Skip to content

Commit

Permalink
fix(grid-core): Make virtual table's viewport calculation band-friend…
Browse files Browse the repository at this point in the history
…ly (T1154239) (#3643)

* make virtual table's viewport calculation band-friendly

* lint

* prettify code a little

* address Yulia's remarks: refactor tests

* Address Mike's remarks

* lint

* one more remark
  • Loading branch information
VasilyStrelyaev committed Mar 23, 2023
1 parent fc2b29e commit cf41706
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 15 deletions.
1 change: 1 addition & 0 deletions .gitignore
@@ -1,3 +1,4 @@
.DS_Store
*.log
**/dist

Expand Down
6 changes: 6 additions & 0 deletions packages/dx-grid-core/src/types/virtual-table.types.ts
Expand Up @@ -45,6 +45,12 @@ export type GetVisibleBoundaryWithFixedFn = PureComputed<
VisibleBoundary[]
>;

/** @internal */
export type GetVisibleBoundaryWithFixedPredicate = PureComputed<
[TableColumn, number, VisibleBoundary],
boolean
>;

/** @internal */
export type GetSpanBoundaryFn = PureComputed<
[TableColumn[], VisibleBoundary[], (item: any) => number],
Expand Down
95 changes: 83 additions & 12 deletions packages/dx-grid-core/src/utils/virtual-table.test.ts
Expand Up @@ -74,8 +74,8 @@ describe('VirtualTableLayout utils', () => {

expect(getColumnBoundaries(columns, 120, 80, getItemSize))
.toEqual([
[2, 5],
[0, 0],
[2, 5],
[7, 7],
]);
});
Expand Down Expand Up @@ -157,21 +157,92 @@ describe('VirtualTableLayout utils', () => {
});

describe('#getVisibleBoundaryWithFixed', () => {
it('should support fixed columns', () => {
it('should merge fixed columns in ranges', () => {
const items = [
{ key: 'a', fixed: 'before' },
{ key: 'b' },
{ key: 'c' },
{ key: 'd', fixed: 'before' },
{ key: 'e' },
{ key: 'f' },
{ key: 'g', fixed: 'after' },
{ key: '0' },
{ key: '1', fixed: 'left' },
{ key: '2', fixed: 'left' },
{ key: '3', fixed: 'left' },
{ key: '4' },
{ key: '5', fixed: 'left' },
{ key: '6', fixed: 'left' },
{ key: '7' },
{ key: '8' },
{ key: '9' },
{ key: '10' },
{ key: '11' },
{ key: '12', fixed: 'right' },
];

expect(getVisibleBoundaryWithFixed([8, 10], items))
.toEqual([[1, 3], [5, 6], [8, 10], [12, 12]]);
});

it('should accept fixed columns inside viewport', () => {
const items = [
{ key: '0', fixed: 'left' },
{ key: '1', fixed: 'left' },
{ key: '2' },
{ key: '3' },
{ key: '4', fixed: 'left' },
{ key: '5' },
{ key: '6' },
{ key: '7', fixed: 'right' },
];

expect(getVisibleBoundaryWithFixed([3, 5], items))
.toEqual([[3, 5], [0, 0], [6, 6]]);
expect(getVisibleBoundaryWithFixed([1, 5], items))
.toEqual([[1, 5], [0, 0], [6, 6]]);
.toEqual([[0, 1], [3, 5], [7, 7]]);
});

it('should extend viewport range', () => {
const items = [
{ key: '0' },
{ key: '1', fixed: 'left' },
{ key: '2' },
{ key: '3' },
{ key: '4' },
{ key: '5', fixed: 'right' },
{ key: '6' },
];

expect(getVisibleBoundaryWithFixed([2, 4], items))
.toEqual([[1, 5]]);
});

it('should not include "fixed: rignt" columns to the left of the viewport', () => {
const items = [
{ key: '0' },
{ key: '1', fixed: 'right' },
{ key: '2' },
{ key: '3' },
{ key: '4' },
{ key: '5' },
{ key: '6' },
{ key: '7', fixed: 'right' },
{ key: '8', fixed: 'right' },
{ key: '9' },
];

expect(getVisibleBoundaryWithFixed([3, 5], items))
.toEqual([[3, 5], [7, 8]]);
});

it('should not include "fixed: left" columns to the right of the viewport', () => {
const items = [
{ key: '0' },
{ key: '1', fixed: 'left' },
{ key: '2', fixed: 'left' },
{ key: '3' },
{ key: '4' },
{ key: '5' },
{ key: '6' },
{ key: '7' },
{ key: '8', fixed: 'left' },
{ key: '9' },
];

expect(getVisibleBoundaryWithFixed([4, 6], items))
.toEqual([[1, 2], [4, 6]]);
});
});

Expand Down
33 changes: 30 additions & 3 deletions packages/dx-grid-core/src/utils/virtual-table.ts
Expand Up @@ -14,19 +14,46 @@ import {
GetRenderBoundaryFn,
GetRowsVisibleBoundaryFn,
TableRow,
GetVisibleBoundaryWithFixedPredicate,
} from '../types';
import { TABLE_FLEX_TYPE, intervalUtil } from '..';

export const TABLE_STUB_TYPE = Symbol('stub');

const isLeftFixedInViewport: GetVisibleBoundaryWithFixedPredicate = (
item, index, visibleBoundary,
) => index < visibleBoundary[0] && item.fixed === 'left';

const isRightFixedInViewport: GetVisibleBoundaryWithFixedPredicate = (
item, index, visibleBoundary,
) => index > visibleBoundary[1] && item.fixed === 'right';

const isFixedInViewport: GetVisibleBoundaryWithFixedPredicate = (
item, index, visibleBoundary,
) => isLeftFixedInViewport(item, index, visibleBoundary)
|| isRightFixedInViewport(item, index, visibleBoundary);

const isColumnInViewport: GetVisibleBoundaryWithFixedPredicate = (
item, index, visibleBoundary,
) => index >= visibleBoundary[0] && index <= visibleBoundary[1]
|| isFixedInViewport(item, index, visibleBoundary);

export const getVisibleBoundaryWithFixed: GetVisibleBoundaryWithFixedFn = (
visibleBoundary, items,
) => items.reduce((acc, item, index) => {
if (item.fixed && (index < visibleBoundary[0] || index > visibleBoundary[1])) {
acc.push([index, index]);
if (isColumnInViewport(item, index, visibleBoundary)) {
const previousRange = !!acc.length && acc[acc.length - 1];
const isAdjacentToPreviousRange = previousRange && previousRange[1] === index - 1;

if (isAdjacentToPreviousRange) {
acc.splice(-1, 1, [previousRange[0], index]);
} else {
acc.push([index, index]);
}
}

return acc;
}, [visibleBoundary] as [VisibleBoundary]);
}, [] as VisibleBoundary[]);

export const getVisibleBoundary: GetVisibleBoundaryFn = (
items, viewportStart, viewportSize, getItemSize, skipItems, offset = 0,
Expand Down

0 comments on commit cf41706

Please sign in to comment.