Skip to content

Commit

Permalink
Fix #268
Browse files Browse the repository at this point in the history
  • Loading branch information
amcdnl committed Nov 9, 2016
1 parent 5b90052 commit a07d2f7
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 110 deletions.
10 changes: 0 additions & 10 deletions src/custom-types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,3 @@ interface AppWindow {
interface Window extends AppWindow {}

interface ErrorConstructor extends ErrorStackTraceLimit {}

interface IntersectionObserver {
root: HTMLElement;
rootMargin: string;
thresholds: Array<number>;
disconnect: Function;
observe: Function;
takeRecords: Function;
unobserve: Function;
}
9 changes: 4 additions & 5 deletions src/directives/visibility.directive.ts
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -12,7 +11,7 @@ import { VisibilityObserver } from '../utils';
*
* <div
* visibility-observer
* (onVisibilityChange)="doSomething($event)">
* (visible)="onVisible($event)">
* </div>
*
*/
Expand All @@ -25,7 +24,7 @@ export class VisibilityDirective {
@Output() visible: EventEmitter<any> = new EventEmitter();

constructor(element: ElementRef, zone: NgZone) {
new VisibilityObserver(
checkVisibility(
element.nativeElement,
this.visbilityChange.bind(this),
zone);
Expand Down
112 changes: 17 additions & 95 deletions src/utils/visibility-observer.ts
Original file line number Diff line number Diff line change
@@ -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();
}

0 comments on commit a07d2f7

Please sign in to comment.