103 lines
2.9 KiB
TypeScript
103 lines
2.9 KiB
TypeScript
import {AfterViewInit, Component, Input, ViewEncapsulation} from "@angular/core";
|
|
|
|
|
|
/**
|
|
* <section-scroll [customClass]="'optional classes for section e.g. uk-section-primary'"
|
|
* [childrenCustomClass]="'optional classes for content e.g. uk-container'">
|
|
* <div top>...</div>
|
|
* <div left>...</div>
|
|
* <div scroll>...</div>
|
|
* </section-scroll>
|
|
*
|
|
* */
|
|
@Component({
|
|
selector: 'section-scroll',
|
|
template: `
|
|
<div [ngClass]="customClass">
|
|
<ng-content select="[top]"></ng-content>
|
|
<div [ngClass]="childrenCustomClass">
|
|
<div class="uk-grid" uk-grid>
|
|
<ng-content select="[left]"></ng-content>
|
|
<ng-content select="[scroll]"></ng-content>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`,
|
|
styleUrls: ['section-scroll.component.css'],
|
|
encapsulation: ViewEncapsulation.None
|
|
})
|
|
export class SectionScrollComponent implements AfterViewInit {
|
|
|
|
@Input()
|
|
public customClass = null;
|
|
@Input()
|
|
public childrenCustomClass = null;
|
|
@Input()
|
|
public animationSteps: number = 20;
|
|
private observer: IntersectionObserver = null;
|
|
/**
|
|
* Define as keys the ids of elements in scroll section and as values the ids of left section
|
|
* */
|
|
@Input()
|
|
private map: Map<string, string> = null;
|
|
private left: Map<string, HTMLElement> = new Map<string, HTMLElement>();
|
|
private scroll: Map<string, HTMLElement> = new Map<string, HTMLElement>();
|
|
private lastElementId: string = null;
|
|
|
|
constructor() {
|
|
}
|
|
|
|
ngOnDestroy() {
|
|
if (this.observer) {
|
|
this.observer.disconnect();
|
|
}
|
|
}
|
|
|
|
ngAfterViewInit() {
|
|
if (typeof document !== "undefined" && this.map) {
|
|
this.createObserver();
|
|
}
|
|
}
|
|
|
|
createObserver() {
|
|
let observer;
|
|
let options = {
|
|
root: null,
|
|
rootMargin: "-20%",
|
|
threshold: this.buildThresholdList()
|
|
};
|
|
Array.from(this.map.values()).forEach(value => {
|
|
let element = document.getElementById(value);
|
|
this.left.set(value, element);
|
|
})
|
|
Array.from(this.map.keys()).forEach(key => {
|
|
this.scroll.set(key, document.getElementById(key));
|
|
})
|
|
observer = new IntersectionObserver(entries => {
|
|
entries.forEach((entry) => {
|
|
entry.target['style'].opacity = String(entry.intersectionRatio);
|
|
let id = this.map.get(entry.target.id);
|
|
if (this.left.has(id) && this.lastElementId !== id) {
|
|
if(entry.isIntersecting) {
|
|
this.lastElementId = id;
|
|
}
|
|
this.left.get(id).parentElement.style.opacity = String(entry.intersectionRatio);
|
|
}
|
|
});
|
|
}, options);
|
|
Array.from(this.scroll.values()).forEach(target => {
|
|
observer.observe(target)
|
|
});
|
|
}
|
|
|
|
buildThresholdList() {
|
|
let thresholds = [];
|
|
for (let i = 1.0; i <= this.animationSteps; i++) {
|
|
let ratio = i / this.animationSteps;
|
|
thresholds.push(ratio);
|
|
}
|
|
thresholds.push(0);
|
|
return thresholds;
|
|
}
|
|
}
|