Skip to content

fix,perf(column-resize): Coalesce style updates along with sticky styler #20086

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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} 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 @@ -255,12 +260,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
Loading