-
-
Notifications
You must be signed in to change notification settings - Fork 880
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Improve the performance by OPC UA browser dialog #20
With LazyForDirective
- Loading branch information
Showing
7 changed files
with
410 additions
and
56 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
import { | ||
Input, Directive, ViewContainerRef, | ||
OnInit, TemplateRef, DoCheck, | ||
IterableDiffers, IterableDiffer | ||
} from '@angular/core'; | ||
|
||
@Directive({ | ||
selector: '[lazyFor]' | ||
}) | ||
export class LazyForDirective implements DoCheck, OnInit { | ||
|
||
lazyForContainer: HTMLElement; | ||
|
||
itemHeight: number; | ||
itemTagName: string; | ||
|
||
@Input() | ||
set lazyForOf(list: any[]) { | ||
this.list = list; | ||
|
||
if (list) { | ||
this.differ = this.iterableDiffers.find(list).create(); | ||
|
||
if (this.initialized) { | ||
this.update(); | ||
} | ||
} | ||
} | ||
|
||
private templateElem: HTMLElement; | ||
|
||
private beforeListElem: HTMLElement; | ||
private afterListElem: HTMLElement; | ||
|
||
private list: any[] = []; | ||
|
||
private initialized = false; | ||
private firstUpdate = true; | ||
|
||
private differ: IterableDiffer<any>; | ||
|
||
private lastChangeTriggeredByScroll = false; | ||
|
||
constructor(private vcr: ViewContainerRef, | ||
private tpl: TemplateRef<any>, | ||
private iterableDiffers: IterableDiffers) { } | ||
|
||
ngOnInit() { | ||
this.templateElem = this.vcr.element.nativeElement; | ||
|
||
this.lazyForContainer = this.templateElem.parentElement; | ||
|
||
//Adding an event listener will trigger ngDoCheck whenever the event fires so we don't actually need to call | ||
//update here. | ||
this.lazyForContainer.addEventListener('scroll', () => { | ||
this.lastChangeTriggeredByScroll = true; | ||
}); | ||
|
||
this.initialized = true; | ||
} | ||
|
||
ngDoCheck() { | ||
if (this.differ && Array.isArray(this.list)) { | ||
|
||
if (this.lastChangeTriggeredByScroll) { | ||
this.update(); | ||
this.lastChangeTriggeredByScroll = false; | ||
} else { | ||
const changes = this.differ.diff(this.list); | ||
|
||
if (changes !== null) { | ||
this.update(); | ||
} | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* List update | ||
* | ||
* @returns {void} | ||
*/ | ||
private update(): void { | ||
|
||
//Can't run the first update unless there is an element in the list | ||
if (this.list.length === 0) { | ||
this.vcr.clear(); | ||
if (!this.firstUpdate) { | ||
this.beforeListElem.style.height = '0'; | ||
this.afterListElem.style.height = '0'; | ||
} | ||
return; | ||
} | ||
|
||
if (this.firstUpdate) { | ||
this.onFirstUpdate(); | ||
} | ||
|
||
const listHeight = this.lazyForContainer.clientHeight; | ||
const scrollTop = this.lazyForContainer.scrollTop; | ||
|
||
//The height of anything inside the container but above the lazyFor content | ||
const fixedHeaderHeight = | ||
(this.beforeListElem.getBoundingClientRect().top - this.beforeListElem.scrollTop) - | ||
(this.lazyForContainer.getBoundingClientRect().top - this.lazyForContainer.scrollTop); | ||
|
||
//This needs to run after the scrollTop is retrieved. | ||
this.vcr.clear(); | ||
|
||
let listStartI = Math.floor((scrollTop - fixedHeaderHeight) / this.itemHeight); | ||
listStartI = this.limitToRange(listStartI, 0, this.list.length); | ||
|
||
let listEndI = Math.ceil((scrollTop - fixedHeaderHeight + listHeight) / this.itemHeight); | ||
listEndI = this.limitToRange(listEndI, -1, this.list.length - 1); | ||
|
||
for (let i = listStartI; i <= listEndI; i++) { | ||
this.vcr.createEmbeddedView(this.tpl, { | ||
$implicit: this.list[i], | ||
index: i | ||
}); | ||
} | ||
|
||
this.beforeListElem.style.height = `${listStartI * this.itemHeight}px`; | ||
this.afterListElem.style.height = `${(this.list.length - listEndI - 1) * this.itemHeight}px`; | ||
} | ||
|
||
/** | ||
* First update. | ||
* | ||
* @returns {void} | ||
*/ | ||
private onFirstUpdate(): void { | ||
|
||
let sampleItemElem: HTMLElement; | ||
if (this.itemHeight === undefined || this.itemTagName === undefined) { | ||
this.vcr.createEmbeddedView(this.tpl, { | ||
$implicit: this.list[0], | ||
index: 0 | ||
}); | ||
sampleItemElem = <HTMLElement>this.templateElem.nextSibling; | ||
} | ||
|
||
if (this.itemHeight === undefined) { | ||
this.itemHeight = sampleItemElem.clientHeight; | ||
} | ||
|
||
if (this.itemTagName === undefined) { | ||
this.itemTagName = sampleItemElem.tagName; | ||
} | ||
|
||
this.beforeListElem = document.createElement(this.itemTagName); | ||
this.templateElem.parentElement.insertBefore(this.beforeListElem, this.templateElem); | ||
|
||
this.afterListElem = document.createElement(this.itemTagName); | ||
this.templateElem.parentElement.insertBefore(this.afterListElem, this.templateElem.nextSibling); | ||
|
||
// If you want to use <li> elements | ||
if (this.itemTagName.toLowerCase() === 'li') { | ||
this.beforeListElem.style.listStyleType = 'none'; | ||
this.afterListElem.style.listStyleType = 'none'; | ||
} | ||
|
||
this.firstUpdate = false; | ||
} | ||
|
||
/** | ||
* Limit To Range | ||
* | ||
* @param {number} num - Element number. | ||
* @param {number} min - Min element number. | ||
* @param {number} max - Max element number. | ||
* | ||
* @returns {number} | ||
*/ | ||
private limitToRange(num: number, min: number, max: number) { | ||
return Math.max( | ||
Math.min(num, max), | ||
min | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,8 @@ | |
} | ||
|
||
.item { | ||
width: 100% | ||
width: 100%; | ||
height: 40px; | ||
} | ||
.item:hover { | ||
background-color: rgba(0,0,0,0.1); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters