import { Component , Input , AfterViewInit , ElementRef , ChangeDetectorRef } from '@angular/core' ; @ Component ( { selector : 'tooltip-content' , templateUrl : './tooltip-content.component.html' , styleUrls : [ './tooltip-content.component.css' ] , } ) export class TooltipContentComponent implements AfterViewInit { @ Input ( ) hostElement : HTMLElement ; @ Input ( ) content : string ; @ Input ( ) placement : 'top' | 'bottom' | 'left' | 'right' = 'bottom' ; @ Input ( ) animation : boolean = true ; top : number = - 100000 ; left : number = - 100000 ; isIn : boolean = false ; isFade : boolean = false ; constructor ( private element , private cdr ) { } ngAfterViewInit ( ) { this . show ( ) ; this . cdr . detectChanges ( ) ; } show ( ) { if ( ! this . hostElement ) return ; const p = this . positionElements ( this . hostElement , this . element . nativeElement . children [ 0 ] , this . placement ) ; this . top = p . top ; this . left = p . left ; this . isIn = true ; if ( this . animation ) this . isFade = true ; } hide ( ) { this . top = - 100000 ; this . left = - 100000 ; this . isIn = true ; if ( this . animation ) this . isFade = false ; } private positionElements ( hostEl , targetEl , positionStr , appendToBody = false ) { let positionStrParts = positionStr . split ( '-' ) ; let pos0 = positionStrParts [ 0 ] ; let pos1 = positionStrParts [ 1 ] || 'center' ; let hostElPos = appendToBody ? this . offset ( hostEl ) : this . position ( hostEl ) ; let targetElWidth = targetEl . offsetWidth ; let targetElHeight = targetEl . offsetHeight ; let shiftWidth = { center : function ( ) : number { return hostElPos . left + hostElPos . width / 2 - targetElWidth / 2 ; } , left : function ( ) : number { return hostElPos . left ; } , right : function ( ) : number { return hostElPos . left + hostElPos . width ; } , } ; let shiftHeight = { center : function ( ) : number { return hostElPos . top + hostElPos . height / 2 - targetElHeight / 2 ; } , top : function ( ) : number { return hostElPos . top ; } , bottom : function ( ) : number { return hostElPos . top + hostElPos . height ; } , } ; let targetElPos ; switch ( pos0 ) { case 'right' : targetElPos = { top : shiftHeight [ pos1 ] ( ) , left : shiftWidth [ pos0 ] ( ) , } ; break ; case 'left' : targetElPos = { top : shiftHeight [ pos1 ] ( ) , left : hostElPos . left - targetElWidth , } ; break ; case 'bottom' : targetElPos = { top : shiftHeight [ pos0 ] ( ) , left : shiftWidth [ pos1 ] ( ) , } ; break ; default : targetElPos = { top : hostElPos . top - targetElHeight , left : shiftWidth [ pos1 ] ( ) , } ; break ; } return targetElPos ; } private position ( nativeEl ) { let offsetParentBCR = { top : 0 , left : 0 } ; const elBCR = this . offset ( nativeEl ) ; const offsetParentEl = this . parentOffsetEl ( nativeEl ) ; if ( offsetParentEl !== window . document ) { offsetParentBCR = this . offset ( offsetParentEl ) ; offsetParentBCR . top += offsetParentEl . clientTop - offsetParentEl . scrollTop ; offsetParentBCR . left += offsetParentEl . clientLeft - offsetParentEl . scrollLeft ; } const boundingClientRect = nativeEl . getBoundingClientRect ( ) ; return { width : boundingClientRect . width || nativeEl . offsetWidth , height : boundingClientRect . height || nativeEl . offsetHeight , top : elBCR . top - offsetParentBCR . top , left : elBCR . left - offsetParentBCR . left , } ; } private offset ( nativeEl ) { const boundingClientRect = nativeEl . getBoundingClientRect ( ) ; return { width : boundingClientRect . width || nativeEl . offsetWidth , height : boundingClientRect . height || nativeEl . offsetHeight , top : boundingClientRect . top + ( window . pageYOffset || window . document . documentElement . scrollTop ) , left : boundingClientRect . left + ( window . pageXOffset || window . document . documentElement . scrollLeft ) , } ; } private getStyle ( nativeEl , cssProp ) { if ( ( nativeEl as any ) . currentStyle ) return ( nativeEl as any ) . currentStyle [ cssProp ] ; if ( window . getComputedStyle ) return ( window . getComputedStyle ( nativeEl ) as any ) [ cssProp ] ; return ( nativeEl . style as any ) [ cssProp ] ; } private isStaticPositioned ( nativeEl ) { return ( this . getStyle ( nativeEl , 'position' ) || 'static' ) === 'static' ; } private parentOffsetEl ( nativeEl ) { let offsetParent = nativeEl . offsetParent || window . document ; while ( offsetParent && offsetParent !== window . document && this . isStaticPositioned ( offsetParent ) ) { offsetParent = offsetParent . offsetParent ; } return offsetParent || window . document ; } }