/*-------------------------------------------------------------------------------------------------------------- * Copyright (c) insite-gmbh. All rights reserved. * Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------------------------*/ import { Directive, ElementRef, Renderer, EventEmitter, Input, Output, Inject, OnInit, DoCheck } from '@angular/core'; import { Rect } from './rect'; import { InViewInfo } from './inViewInfo'; import * as _ from 'underscore'; @Directive({ selector: '[inaxInView]' }) export class InViewDirective implements OnInit, DoCheck { private _initialCall: boolean = true; private _lastInfo: any = null; @Output() onInView: EventEmitter = new EventEmitter(); @Input('inaxInView') inViewId: string = ""; @Input('inaxInViewOptions') options: any = {}; constructor(private el: ElementRef) {} ngOnInit() { if (!this.options) { this.options = {}; } if (this.options.hasOwnProperty('offset')) { this.options.offset = this.normalizeOffset(this.options.offset); } else { this.options.offset = [0, 0, 0, 0]; } if (this.options.hasOwnProperty('viewportOffset')) { this.options.viewportOffset = this.normalizeOffset(this.options.viewportOffset); } else { this.options.viewportOffset = [0, 0, 0, 0]; } if (!this.options.hasOwnProperty('generateDirection')) { this.options.generateDirection = false; } console.log(this.options); } ngDoCheck() { this.onCheckInView(); } onCheckInView() { let newInfo = this.calcInfo(); if (this._lastInfo) { // Add inview direction info if (newInfo.inView && this._lastInfo.elementRect && this.options.generateDirection) { newInfo.directionHorizontal = newInfo.elementRect.left - this._lastInfo.elementRect.left; newInfo.directionVertical = newInfo.elementRect.top - this._lastInfo.elementRect.top } // Calculate changed flag newInfo.changed = newInfo.inView !== this._lastInfo.inView; } if ((this._initialCall && newInfo.inView) || newInfo.changed || newInfo.directionVertical !== this._lastInfo.directionVertical || newInfo.directionHorizontal !== this._lastInfo.directionHorizontal) { // Execute in-view callback this.onInView.emit(newInfo); this._lastInfo = newInfo; this._initialCall = false; } } private calcInfo(): InViewInfo { let info = new InViewInfo(); info.id = this.inViewId; info.viewportRect = this.getViewportRect().offsetRect(this.options.viewportOffset); info.elementRect = this.getBoundingClientRect().offsetRect(this.options.offset); let isVisible = !!(this.el.nativeElement.offsetWidth || this.el.nativeElement.offsetHeight || this.el.nativeElement.getClientRects().length); info.inView = isVisible && info.elementRect.intersectRect(info.viewportRect); info.element = this.el; return info; } private normalizeOffset(offset: any): any { if (!_.isArray(offset)) { return [offset, offset, offset, offset]; } if (offset.length == 2) { return offset.concat(offset); } else if (offset.length == 3) { return offset.concat([offset[1]]); } return offset; } private getViewportRect(): Rect { if (window.innerHeight) { return new Rect(0, 0, window.innerWidth, window.innerHeight); } var mode = document.compatMode; if (mode === 'CSS1Compat') { return new Rect(0, 0, document.documentElement.clientWidth, document.documentElement.clientHeight); } return new Rect(0, 0, document.body.clientWidth, document.body.clientHeight); } private getBoundingClientRect(): Rect { let boundingNativeElRect = this.el.nativeElement.getBoundingClientRect(); return new Rect(boundingNativeElRect.left, boundingNativeElRect.top, boundingNativeElRect.width, boundingNativeElRect.height); } }