@@ -16,7 +16,7 @@ import {CdkVirtualScrollViewport} from './virtual-scroll-viewport';
16
16
* A class that tracks the size of items that have been seen and uses it to estimate the average
17
17
* item size.
18
18
*/
19
- export class ItemSizeEstimator {
19
+ export class ItemSizeAverager {
20
20
/** The total amount of weight behind the current average. */
21
21
private _totalWeight = 0 ;
22
22
@@ -65,20 +65,20 @@ export class AutoSizeVirtualScrollStrategy implements VirtualScrollStrategy {
65
65
private _addBufferPx : number ;
66
66
67
67
/** The estimator used to estimate the size of unseen items. */
68
- private _estimator : ItemSizeEstimator ;
68
+ private _averager : ItemSizeAverager ;
69
69
70
70
/**
71
71
* @param minBufferPx The minimum amount of buffer rendered beyond the viewport (in pixels).
72
72
* If the amount of buffer dips below this number, more items will be rendered.
73
73
* @param addBufferPx The number of pixels worth of buffer to shoot for when rendering new items.
74
74
* If the actual amount turns out to be less it will not necessarily trigger an additional
75
75
* 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.
76
+ * @param averager The averager used to estimate the size of unseen items.
77
77
*/
78
- constructor ( minBufferPx : number , addBufferPx : number , estimator = new ItemSizeEstimator ( ) ) {
78
+ constructor ( minBufferPx : number , addBufferPx : number , averager = new ItemSizeAverager ( ) ) {
79
79
this . _minBufferPx = minBufferPx ;
80
80
this . _addBufferPx = addBufferPx ;
81
- this . _estimator = estimator ;
81
+ this . _averager = averager ;
82
82
}
83
83
84
84
/**
@@ -87,7 +87,8 @@ export class AutoSizeVirtualScrollStrategy implements VirtualScrollStrategy {
87
87
*/
88
88
attach ( viewport : CdkVirtualScrollViewport ) {
89
89
this . _viewport = viewport ;
90
- // TODO: kick off rendering (start with totally made up size estimate).
90
+ this . _updateTotalContentSize ( ) ;
91
+ this . _renderContentForOffset ( this . _viewport . measureScrollOffset ( ) ) ;
91
92
}
92
93
93
94
/** Detaches this scroll strategy from the currently attached viewport. */
@@ -97,12 +98,17 @@ export class AutoSizeVirtualScrollStrategy implements VirtualScrollStrategy {
97
98
98
99
/** Called when the viewport is scrolled. */
99
100
onContentScrolled ( ) {
100
- // TODO: do stuff.
101
+ if ( this . _viewport ) {
102
+ this . _renderContentForOffset ( this . _viewport . measureScrollOffset ( ) ) ;
103
+ }
101
104
}
102
105
103
106
/** Called when the length of the data changes. */
104
107
onDataLengthChanged ( ) {
105
- // TODO: do stuff.
108
+ if ( this . _viewport ) {
109
+ this . _updateTotalContentSize ( ) ;
110
+ this . _renderContentForOffset ( this . _viewport . measureScrollOffset ( ) ) ;
111
+ }
106
112
}
107
113
108
114
/**
@@ -115,6 +121,68 @@ export class AutoSizeVirtualScrollStrategy implements VirtualScrollStrategy {
115
121
this . _minBufferPx = minBufferPx ;
116
122
this . _addBufferPx = addBufferPx ;
117
123
}
124
+
125
+ /**
126
+ * Render the content that we estimate should be shown for the given scroll offset.
127
+ * Note: must not be called if `this._viewport` is null
128
+ */
129
+ private _renderContentForOffset ( scrollOffset : number ) {
130
+ const viewport = this . _viewport ! ;
131
+ const itemSize = this . _averager . getAverageItemSize ( ) ;
132
+ const firstVisibleIndex =
133
+ Math . min ( viewport . getDataLength ( ) - 1 , Math . floor ( scrollOffset / itemSize ) ) ;
134
+ const bufferSize = Math . ceil ( this . _addBufferPx / itemSize ) ;
135
+ const range = this . _expandRange (
136
+ this . _getVisibleRangeForIndex ( firstVisibleIndex ) , bufferSize , bufferSize ) ;
137
+
138
+ viewport . setRenderedRange ( range ) ;
139
+ viewport . setRenderedContentOffset ( itemSize * range . start ) ;
140
+ }
141
+
142
+ // TODO: maybe move to base class, can probably share with fixed size strategy.
143
+ /**
144
+ * Gets the visible range of data for the given start index. If the start index is too close to
145
+ * the end of the list it may be backed up to ensure the estimated size of the range is enough to
146
+ * fill the viewport.
147
+ * Note: must not be called if `this._viewport` is null
148
+ * @param startIndex The index to start the range at
149
+ * @return a range estimated to be large enough to fill the viewport when rendered.
150
+ */
151
+ private _getVisibleRangeForIndex ( startIndex : number ) : Range {
152
+ const viewport = this . _viewport ! ;
153
+ let range = {
154
+ start : startIndex ,
155
+ end : startIndex +
156
+ Math . ceil ( viewport . getViewportSize ( ) / this . _averager . getAverageItemSize ( ) )
157
+ } ;
158
+ const extra = range . end - viewport . getDataLength ( ) ;
159
+ if ( extra > 0 ) {
160
+ range . start = Math . max ( 0 , range . start - extra ) ;
161
+ }
162
+ return range ;
163
+ }
164
+
165
+ // TODO: maybe move to base class, can probably share with fixed size strategy.
166
+ /**
167
+ * Expand the given range by the given amount in either direction.
168
+ * Note: must not be called if `this._viewport` is null
169
+ * @param range The range to expand
170
+ * @param expandStart The number of items to expand the start of the range by.
171
+ * @param expandEnd The number of items to expand the end of the range by.
172
+ * @return The expanded range.
173
+ */
174
+ private _expandRange ( range : Range , expandStart : number , expandEnd : number ) : Range {
175
+ const viewport = this . _viewport ! ;
176
+ const start = Math . max ( 0 , range . start - expandStart ) ;
177
+ const end = Math . min ( viewport . getDataLength ( ) , range . end + expandEnd ) ;
178
+ return { start, end} ;
179
+ }
180
+
181
+ /** Update the viewport's total content size. */
182
+ private _updateTotalContentSize ( ) {
183
+ const viewport = this . _viewport ! ;
184
+ viewport . setTotalContentSize ( viewport . getDataLength ( ) * this . _averager . getAverageItemSize ( ) ) ;
185
+ }
118
186
}
119
187
120
188
/**
@@ -142,14 +210,14 @@ export class CdkAutoSizeVirtualScroll implements OnChanges {
142
210
* The minimum amount of buffer rendered beyond the viewport (in pixels).
143
211
* If the amount of buffer dips below this number, more items will be rendered.
144
212
*/
145
- @Input ( ) minBufferPx = 20 ;
213
+ @Input ( ) minBufferPx = 100 ;
146
214
147
215
/**
148
216
* The number of pixels worth of buffer to shoot for when rendering new items.
149
217
* If the actual amount turns out to be less it will not necessarily trigger an additional
150
218
* rendering cycle (as long as the amount of buffer is still greater than `minBufferPx`).
151
219
*/
152
- @Input ( ) addBufferPx = 5 ;
220
+ @Input ( ) addBufferPx = 200 ;
153
221
154
222
/** The scroll strategy used by this directive. */
155
223
_scrollStrategy = new AutoSizeVirtualScrollStrategy ( this . minBufferPx , this . addBufferPx ) ;
0 commit comments