Skip to content
Draft
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 @@ -5,6 +5,10 @@
{{ route.title }}
</button>
}

<button igxButton="contained" (click)="OnPerfTest()">
Test scroll performance
</button>
</div>
<router-outlet />
</main>
22 changes: 21 additions & 1 deletion projects/igniteui-angular-performance/src/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component } from '@angular/core';
import { Component, ViewChild } from '@angular/core';
import { RouterLink, RouterOutlet, Routes } from '@angular/router';
import { IgxButtonDirective } from 'igniteui-angular';
import { routes } from './app.routes';
Expand All @@ -11,4 +11,24 @@ import { routes } from './app.routes';
})
export class AppComponent {
protected routes: Routes = routes;

@ViewChild(RouterOutlet) outlet!: RouterOutlet;

public async OnPerfTest() {
const longTask = [];
const observer = new PerformanceObserver((list) => {
longTask.push(...list.getEntries());
});
observer.observe({ entryTypes: ['longtask'] });
const grid = (this.outlet.component as any).grid || (this.outlet.component as any).pivotGrid;
for (let i = 0; i < 100; i++) {
grid.navigateTo(i * 50);
await new Promise(r => setTimeout(r, 50));
}
const sum = longTask.reduce((acc, task) => acc + task.duration, 0);
const avgTime = sum / longTask.length;
console.log('Long Tasks:'+ longTask.length + ", ", 'Average Long Task Time:', avgTime);
observer.disconnect();

}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
<div class="grid-wrapper">
<igx-grid

#grid
[data]="data"
[allowFiltering]="true"
[allowFiltering]="false"
[height]="'100%'"
[width]="'100%'"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,9 +182,9 @@ export class PivotGridComponent {
sortDirection: SortingDirection.None
},
{
fullDate: false,
fullDate: true,
quarters: true,
months: false,
months: true,
}),
],
values: [
Expand Down
2 changes: 1 addition & 1 deletion projects/igniteui-angular-performance/src/styles.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@use '../../igniteui-angular/src/lib/core/styles/themes' as *;
@use '../../igniteui-angular/core/src/core/styles/themes' as *;
@import url('https://fonts.googleapis.com/icon?family=Material+Icons');
@include core();
@include typography(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,6 @@ export class VirtualHelperBaseDirective implements OnDestroy, AfterViewInit {
this._scrollNativeSize = this.calculateScrollNativeSize();
}

@HostListener('scroll', ['$event'])
public onScroll(event) {
this.scrollAmount = event.target.scrollTop || event.target.scrollLeft;
}


public ngAfterViewInit() {
this._afterViewInit = true;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { NgForOfContext } from '@angular/common';
import { ChangeDetectorRef, ComponentRef, Directive, DoCheck, EmbeddedViewRef, EventEmitter, Input, IterableChanges, IterableDiffer, IterableDiffers, NgZone, OnChanges, OnDestroy, OnInit, Output, SimpleChanges, TemplateRef, TrackByFunction, ViewContainerRef, AfterViewInit, booleanAttribute, DOCUMENT, inject } from '@angular/core';
import { ChangeDetectorRef, ComponentRef, Directive, EmbeddedViewRef, EventEmitter, Input, IterableChanges, IterableDiffer, IterableDiffers, NgZone, OnChanges, OnDestroy, OnInit, Output, SimpleChanges, TemplateRef, TrackByFunction, ViewContainerRef, AfterViewInit, booleanAttribute, DOCUMENT, inject, afterNextRender, runInInjectionContext, EnvironmentInjector } from '@angular/core';

import { DisplayContainerComponent } from './display.container';
import { HVirtualHelperComponent } from './horizontal.virtual.helper.component';
Expand Down Expand Up @@ -84,16 +84,17 @@ export abstract class IgxForOfToken<T, U extends T[] = T[]> {
],
standalone: true
})
export class IgxForOfDirective<T, U extends T[] = T[]> extends IgxForOfToken<T,U> implements OnInit, OnChanges, DoCheck, OnDestroy, AfterViewInit {
export class IgxForOfDirective<T, U extends T[] = T[]> extends IgxForOfToken<T,U> implements OnInit, OnChanges, OnDestroy, AfterViewInit {
private _viewContainer = inject(ViewContainerRef);
protected _template = inject<TemplateRef<NgForOfContext<T>>>(TemplateRef);
protected _differs = inject(IterableDiffers);
protected _injector = inject(EnvironmentInjector);
public cdr = inject(ChangeDetectorRef);
protected _zone = inject(NgZone);
protected syncScrollService = inject(IgxForOfScrollSyncService);
protected platformUtil = inject(PlatformUtil);
protected document = inject(DOCUMENT);

private _igxForOf: U & T[] | null = null;

/**
* Sets the data to be rendered.
Expand All @@ -102,7 +103,14 @@ export class IgxForOfDirective<T, U extends T[] = T[]> extends IgxForOfToken<T,U
* ```
*/
@Input()
public igxForOf: U & T[] | null;
public get igxForOf(): U & T[] | null {
return this._igxForOf;
}

public set igxForOf(value: U & T[] | null) {
this._igxForOf = value;
this.resolveDataDiff();
}

/**
* Sets the property name from which to read the size in the data object.
Expand Down Expand Up @@ -425,7 +433,7 @@ export class IgxForOfDirective<T, U extends T[] = T[]> extends IgxForOfToken<T,U
}
this._maxSize = this._calcMaxBrowserSize();
if (this.igxForScrollOrientation === 'vertical') {
this.dc.instance._viewContainer.element.nativeElement.style.top = '0px';
this.dc.instance._viewContainer.element.nativeElement.style.transform = `translateY(0px)`;
this.scrollComponent = this.syncScrollService.getScrollMaster(this.igxForScrollOrientation);
if (!this.scrollComponent || this.scrollComponent.destroyed) {
this.scrollComponent = vc.createComponent(VirtualHelperComponent).instance;
Expand Down Expand Up @@ -536,7 +544,7 @@ export class IgxForOfDirective<T, U extends T[] = T[]> extends IgxForOfToken<T,U
/**
* @hidden
*/
public ngDoCheck(): void {
public resolveDataDiff(): void {
if (this._differ) {
const changes = this._differ.diff(this.igxForOf);
if (changes) {
Expand Down Expand Up @@ -599,7 +607,13 @@ export class IgxForOfDirective<T, U extends T[] = T[]> extends IgxForOfToken<T,U
// Actual scroll delta that was added is smaller than 1 and onScroll handler doesn't trigger when scrolling < 1px
const scrollOffset = this.fixedUpdateAllElements(this._virtScrollPosition);
// scrollOffset = scrollOffset !== parseInt(this.igxForItemSize, 10) ? scrollOffset : 0;
this.dc.instance._viewContainer.element.nativeElement.style.top = -(scrollOffset) + 'px';
runInInjectionContext(this._injector, () => {
afterNextRender({
write: () => {
this.dc.instance._viewContainer.element.nativeElement.style.transform = `translateY(${-scrollOffset}px)`;
}
});
});
}

const maxRealScrollTop = this.scrollComponent.nativeElement.scrollHeight - containerSize;
Expand Down Expand Up @@ -894,7 +908,13 @@ export class IgxForOfDirective<T, U extends T[] = T[]> extends IgxForOfToken<T,U
const prevStartIndex = this.state.startIndex;
const scrollOffset = this.fixedUpdateAllElements(this._virtScrollPosition);

this.dc.instance._viewContainer.element.nativeElement.style.top = -(scrollOffset) + 'px';
runInInjectionContext(this._injector, () => {
afterNextRender({
write: () => {
this.dc.instance._viewContainer.element.nativeElement.style.transform = `translateY(${-scrollOffset}px)`;
}
});
});

this._zone.onStable.pipe(first()).subscribe(this.recalcUpdateSizes.bind(this));

Expand Down Expand Up @@ -1446,8 +1466,10 @@ export class IgxForOfDirective<T, U extends T[] = T[]> extends IgxForOfToken<T,U
const scroll = this.scrollComponent.nativeElement;
scrollOffset = scroll && this.scrollComponent.size ?
currentScroll - this.sizesCache[this.state.startIndex] : 0;
const dir = this.igxForScrollOrientation === 'horizontal' ? 'left' : 'top';
this.dc.instance._viewContainer.element.nativeElement.style[dir] = -(scrollOffset) + 'px';
const dir = this.igxForScrollOrientation === 'horizontal' ? 'left' : 'transform';
this.dc.instance._viewContainer.element.nativeElement.style[dir] = this.igxForScrollOrientation === 'horizontal' ?
-(scrollOffset) + 'px' :
`translateY(${-scrollOffset}px)`;
}

protected _adjustScrollPositionAfterSizeChange(sizeDiff) {
Expand All @@ -1457,7 +1479,7 @@ export class IgxForOfDirective<T, U extends T[] = T[]> extends IgxForOfToken<T,U
this.recalcUpdateSizes();
const offset = this.igxForScrollOrientation === 'horizontal' ?
parseInt(this.dc.instance._viewContainer.element.nativeElement.style.left, 10) :
parseInt(this.dc.instance._viewContainer.element.nativeElement.style.top, 10);
Number(this.dc.instance._viewContainer.element.nativeElement.style.transform?.match(/translateY\((-?\d+\.?\d*)px\)/)?.[1]);
const newSize = this.sizesCache[this.state.startIndex] - offset;
this.scrollPosition = newSize;
if (this.scrollPosition !== newSize) {
Expand Down Expand Up @@ -1509,7 +1531,7 @@ export class IgxGridForOfContext<T, U extends T[] = T[]> extends IgxForOfContext
selector: '[igxGridFor][igxGridForOf]',
standalone: true
})
export class IgxGridForOfDirective<T, U extends T[] = T[]> extends IgxForOfDirective<T, U> implements OnInit, OnChanges, DoCheck {
export class IgxGridForOfDirective<T, U extends T[] = T[]> extends IgxForOfDirective<T, U> implements OnInit, OnChanges {
protected syncService = inject(IgxForOfSyncService);

@Input()
Expand Down Expand Up @@ -1626,7 +1648,7 @@ export class IgxGridForOfDirective<T, U extends T[] = T[]> extends IgxForOfDirec
this.syncService.setMaster(this, true);
}

public override ngDoCheck() {
public override resolveDataDiff() {
if (this._differ) {
const changes = this._differ.diff(this.igxForOf);
if (changes) {
Expand Down Expand Up @@ -1660,19 +1682,24 @@ export class IgxGridForOfDirective<T, U extends T[] = T[]> extends IgxForOfDirec
}

public override onScroll(event) {
if (!parseInt(this.scrollComponent.nativeElement.style.height, 10)) {
this.scrollComponent.scrollAmount = event.target.scrollTop;
if (!this.scrollComponent.size) {
return;
}
if (!this._bScrollInternal) {
this._calcVirtualScrollPosition(event.target.scrollTop);
this._calcVirtualScrollPosition(this.scrollComponent.scrollAmount);
} else {
this._bScrollInternal = false;
}
const scrollOffset = this.fixedUpdateAllElements(this._virtScrollPosition);
runInInjectionContext(this._injector, () => {
afterNextRender({
write: () => {
this.dc.instance._viewContainer.element.nativeElement.style.transform = `translateY(${-scrollOffset}px)`;
}
});
});

this.dc.instance._viewContainer.element.nativeElement.style.top = -(scrollOffset) + 'px';

this._zone.onStable.pipe(first()).subscribe(this.recalcUpdateSizes.bind(this));
this.cdr.markForCheck();
}

Expand Down
26 changes: 18 additions & 8 deletions projects/igniteui-angular/grids/grid/src/grid-base.directive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2998,6 +2998,9 @@ export abstract class IgxGridBaseDirective implements GridType,
/** @hidden @internal */
public resizeNotify = new Subject<void>();

/** @hidden @internal */
public scrollNotify = new Subject<any>();

/** @hidden @internal */
public rowAddedNotifier = new Subject<IRowDataEventArgs>();

Expand Down Expand Up @@ -3709,6 +3712,15 @@ export abstract class IgxGridBaseDirective implements GridType,

this.subscribeToTransactions();

this.scrollNotify.pipe(
filter(() => !this._init),
throttleTime(40, animationFrameScheduler, { leading: false, trailing: true }),
destructor
)
.subscribe((event) => {
this.verticalScrollHandler(event);
});

this.resizeNotify.pipe(
filter(() => !this._init),
throttleTime(40, animationFrameScheduler, { leading: true, trailing: true }),
Expand Down Expand Up @@ -4153,7 +4165,7 @@ export abstract class IgxGridBaseDirective implements GridType,
this.zone.runOutsideAngular(() => {
this.verticalScrollHandler = this.verticalScrollHandler.bind(this);
this.horizontalScrollHandler = this.horizontalScrollHandler.bind(this);
this.verticalScrollContainer.getScroll().addEventListener('scroll', this.verticalScrollHandler);
this.verticalScrollContainer.getScroll().addEventListener('scroll', (event) => this.scrollNotify.next(event));
this.headerContainer?.getScroll().addEventListener('scroll', this.horizontalScrollHandler);
if (this.hasColumnsToAutosize) {
this.headerContainer?.dataChanged.pipe(takeUntil(this.destroy$)).subscribe(() => {
Expand Down Expand Up @@ -7721,13 +7733,11 @@ export abstract class IgxGridBaseDirective implements GridType,
this.verticalScrollContainer.onScroll(event);
this.disableTransitions = true;

this.zone.run(() => {
this.zone.onStable.pipe(first()).subscribe(() => {
this.verticalScrollContainer.chunkLoad.emit(this.verticalScrollContainer.state);
if (this.rowEditable) {
this.changeRowEditingOverlayStateOnScroll(this.crudService.rowInEditMode);
}
});
this.zone.onStable.pipe(first()).subscribe(() => {
this.verticalScrollContainer.chunkLoad.emit(this.verticalScrollContainer.state);
if (this.rowEditable) {
this.changeRowEditingOverlayStateOnScroll(this.crudService.rowInEditMode);
}
});
this.disableTransitions = false;

Expand Down
Loading