import { Directive , Input , Renderer2 , ElementRef , OnInit , OnDestroy , AfterViewInit , } from "@angular/core" ; import { ScrollService } from "./scroll.service" ; import { Subscription } from "rxjs" ; @ Directive ( { selector : "[animateOnScroll]" , } ) export class AnimateOnScrollDirective implements OnInit , OnDestroy , AfterViewInit { private offsetTop : number ; private isVisible : boolean ; private winHeight : number ; private scrollSub : Subscription = new Subscription ( ) ; private resizeSub : Subscription = new Subscription ( ) ; private get id ( ) : string { return this . elementRef . nativeElement . id ; } @ Input ( ) animationName : string | null ; @ Input ( ) offset : number = 80 ; @ Input ( ) useScroll ? : boolean ; @ Input ( ) threshold ? : number ; constructor ( private elementRef , private renderer , private scroll ) { } ngOnInit ( ) { if ( ! this . animationName ) { return ; } this . isVisible = false ; this . useScroll = this . useScroll ? this . useScroll : this . useScroll === false ? false : true ; this . threshold = this . threshold ? this . threshold || 0.5 : 0.5 ; if ( "IntersectionObserver" in window && this . useScroll ) { const options = { root : null , threshold : this . threshold , rootMargin : "0px" , } ; const observer = new IntersectionObserver ( ( entries , _ ) => { entries . forEach ( ( entry ) => { if ( ! entry . isIntersecting ) { return ; } this . addAnimationClass ( ) ; } ) ; } , options ) ; observer . observe ( this . elementRef . nativeElement ) ; return ; } this . scrollSub = this . scroll . scrollObs . subscribe ( ( ) => this . manageVisibility ( ) ) ; this . resizeSub = this . scroll . resizeObs . subscribe ( ( ) => this . manageVisibility ( ) ) ; } ngAfterViewInit ( ) { setTimeout ( ( ) => this . manageVisibility ( ) , 1 ) ; } ngOnDestroy ( ) { this . scrollSub . unsubscribe ( ) ; this . resizeSub . unsubscribe ( ) ; } returns private manageVisibility ( ) { if ( this . isVisible ) { return ; } this . getWinHeight ( ) ; this . getOffsetTop ( ) ; const scrollTrigger = this . offsetTop + this . offset - this . winHeight ; if ( this . scroll . pos >= scrollTrigger ) { this . addAnimationClass ( ) ; } } returns private addAnimationClass ( ) { if ( ! this . animationName ) { return ; } this . isVisible = true ; this . setClass ( this . animationName ) ; } param { string } classes returns private setClass ( classes ) { for ( const c of classes . split ( " " ) ) { this . renderer . addClass ( this . elementRef . nativeElement , c ) ; } } returns private getWinHeight ( ) { this . winHeight = typeof window !== "undefined" ? window . innerHeight : 0 ; } returns private getOffsetTop ( ) { if ( typeof this . elementRef . nativeElement . getBoundingClientRect === "function" ) { const viewportTop = this . elementRef . nativeElement . getBoundingClientRect ( ) . top ; const clientTop = this . elementRef . nativeElement . clientTop ; this . offsetTop = viewportTop + this . scroll . pos - clientTop ; } else { this . offsetTop = 0 ; } } }