diff --git a/src/custom-types.d.ts b/src/custom-types.d.ts index f0e3afe27..b03aceb85 100644 --- a/src/custom-types.d.ts +++ b/src/custom-types.d.ts @@ -17,13 +17,3 @@ interface AppWindow { interface Window extends AppWindow {} interface ErrorConstructor extends ErrorStackTraceLimit {} - -interface IntersectionObserver { - root: HTMLElement; - rootMargin: string; - thresholds: Array; - disconnect: Function; - observe: Function; - takeRecords: Function; - unobserve: Function; -} diff --git a/src/directives/visibility.directive.ts b/src/directives/visibility.directive.ts index 3ba42176b..bbb7de46c 100644 --- a/src/directives/visibility.directive.ts +++ b/src/directives/visibility.directive.ts @@ -1,9 +1,8 @@ import { - Directive, Output, EventEmitter, ElementRef, - HostBinding, NgZone + Directive, Output, EventEmitter, ElementRef, HostBinding, NgZone } from '@angular/core'; -import { VisibilityObserver } from '../utils'; +import { checkVisibility } from '../utils'; /** * Visibility Observer Directive @@ -12,7 +11,7 @@ import { VisibilityObserver } from '../utils'; * *
+ * (visible)="onVisible($event)"> *
* */ @@ -25,7 +24,7 @@ export class VisibilityDirective { @Output() visible: EventEmitter = new EventEmitter(); constructor(element: ElementRef, zone: NgZone) { - new VisibilityObserver( + checkVisibility( element.nativeElement, this.visbilityChange.bind(this), zone); diff --git a/src/utils/visibility-observer.ts b/src/utils/visibility-observer.ts index 4f37d3ad9..b1ba2d9aa 100644 --- a/src/utils/visibility-observer.ts +++ b/src/utils/visibility-observer.ts @@ -1,100 +1,22 @@ import { NgZone } from '@angular/core'; -/** - * Observes changes to an elements visibility. - * https://medium.com/@amcdnl/javascript-s-new-intersectionobserver-cdce8a73bef8#.evn5twug3 - * - * Example: - * - * var elm = document.getElementById("panda"); - * new VisibilityObserver(elm, function() { - * alert('PAndas rock!'); - * }); - * - */ -export class VisibilityObserver { - - observer: IntersectionObserver; - callback: any; - timeout: any; - - constructor(element: any, callback: any, zone: NgZone) { - this.callback = callback; - - /* - // this is not working... - if(window.IntersectionObserver) { - this.observer = new IntersectionObserver( - this.processChanges.bind(this), { threshold: [0.5] }); - - this.observer.observe(element); - } else { this.runPolyfill(element); } - */ - - this.runPolyfill(element, zone); - } - - runPolyfill(element: any, zone: NgZone) { - let checkVisibility = () => { - const { width, height } = element.getBoundingClientRect(); - - if (width && height) { - clearTimeout(this.timeout); - if(this.callback) { - zone.run(this.callback.bind(this)); - } - } else { - clearTimeout(this.timeout); - zone.runOutsideAngular(() => { - this.timeout = setTimeout(() => checkVisibility(), 50); - }); - } - }; - - checkVisibility(); - } - - isVisible(boundingClientRect, intersectionRect) { - return ((intersectionRect.width * intersectionRect.height) / - (boundingClientRect.width * boundingClientRect.height) >= 0.5); - } - - visibleTimerCallback(element, observer) { - delete element.visibleTimeout; - - // Process any pending observations - this.processChanges(observer.takeRecords()); - - if ('isVisible' in element) { - delete element.isVisible; - if(this.callback) this.callback(); - observer.unobserve(element); +export function checkVisibility(element: any, callback: any, zone: NgZone) { + let timeout; + + function check() { + // https://davidwalsh.name/offsetheight-visibility + const { offsetHeight, offsetWidth } = element; + + if (offsetHeight && offsetWidth) { + clearTimeout(timeout); + if(callback) zone.run(() => callback()); + } else { + clearTimeout(timeout); + zone.runOutsideAngular(() => { + timeout = setTimeout(() => check(), 50); + }); } } - - processChanges(changes) { - changes.forEach((changeRecord) => { - let element = changeRecord.target; - - element.isVisible = this.isVisible( - changeRecord.boundingClientRect, - changeRecord.intersectionRect); - - if ('isVisible' in element) { - // Transitioned from hidden to visible - element.visibleTimeout = setTimeout( - this.visibleTimerCallback.bind(this), - 1000, - element, - this.observer); - } else { - // Transitioned from visible to hidden - if ('visibleTimeout' in element) { - clearTimeout(element.visibleTimeout); - delete element.visibleTimeout; - } - } - }); - } - + + check(); }