From 60ec9e097047c7cec9f961e21eb55c0528636944 Mon Sep 17 00:00:00 2001 From: Austin <amcdaniel2@gmail.com> Date: Thu, 16 Nov 2017 20:30:33 -0600 Subject: [PATCH] feat(perf): attempt at making better performance for offsetx --- src/components/body/body-row.component.ts | 22 +++++++++++++-- src/components/body/body.component.ts | 34 ++++------------------- src/components/body/scroller.component.ts | 26 ++++++++++++----- src/components/body/scroller.service.ts | 7 +++++ src/components/datatable.component.ts | 4 ++- src/components/header/header.component.ts | 34 ++++++++++++++++++----- 6 files changed, 81 insertions(+), 46 deletions(-) create mode 100644 src/components/body/scroller.service.ts diff --git a/src/components/body/body-row.component.ts b/src/components/body/body-row.component.ts index 19e7f7c56..8b6765c1f 100644 --- a/src/components/body/body-row.component.ts +++ b/src/components/body/body-row.component.ts @@ -8,6 +8,8 @@ import { } from '../../utils'; import { ScrollbarHelper } from '../../services'; import { MouseEvent, KeyboardEvent } from '../../events'; +import { ScrollerService } from './scroller.service'; +import { Subscription } from 'rxjs/Subscription'; @Component({ selector: 'datatable-body-row', @@ -16,7 +18,7 @@ import { MouseEvent, KeyboardEvent } from '../../events'; <div *ngFor="let colGroup of columnsByPin; let i = index; trackBy: trackByGroups" class="datatable-row-{{colGroup.type}} datatable-row-group" - [ngStyle]="stylesByGroup(colGroup.type)"> + [ngStyle]="groupStyles[colGroup.type]"> <datatable-body-cell *ngFor="let column of colGroup.columns; let ii = index; trackBy: columnTrackingFn" tabindex="-1" @@ -105,15 +107,30 @@ export class DataTableBodyRowComponent implements DoCheck { _columns: any[]; _innerWidth: number; + groupStyles = { + left: {}, + center: {}, + right: {} + }; + private rowDiffer: KeyValueDiffer<{}, {}>; + private subscription: Subscription; constructor( + private scroller: ScrollerService, private differs: KeyValueDiffers, private scrollbarHelper: ScrollbarHelper, private cd: ChangeDetectorRef, element: ElementRef) { this.element = element.nativeElement; this.rowDiffer = differs.find({}).create(); + + this.subscription = scroller.offset.subscribe((offset: any) => { + this.groupStyles.left = this.stylesByGroup('left', offset.scrollXPos); + this.groupStyles.center = this.stylesByGroup('center', offset.scrollXPos; + this.groupStyles.right = this.stylesByGroup('right', offset.scrollXPos); + this.cd.markForCheck(); + }); } ngDoCheck(): void { @@ -130,9 +147,8 @@ export class DataTableBodyRowComponent implements DoCheck { return column.$$id; } - stylesByGroup(group: string) { + stylesByGroup(group: string, offsetX: number) { const widths = this.columnGroupWidths; - const offsetX = this.offsetX; const styles = { width: `${widths[group]}px` diff --git a/src/components/body/body.component.ts b/src/components/body/body.component.ts index 26a72206c..bbc9123a2 100644 --- a/src/components/body/body.component.ts +++ b/src/components/body/body.component.ts @@ -321,12 +321,14 @@ export class DataTableBodyComponent implements OnInit, OnDestroy { }); } - this.offsetY = scrollYPos; this.offsetX = scrollXPos; - this.updateIndexes(); - this.updatePage(event.direction); - this.updateRows(); + if (this.offsetY !== scrollYPos) { + this.offsetY = scrollYPos; + this.updateIndexes(); + this.updatePage(event.direction); + this.updateRows(); + } } /** @@ -645,30 +647,6 @@ export class DataTableBodyComponent implements OnInit, OnDestroy { columnTrackingFn(index: number, column: any): any { return column.$$id; } - - /** - * Gets the row pinning group styles - */ - stylesByGroup(group: string) { - const widths = this.columnGroupWidths; - const offsetX = this.offsetX; - - const styles = { - width: `${widths[group]}px` - }; - - if(group === 'left') { - translateXY(styles, offsetX, 0); - } else if(group === 'right') { - const bodyWidth = parseInt(this.innerWidth + '', 0); - const totalDiff = widths.total - bodyWidth; - const offsetDiff = totalDiff - offsetX; - const offset = offsetDiff * -1; - translateXY(styles, offset, 0); - } - - return styles; - } /** * Returns if the row was expanded and set default row expansion when row expansion is empty diff --git a/src/components/body/scroller.component.ts b/src/components/body/scroller.component.ts index ea4eb06e4..0e8dc9eeb 100644 --- a/src/components/body/scroller.component.ts +++ b/src/components/body/scroller.component.ts @@ -1,9 +1,10 @@ import { - Component, Input, ElementRef, Output, EventEmitter, + Component, Input, ElementRef, Output, EventEmitter, NgZone, OnInit, OnDestroy, HostBinding, ChangeDetectionStrategy } from '@angular/core'; import { MouseEvent } from '../../events'; +import { ScrollerService } from './scroller.service'; @Component({ selector: 'datatable-scroller', @@ -36,7 +37,10 @@ export class ScrollerComponent implements OnInit, OnDestroy { parentElement: any; onScrollListener: any; - constructor(element: ElementRef) { + constructor( + private ngZone: NgZone, + private scroller: ScrollerService, + element: ElementRef) { this.element = element.nativeElement; } @@ -44,7 +48,9 @@ export class ScrollerComponent implements OnInit, OnDestroy { // manual bind so we don't always listen if (this.scrollbarV || this.scrollbarH) { this.parentElement = this.element.parentElement.parentElement; - this.parentElement.addEventListener('scroll', this.onScrolled.bind(this)); + this.ngZone.runOutsideAngular(() => { + this.parentElement.addEventListener('scroll', this.onScrolled.bind(this)); + }); } } @@ -62,10 +68,11 @@ export class ScrollerComponent implements OnInit, OnDestroy { onScrolled(event: MouseEvent): void { const dom: Element = <Element>event.currentTarget; - this.scrollYPos = dom.scrollTop; - this.scrollXPos = dom.scrollLeft; - - requestAnimationFrame(this.updateOffset.bind(this)); + requestAnimationFrame(() => { + this.scrollYPos = dom.scrollTop; + this.scrollXPos = dom.scrollLeft; + this.updateOffset(); + }); } updateOffset(): void { @@ -82,6 +89,11 @@ export class ScrollerComponent implements OnInit, OnDestroy { scrollXPos: this.scrollXPos }); + this.scroller.offset.next({ + scrollYPos: this.scrollYPos, + scrollXPos: this.scrollXPos + }); + this.prevScrollYPos = this.scrollYPos; this.prevScrollXPos = this.scrollXPos; } diff --git a/src/components/body/scroller.service.ts b/src/components/body/scroller.service.ts new file mode 100644 index 000000000..93f7c32ba --- /dev/null +++ b/src/components/body/scroller.service.ts @@ -0,0 +1,7 @@ +import { Injectable } from '@angular/core'; +import { Subject } from 'rxjs/Subject'; + +@Injectable() +export class ScrollerService { + offset = new Subject(); +} diff --git a/src/components/datatable.component.ts b/src/components/datatable.component.ts index 06a015c4f..b410a9f36 100644 --- a/src/components/datatable.component.ts +++ b/src/components/datatable.component.ts @@ -18,6 +18,7 @@ import { DataTableColumnDirective } from './columns'; import { DatatableRowDetailDirective } from './row-detail'; import { DatatableFooterDirective } from './footer'; import { MouseEvent } from '../events'; +import { ScrollerService } from './body/scroller.service'; @Component({ selector: 'ngx-datatable', @@ -31,7 +32,6 @@ import { MouseEvent } from '../events'; [sortType]="sortType" [scrollbarH]="scrollbarH" [innerWidth]="innerWidth" - [offsetX]="offsetX" [dealsWithGroup]="groupedRows" [columns]="_internalColumns" [headerHeight]="headerHeight" @@ -100,6 +100,7 @@ import { MouseEvent } from '../events'; changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, styleUrls: ['./datatable.component.scss'], + providers: [ScrollerService], host: { class: 'ngx-datatable' } @@ -620,6 +621,7 @@ export class DatatableComponent implements OnInit, DoCheck, AfterViewInit { _columnTemplates: QueryList<DataTableColumnDirective>; constructor( + private scroller: ScrollerService, private scrollbarHelper: ScrollbarHelper, private cd: ChangeDetectorRef, element: ElementRef, diff --git a/src/components/header/header.component.ts b/src/components/header/header.component.ts index fb9e57b3a..8be171598 100644 --- a/src/components/header/header.component.ts +++ b/src/components/header/header.component.ts @@ -1,10 +1,12 @@ import { - Component, Output, EventEmitter, Input, HostBinding + Component, Output, EventEmitter, Input, HostBinding, ChangeDetectorRef, OnDestroy } from '@angular/core'; import { SortType, SelectionType } from '../../types'; import { columnsByPin, columnGroupWidths, columnsByPinArr, translateXY } from '../../utils'; import { DataTableColumnDirective } from '../columns'; import { MouseEvent } from '../../events'; +import { ScrollerService } from '../body/scroller.service'; +import { Subscription } from 'rxjs/Subscription'; @Component({ selector: 'datatable-header', @@ -14,11 +16,10 @@ import { MouseEvent } from '../../events'; (reorder)="onColumnReordered($event)" [style.width.px]="columnGroupWidths.total" class="datatable-header-inner"> - <div *ngFor="let colGroup of columnsByPin; trackBy: trackByGroups" [class]="'datatable-row-' + colGroup.type" - [ngStyle]="stylesByGroup(colGroup.type)"> + [ngStyle]="groupStyles[colGroup.type]"> <datatable-header-cell *ngFor="let column of colGroup.columns; trackBy: columnTrackingFn" resizeable @@ -53,7 +54,7 @@ import { MouseEvent } from '../../events'; class: 'datatable-header' } }) -export class DataTableHeaderComponent { +export class DataTableHeaderComponent implements OnDestroy { @Input() sortAscendingIcon: any; @Input() sortDescendingIcon: any; @Input() scrollbarH: boolean; @@ -74,7 +75,6 @@ export class DataTableHeaderComponent { return this._innerWidth; } - @Input() offsetX: number; @Input() sorts: any[]; @Input() sortType: SortType; @Input() allRowsSelected: boolean; @@ -119,6 +119,27 @@ export class DataTableHeaderComponent { _columns: any[]; _headerHeight: string; + groupStyles = { + left: {}, + center: {}, + right: {} + }; + + private subscription: Subscription; + + constructor(private scroller: ScrollerService, private cd: ChangeDetectorRef) { + this.subscription = scroller.offset.subscribe((offset: any) => { + this.groupStyles.left = this.stylesByGroup('left', offset.scrollXPos); + this.groupStyles.center = this.stylesByGroup('center', offset.scrollXPos; + this.groupStyles.right = this.stylesByGroup('right', offset.scrollXPos); + this.cd.detectChanges(); + }); + } + + ngOnDestroy() { + this.subscription.unsubscribe(); + } + onLongPressStart({ event, model }: { event: any, model: any }) { model.dragging = true; this.dragEventTarget = event; @@ -214,9 +235,8 @@ export class DataTableHeaderComponent { return sorts; } - stylesByGroup(group: string): any { + stylesByGroup(group: string, offsetX: number): any { const widths = this.columnGroupWidths; - const offsetX = this.offsetX; const styles = { width: `${widths[group]}px`