Skip to content

Commit

Permalink
perf(column-resize): Coalesce style updates along with sticky styler (#…
Browse files Browse the repository at this point in the history
…20086)

(cherry picked from commit e2bc083)
  • Loading branch information
kseamon authored and mmalerba committed Aug 5, 2020
1 parent 81d904d commit 7e2079a
Show file tree
Hide file tree
Showing 19 changed files with 190 additions and 87 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*/

import {Directive, ElementRef, NgZone} from '@angular/core';
import {CdkTable} from '@angular/cdk/table';

import {ColumnResize} from '../column-resize';
import {ColumnResizeNotifier, ColumnResizeNotifierSource} from '../column-resize-notifier';
Expand All @@ -30,7 +31,8 @@ export class CdkColumnResizeFlex extends ColumnResize {
readonly elementRef: ElementRef<HTMLElement>,
protected readonly eventDispatcher: HeaderRowEventDispatcher,
protected readonly ngZone: NgZone,
protected readonly notifier: ColumnResizeNotifierSource) {
protected readonly notifier: ColumnResizeNotifierSource,
protected readonly table: CdkTable<unknown>) {
super();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*/

import {Directive, ElementRef, NgZone} from '@angular/core';
import {CdkTable} from '@angular/cdk/table';

import {ColumnResize} from '../column-resize';
import {ColumnResizeNotifier, ColumnResizeNotifierSource} from '../column-resize-notifier';
Expand All @@ -30,7 +31,8 @@ export class CdkColumnResize extends ColumnResize {
readonly elementRef: ElementRef<HTMLElement>,
protected readonly eventDispatcher: HeaderRowEventDispatcher,
protected readonly ngZone: NgZone,
protected readonly notifier: ColumnResizeNotifierSource) {
protected readonly notifier: ColumnResizeNotifierSource,
protected readonly table: CdkTable<unknown>) {
super();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*/

import {Directive, ElementRef, NgZone} from '@angular/core';
import {CdkTable} from '@angular/cdk/table';

import {ColumnResize} from '../column-resize';
import {ColumnResizeNotifier, ColumnResizeNotifierSource} from '../column-resize-notifier';
Expand All @@ -30,7 +31,8 @@ export class CdkDefaultEnabledColumnResizeFlex extends ColumnResize {
readonly elementRef: ElementRef<HTMLElement>,
protected readonly eventDispatcher: HeaderRowEventDispatcher,
protected readonly ngZone: NgZone,
protected readonly notifier: ColumnResizeNotifierSource) {
protected readonly notifier: ColumnResizeNotifierSource,
protected readonly table: CdkTable<unknown>) {
super();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*/

import {Directive, ElementRef, NgZone} from '@angular/core';
import {CdkTable} from '@angular/cdk/table';

import {ColumnResize} from '../column-resize';
import {ColumnResizeNotifier, ColumnResizeNotifierSource} from '../column-resize-notifier';
Expand All @@ -30,7 +31,8 @@ export class CdkDefaultEnabledColumnResize extends ColumnResize {
readonly elementRef: ElementRef<HTMLElement>,
protected readonly eventDispatcher: HeaderRowEventDispatcher,
protected readonly ngZone: NgZone,
protected readonly notifier: ColumnResizeNotifierSource) {
protected readonly notifier: ColumnResizeNotifierSource,
protected readonly table: CdkTable<unknown>) {
super();
}
}
8 changes: 7 additions & 1 deletion src/cdk-experimental/column-resize/column-resize-notifier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ export interface ColumnSizeAction extends ColumnSize {
* for all programatically triggered resizes.
*/
readonly completeImmediately?: boolean;

/**
* Whether the resize action is being applied to a sticky/stickyEnd column.
*/
readonly isStickyColumn?: boolean;
}

/**
Expand Down Expand Up @@ -57,6 +62,7 @@ export class ColumnResizeNotifier {

/** Instantly resizes the specified column. */
resize(columnId: string, size: number): void {
this._source.triggerResize.next({columnId, size, completeImmediately: true});
this._source.triggerResize.next(
{columnId, size, completeImmediately: true, isStickyColumn: true});
}
}
44 changes: 25 additions & 19 deletions src/cdk-experimental/column-resize/overlay-handle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {AfterViewInit, Directive, ElementRef, OnDestroy, NgZone} from '@angular/
import {coerceCssPixelValue} from '@angular/cdk/coercion';
import {Directionality} from '@angular/cdk/bidi';
import {ESCAPE} from '@angular/cdk/keycodes';
import {CdkColumnDef} from '@angular/cdk/table';
import {CdkColumnDef, _CoalescedStyleScheduler} from '@angular/cdk/table';
import {fromEvent, Subject, merge} from 'rxjs';
import {
distinctUntilChanged,
Expand Down Expand Up @@ -47,6 +47,7 @@ export abstract class ResizeOverlayHandle implements AfterViewInit, OnDestroy {
protected abstract readonly ngZone: NgZone;
protected abstract readonly resizeNotifier: ColumnResizeNotifierSource;
protected abstract readonly resizeRef: ResizeRef;
protected abstract readonly styleScheduler: _CoalescedStyleScheduler;

ngAfterViewInit() {
this._listenForMouseEvents();
Expand Down Expand Up @@ -91,15 +92,17 @@ export abstract class ResizeOverlayHandle implements AfterViewInit, OnDestroy {
const startX = mousedownEvent.screenX;

const initialSize = this._getOriginWidth();
let overlayOffset = this._getOverlayOffset();
let overlayOffset = 0;
let originOffset = this._getOriginOffset();
let size = initialSize;
let overshot = 0;

this.updateResizeActive(true);

mouseup.pipe(takeUntil(merge(escape, this.destroyed))).subscribe(({screenX}) => {
this._notifyResizeEnded(size, screenX !== startX);
this.styleScheduler.scheduleEnd(() => {
this._notifyResizeEnded(size, screenX !== startX);
});
});

escape.pipe(takeUntil(merge(mouseup, this.destroyed))).subscribe(() => {
Expand Down Expand Up @@ -137,20 +140,26 @@ export abstract class ResizeOverlayHandle implements AfterViewInit, OnDestroy {
computedNewSize = Math.min(
Math.max(computedNewSize, this.resizeRef.minWidthPx, 0), this.resizeRef.maxWidthPx);

this.resizeNotifier.triggerResize.next(
{columnId: this.columnDef.name, size: computedNewSize, previousSize: size});
this.resizeNotifier.triggerResize.next({
columnId: this.columnDef.name,
size: computedNewSize,
previousSize: size,
isStickyColumn: this.columnDef.sticky || this.columnDef.stickyEnd,
});

const originNewSize = this._getOriginWidth();
const originNewOffset = this._getOriginOffset();
const originOffsetDeltaX = originNewOffset - originOffset;
const originSizeDeltaX = originNewSize - size;
size = originNewSize;
originOffset = originNewOffset;
this.styleScheduler.scheduleEnd(() => {
const originNewSize = this._getOriginWidth();
const originNewOffset = this._getOriginOffset();
const originOffsetDeltaX = originNewOffset - originOffset;
const originSizeDeltaX = originNewSize - size;
size = originNewSize;
originOffset = originNewOffset;

overshot += deltaX + (this._isLtr() ? -originSizeDeltaX : originSizeDeltaX);
overlayOffset += originOffsetDeltaX + (this._isLtr() ? originSizeDeltaX : 0);
overshot += deltaX + (this._isLtr() ? -originSizeDeltaX : originSizeDeltaX);
overlayOffset += originOffsetDeltaX + (this._isLtr() ? originSizeDeltaX : 0);

this._updateOverlayOffset(overlayOffset);
this._updateOverlayOffset(overlayOffset);
});
});
}

Expand All @@ -167,12 +176,9 @@ export abstract class ResizeOverlayHandle implements AfterViewInit, OnDestroy {
return this.resizeRef.origin.nativeElement!.offsetLeft;
}

private _getOverlayOffset(): number {
return parseInt(this.resizeRef.overlayRef.overlayElement.style.left!, 10);
}

private _updateOverlayOffset(offset: number): void {
this.resizeRef.overlayRef.overlayElement.style.left = coerceCssPixelValue(offset);
this.resizeRef.overlayRef.overlayElement.style.transform =
`translateX(${coerceCssPixelValue(offset)})`;
}

private _isLtr(): boolean {
Expand Down
27 changes: 17 additions & 10 deletions src/cdk-experimental/column-resize/resizable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
import {Directionality} from '@angular/cdk/bidi';
import {ComponentPortal, PortalInjector} from '@angular/cdk/portal';
import {Overlay, OverlayRef} from '@angular/cdk/overlay';
import {CdkColumnDef} from '@angular/cdk/table';
import {CdkColumnDef, _CoalescedStyleScheduler} from '@angular/cdk/table';
import {merge, Subject} from 'rxjs';
import {filter, takeUntil} from 'rxjs/operators';

Expand Down Expand Up @@ -61,18 +61,21 @@ export abstract class Resizable<HandleComponent extends ResizeOverlayHandle>
protected abstract readonly overlay: Overlay;
protected abstract readonly resizeNotifier: ColumnResizeNotifierSource;
protected abstract readonly resizeStrategy: ResizeStrategy;
protected abstract readonly styleScheduler: _CoalescedStyleScheduler;
protected abstract readonly viewContainerRef: ViewContainerRef;
protected abstract readonly changeDetectorRef: ChangeDetectorRef;

private _viewInitialized = false;

/** The minimum width to allow the column to be sized to. */
get minWidthPx(): number {
return this.minWidthPxInternal;
}
set minWidthPx(value: number) {
this.minWidthPxInternal = value;

if (this.elementRef.nativeElement) {
this.columnResize.setResized();
this.columnResize.setResized();
if (this.elementRef.nativeElement && this._viewInitialized) {
this._applyMinWidthPx();
}
}
Expand All @@ -84,13 +87,15 @@ export abstract class Resizable<HandleComponent extends ResizeOverlayHandle>
set maxWidthPx(value: number) {
this.maxWidthPxInternal = value;

if (this.elementRef.nativeElement) {
this.columnResize.setResized();
this.columnResize.setResized();
if (this.elementRef.nativeElement && this._viewInitialized) {
this._applyMaxWidthPx();
}
}

ngAfterViewInit() {
this._viewInitialized = true;

this._listenForRowHoverEvents();
this._listenForResizeEvents();
this._appendInlineHandle();
Expand Down Expand Up @@ -251,12 +256,14 @@ export abstract class Resizable<HandleComponent extends ResizeOverlayHandle>
}

private _appendInlineHandle(): void {
this.inlineHandle = this.document.createElement('div');
this.inlineHandle.tabIndex = 0;
this.inlineHandle.className = this.getInlineHandleCssClassName();
this.styleScheduler.schedule(() => {
this.inlineHandle = this.document.createElement('div');
this.inlineHandle.tabIndex = 0;
this.inlineHandle.className = this.getInlineHandleCssClassName();

// TODO: Apply correct aria role (probably slider) after a11y spec questions resolved.
// TODO: Apply correct aria role (probably slider) after a11y spec questions resolved.

this.elementRef.nativeElement!.appendChild(this.inlineHandle);
this.elementRef.nativeElement!.appendChild(this.inlineHandle);
});
}
}
64 changes: 50 additions & 14 deletions src/cdk-experimental/column-resize/resize-strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import {Inject, Injectable, OnDestroy, Provider} from '@angular/core';
import {DOCUMENT} from '@angular/common';
import {coerceCssPixelValue} from '@angular/cdk/coercion';
import {CdkTable, _CoalescedStyleScheduler} from '@angular/cdk/table';

import {ColumnResize} from './column-resize';

Expand All @@ -19,6 +20,10 @@ import {ColumnResize} from './column-resize';
@Injectable()
export abstract class ResizeStrategy {
protected abstract readonly columnResize: ColumnResize;
protected abstract readonly styleScheduler: _CoalescedStyleScheduler;
protected abstract readonly table: CdkTable<unknown>;

private _pendingResizeDelta: number|null = null;

/** Updates the width of the specified column. */
abstract applyColumnSize(
Expand All @@ -40,11 +45,23 @@ export abstract class ResizeStrategy {
minSizeInPx: number): void;

/** Adjusts the width of the table element by the specified delta. */
protected updateTableWidth(delta: number): void {
const table = this.columnResize.elementRef.nativeElement;
const tableWidth = getElementWidth(table);
protected updateTableWidthAndStickyColumns(delta: number): void {
if (this._pendingResizeDelta === null) {
const tableElement = this.columnResize.elementRef.nativeElement;
const tableWidth = getElementWidth(tableElement);

this.styleScheduler.schedule(() => {
tableElement.style.width = coerceCssPixelValue(tableWidth + this._pendingResizeDelta!);

table.style.width = coerceCssPixelValue(tableWidth + delta);
this._pendingResizeDelta = null;
});

this.styleScheduler.scheduleEnd(() => {
this.table.updateStickyColumnStyles();
});
}

this._pendingResizeDelta = (this._pendingResizeDelta ?? 0) + delta;
}
}

Expand All @@ -57,17 +74,26 @@ export abstract class ResizeStrategy {
*/
@Injectable()
export class TableLayoutFixedResizeStrategy extends ResizeStrategy {
constructor(protected readonly columnResize: ColumnResize) {
constructor(
protected readonly columnResize: ColumnResize,
protected readonly styleScheduler: _CoalescedStyleScheduler,
protected readonly table: CdkTable<unknown>) {
super();
}

applyColumnSize(_: string, columnHeader: HTMLElement, sizeInPx: number,
previousSizeInPx?: number): void {
const delta = sizeInPx - (previousSizeInPx ?? getElementWidth(columnHeader));

columnHeader.style.width = coerceCssPixelValue(sizeInPx);
if (delta === 0) {
return;
}

this.styleScheduler.schedule(() => {
columnHeader.style.width = coerceCssPixelValue(sizeInPx);
});

this.updateTableWidth(delta);
this.updateTableWidthAndStickyColumns(delta);
}

applyMinColumnSize(_: string, columnHeader: HTMLElement, sizeInPx: number): void {
Expand Down Expand Up @@ -105,6 +131,8 @@ export class CdkFlexTableResizeStrategy extends ResizeStrategy implements OnDest

constructor(
protected readonly columnResize: ColumnResize,
protected readonly styleScheduler: _CoalescedStyleScheduler,
protected readonly table: CdkTable<unknown>,
@Inject(DOCUMENT) document: any) {
super();
this._document = document;
Expand All @@ -117,24 +145,30 @@ export class CdkFlexTableResizeStrategy extends ResizeStrategy implements OnDest
const delta = sizeInPx - (previousSizeInPx ??
(this._getAppliedWidth(cssFriendlyColumnName) || columnHeader.offsetWidth));

if (delta === 0) {
return;
}

const cssSize = coerceCssPixelValue(sizeInPx);

this._applyProperty(cssFriendlyColumnName, 'flex', `0 0.01 ${cssSize}`);
this.updateTableWidth(delta);
this.updateTableWidthAndStickyColumns(delta);
}

applyMinColumnSize(cssFriendlyColumnName: string, _: HTMLElement, sizeInPx: number): void {
const cssSize = coerceCssPixelValue(sizeInPx);

this._applyProperty(cssFriendlyColumnName, 'min-width', cssSize,
sizeInPx !== this.defaultMinSize);
this.updateTableWidthAndStickyColumns(0);
}

applyMaxColumnSize(cssFriendlyColumnName: string, _: HTMLElement, sizeInPx: number): void {
const cssSize = coerceCssPixelValue(sizeInPx);

this._applyProperty(cssFriendlyColumnName, 'max-width', cssSize,
sizeInPx !== this.defaultMaxSize);
this.updateTableWidthAndStickyColumns(0);
}

protected getColumnCssClass(cssFriendlyColumnName: string): string {
Expand Down Expand Up @@ -165,12 +199,14 @@ export class CdkFlexTableResizeStrategy extends ResizeStrategy implements OnDest
enable = true): void {
const properties = this._getColumnPropertiesMap(cssFriendlyColumnName);

if (enable) {
properties.set(key, value);
} else {
properties.delete(key);
}
this._applySizeCss(cssFriendlyColumnName);
this.styleScheduler.schedule(() => {
if (enable) {
properties.set(key, value);
} else {
properties.delete(key);
}
this._applySizeCss(cssFriendlyColumnName);
});
}

private _getStyleSheet(): CSSStyleSheet {
Expand Down

0 comments on commit 7e2079a

Please sign in to comment.