import { ElementRef , Injectable , OnDestroy } from '@angular/core' ; import { debounceTime } from 'rxjs/operators' ; import { Subject , Subscription } from 'rxjs' ; import { ScrollService } from '../../services/ux/scroll' ; @ Injectable ( ) export class ElementVisibilityService implements OnDestroy { protected element : HTMLElement ; protected entity ; protected visibilitySubscription : Subscription ; protected visibility$ : Subject < boolean > = new Subject ( ) ; protected scrollSubscription : Subscription ; protected visible : boolean = false ; protected onViewFn : ( entity ) => void ; protected enabled : boolean = true ; constructor ( protected scroll ) { this . init ( ) ; } setElementRef ( elementRef ) { this . element = ( elementRef && elementRef . nativeElement ) || void 0 ; return this ; } setEntity ( entity ) { this . entity = entity || void 0 ; return this ; } onView ( fn ) { this . onViewFn = fn ; return this ; } setEnabled ( enabled ) { this . enabled = enabled ; return this ; } init ( ) { this . visibilitySubscription = this . visibility$ . subscribe ( ( ) => { if ( this . entity && this . visible ) { this . scroll . unListen ( this . scrollSubscription ) ; if ( this . onViewFn ) { this . onViewFn ( this . entity ) ; } else { console . warn ( 'Missing onView handler for Activity' ) ; } } } ) ; this . scrollSubscription = this . scroll . listenForView ( ) . subscribe ( ( ) => { this . checkVisibility ( ) ; } ) ; } checkVisibility ( ) { if ( ! this . element ) { return ; } if ( ! this . element . offsetHeight || ! this . enabled ) { return ; } const top = this . element . offsetTop ; const bottom = top + this . element . offsetHeight ; const vpTop = this . scroll . view . scrollTop ; const vpBottom = vpTop + this . scroll . view . clientHeight ; const totalH = Math . max ( bottom , vpBottom ) - Math . min ( top , vpTop ) ; const vpComp = totalH - this . scroll . view . clientHeight ; const vpEl = this . element . offsetHeight - vpComp ; const visible = vpEl <= 0 ? 0 : vpEl / this . element . offsetHeight ; if ( visible > 0 && ! this . visible ) { this . visible = true ; this . visibility$ . next ( this . visible ) ; } else { this . visible = false ; } } ngOnDestroy ( ) { this . scroll . unListen ( this . scrollSubscription ) ; if ( this . visibilitySubscription ) { this . visibilitySubscription . unsubscribe ( ) ; } } }