Skip to content

Commit 1ddd749

Browse files
committed
add item size estimator class
1 parent 9a85501 commit 1ddd749

File tree

3 files changed

+65
-5
lines changed

3 files changed

+65
-5
lines changed

src/cdk-experimental/scrolling/auto-size-virtual-scroll.ts

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,32 +6,79 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9+
import {Range} from '@angular/cdk/collections';
910
import {Directive, forwardRef, Input, OnChanges} from '@angular/core';
1011
import {VIRTUAL_SCROLL_STRATEGY, VirtualScrollStrategy} from './virtual-scroll-strategy';
1112
import {CdkVirtualScrollViewport} from './virtual-scroll-viewport';
1213

1314

15+
/**
16+
* A class that tracks the size of items that have been seen and uses it to estimate the average
17+
* item size.
18+
*/
19+
export class ItemSizeEstimator {
20+
/** The total amount of weight behind the current average. */
21+
private _totalWeight = 0;
22+
23+
/** The current average item size. */
24+
private _averageItemSize: number;
25+
26+
/** @param defaultItemSize The default size to use for items when no data is available. */
27+
constructor(defaultItemSize = 50) {
28+
this._averageItemSize = defaultItemSize;
29+
}
30+
31+
/** Returns the average item size. */
32+
getAverageItemSize(): number {
33+
return this._averageItemSize;
34+
}
35+
36+
/**
37+
* Adds a measurement sample for the estimator to consider.
38+
* @param range The measured range.
39+
* @param size The measured size of the given range in pixels.
40+
*/
41+
addSample(range: Range, size: number) {
42+
const weight = range.end - range.start;
43+
const newTotalWeight = this._totalWeight + weight;
44+
if (newTotalWeight) {
45+
const newAverageItemSize =
46+
(size * weight + this._averageItemSize * this._totalWeight) / newTotalWeight;
47+
if (newAverageItemSize) {
48+
this._averageItemSize = newAverageItemSize;
49+
this._totalWeight = newTotalWeight;
50+
}
51+
}
52+
}
53+
}
54+
55+
1456
/** Virtual scrolling strategy for lists with items of unknown or dynamic size. */
1557
export class AutoSizeVirtualScrollStrategy implements VirtualScrollStrategy {
1658
/** The attached viewport. */
1759
private _viewport: CdkVirtualScrollViewport | null = null;
1860

19-
/** The size of the items in the virtually scrolling list. */
61+
/** The minimum amount of buffer rendered beyond the viewport (in pixels). */
2062
private _minBufferPx: number;
2163

22-
/** The number of buffer items to render beyond the edge of the viewport. */
64+
/** The number of buffer items to render beyond the edge of the viewport (in pixels). */
2365
private _addBufferPx: number;
2466

67+
/** The estimator used to estimate the size of unseen items. */
68+
private _estimator: ItemSizeEstimator;
69+
2570
/**
2671
* @param minBufferPx The minimum amount of buffer rendered beyond the viewport (in pixels).
2772
* If the amount of buffer dips below this number, more items will be rendered.
2873
* @param addBufferPx The number of pixels worth of buffer to shoot for when rendering new items.
2974
* If the actual amount turns out to be less it will not necessarily trigger an additional
3075
* rendering cycle (as long as the amount of buffer is still greater than `minBufferPx`).
76+
* @param estimator The estimator used to estimate the size of unseen items.
3177
*/
32-
constructor(minBufferPx: number, addBufferPx: number) {
78+
constructor(minBufferPx: number, addBufferPx: number, estimator = new ItemSizeEstimator()) {
3379
this._minBufferPx = minBufferPx;
3480
this._addBufferPx = addBufferPx;
81+
this._estimator = estimator;
3582
}
3683

3784
/**
@@ -48,7 +95,7 @@ export class AutoSizeVirtualScrollStrategy implements VirtualScrollStrategy {
4895
this._viewport = null;
4996
}
5097

51-
/** Called when the viewport is scrolled (debounced using requestAnimationFrame). */
98+
/** Called when the viewport is scrolled. */
5299
onContentScrolled() {
53100
// TODO: do stuff.
54101
}
@@ -58,6 +105,12 @@ export class AutoSizeVirtualScrollStrategy implements VirtualScrollStrategy {
58105
// TODO: do stuff.
59106
}
60107

108+
/**
109+
* Update the buffer parameters.
110+
* @param minBufferPx The minimum amount of buffer rendered beyond the viewport (in pixels).
111+
* @param addBufferPx The number of buffer items to render beyond the edge of the viewport (in
112+
* pixels).
113+
*/
61114
updateBufferSize(minBufferPx, addBufferPx) {
62115
this._minBufferPx = minBufferPx;
63116
this._addBufferPx = addBufferPx;

src/cdk-experimental/scrolling/fixed-size-virtual-scroll.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ export class FixedSizeVirtualScrollStrategy implements VirtualScrollStrategy {
5959
this._updateRenderedRange();
6060
}
6161

62-
/** Called when the viewport is scrolled (debounced using requestAnimationFrame). */
62+
/** Called when the viewport is scrolled. */
6363
onContentScrolled() {
6464
this._updateRenderedRange();
6565
}

src/demo-app/virtual-scroll/virtual-scroll-demo.html

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,10 @@
1010
Item #{{i}} - ({{size}}px)
1111
</div>
1212
</cdk-virtual-scroll-viewport>
13+
14+
15+
<cdk-virtual-scroll-viewport class="demo-viewport" autosize>
16+
<div *cdkVirtualFor="let size of data; let i = index" class="demo-item" [style.height.px]="size">
17+
Item #{{i}} - ({{size}}px)
18+
</div>
19+
</cdk-virtual-scroll-viewport>

0 commit comments

Comments
 (0)