From b796b6eef021416f7b6732b5cf40f1c00bb3dde7 Mon Sep 17 00:00:00 2001 From: mmalerba Date: Mon, 12 Aug 2019 10:19:28 -0700 Subject: [PATCH] =?UTF-8?q?fix(cdk/virtual-scroll):=20fix=20subpixel=20rou?= =?UTF-8?q?nding=20errors=20on=20hdpi=E2=80=A6=20(#16269)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(cdk/virtual-scroll): fix subpixel rounding errors on hdpi screens Using `transform` appears to cause rounding errors that can accumulate and become significant after scrolling through a large number of items. Switching to `width` / `height` corrects this. * don't recalulate height/width during every change detection --- .../scrolling/virtual-scroll-viewport.html | 3 +- src/cdk/scrolling/virtual-scroll-viewport.ts | 35 ++++++++++++++----- tools/public_api_guard/cdk/scrolling.d.ts | 3 +- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/cdk/scrolling/virtual-scroll-viewport.html b/src/cdk/scrolling/virtual-scroll-viewport.html index 4da0d8085b5..39f165cfff3 100644 --- a/src/cdk/scrolling/virtual-scroll-viewport.html +++ b/src/cdk/scrolling/virtual-scroll-viewport.html @@ -9,4 +9,5 @@ Spacer used to force the scrolling container to the correct size for the *total* number of items so that the scrollbar captures the size of the entire data set. --> -
+
diff --git a/src/cdk/scrolling/virtual-scroll-viewport.ts b/src/cdk/scrolling/virtual-scroll-viewport.ts index 2bd7c815e0b..970e1ede9d9 100644 --- a/src/cdk/scrolling/virtual-scroll-viewport.ts +++ b/src/cdk/scrolling/virtual-scroll-viewport.ts @@ -71,7 +71,17 @@ export class CdkVirtualScrollViewport extends CdkScrollable implements OnInit, O private _renderedRangeSubject = new Subject(); /** The direction the viewport scrolls. */ - @Input() orientation: 'horizontal' | 'vertical' = 'vertical'; + @Input() + get orientation() { + return this._orientation; + } + set orientation(orientation: 'horizontal' | 'vertical') { + if (this._orientation !== orientation) { + this._orientation = orientation; + this._calculateSpacerSize(); + } + } + private _orientation: 'horizontal' | 'vertical' = 'vertical'; // Note: we don't use the typical EventEmitter here because we need to subscribe to the scroll // strategy lazily (i.e. only if the user is actually listening to the events). We do this because @@ -89,17 +99,17 @@ export class CdkVirtualScrollViewport extends CdkScrollable implements OnInit, O /** A stream that emits whenever the rendered range changes. */ renderedRangeStream: Observable = this._renderedRangeSubject.asObservable(); - /** - * The transform used to scale the spacer to the same size as all content, including content that - * is not currently rendered. - */ - _totalContentSizeTransform = ''; - /** * The total size of all content (in pixels), including content that is not currently rendered. */ private _totalContentSize = 0; + /** A string representing the `style.width` property value to be used for the spacer element. */ + _totalContentWidth = ''; + + /** A string representing the `style.height` property value to be used for the spacer element. */ + _totalContentHeight = ''; + /** * The CSS transform applied to the rendered subset of items so that they appear within the bounds * of the visible viewport. @@ -238,8 +248,7 @@ export class CdkVirtualScrollViewport extends CdkScrollable implements OnInit, O setTotalContentSize(size: number) { if (this._totalContentSize !== size) { this._totalContentSize = size; - const axis = this.orientation == 'horizontal' ? 'X' : 'Y'; - this._totalContentSizeTransform = `scale${axis}(${this._totalContentSize})`; + this._calculateSpacerSize(); this._markChangeDetectionNeeded(); } } @@ -398,4 +407,12 @@ export class CdkVirtualScrollViewport extends CdkScrollable implements OnInit, O fn(); } } + + /** Calculates the `style.width` and `style.height` for the spacer element. */ + private _calculateSpacerSize() { + this._totalContentHeight = + this.orientation === 'horizontal' ? '' : `${this._totalContentSize}px`; + this._totalContentWidth = + this.orientation === 'horizontal' ? `${this._totalContentSize}px` : ''; + } } diff --git a/tools/public_api_guard/cdk/scrolling.d.ts b/tools/public_api_guard/cdk/scrolling.d.ts index 950c49b0b7d..f47d94f7c1c 100644 --- a/tools/public_api_guard/cdk/scrolling.d.ts +++ b/tools/public_api_guard/cdk/scrolling.d.ts @@ -90,7 +90,8 @@ export declare type CdkVirtualForOfContext = { export declare class CdkVirtualScrollViewport extends CdkScrollable implements OnInit, OnDestroy { _contentWrapper: ElementRef; - _totalContentSizeTransform: string; + _totalContentHeight: string; + _totalContentWidth: string; elementRef: ElementRef; orientation: 'horizontal' | 'vertical'; renderedRangeStream: Observable;