File

projects/i-components/src/lib/components/tooltip-service/tooltip-service.component.ts

Description

ToolTip Service holder component

Implements

OnInit AfterViewInit

Metadata

changeDetection ChangeDetectionStrategy.OnPush
selector wm-tooltip-service
styleUrls ./tooltip-service.component.scss
templateUrl ./tooltip-service.component.html

Index

Properties
Methods
Inputs
HostBindings
Accessors

Constructor

constructor(elementRef: ElementRef, injector: Injector, cd: ChangeDetectorRef)

Creates an instance of ToolTipServiceComponent.

Parameters :
Name Type Optional
elementRef ElementRef No
injector Injector No
cd ChangeDetectorRef No

Inputs

model
Type : ToolTipModel

Input model property

HostBindings

style.left
Type : string
Default value : 'calc(50% - 11em)'

Binding to locate the message on left

style.top
Type : string
Default value : 'calc(50% - 11em)'

Binding to locate the message on top

Methods

Private adjustPositionByMouse
adjustPositionByMouse(targetLeft: number, targetTop: number, thisRect: DOMRect)

Adjust the position to not leave the limits of the screen when the position is handled by mouse position

Parameters :
Name Type Optional
targetLeft number No
targetTop number No
thisRect DOMRect No
Returns : { targetLeft: number; targetTop: number; }
Private adjustPositionHorizontally
adjustPositionHorizontally(targetLeft: number, targetTop: number, thisRect: DOMRect)

Adjust the position to not leave the limits of the screen when the position is handled to the left or to the right

Parameters :
Name Type Optional
targetLeft number No
targetTop number No
thisRect DOMRect No
Returns : { targetLeft: number; targetTop: number; }
Private adjustPositionVertically
adjustPositionVertically(targetLeft: number, targetTop: number, thisRect: DOMRect)

Adjust the position to not leave the limits of the screen when the position is handled to the top or to the bottom

Parameters :
Name Type Optional
targetLeft number No
targetTop number No
thisRect DOMRect No
Returns : { targetLeft: number; targetTop: number; }
assignInjector
assignInjector()

Creates a new custom injector.

Returns : void
Private calculatePosition
calculatePosition()

Calculates the position to be rendered

Returns : void
ngAfterViewInit
ngAfterViewInit()

Angular lifecycle

Returns : void
ngOnInit
ngOnInit()

Angular lifecycle

Returns : void

Properties

customInjector
Type : Injector

Static custom injector to render dynamic components.

left
Type : string
Default value : 'calc(50% - 11em)'
Decorators :
@HostBinding('style.left')

Binding to locate the message on left

model
Type : ToolTipModel
Decorators :
@Input()

Input model property

Public mousePosition
Type : DOMRect
Default value : null

Position of the mouse at the moment of requesting the tooltip service to be displayed

Public ownerTargetRect
Type : DOMRect
Default value : null

Owner element to use as anchor

Public placement
Type : PlacementMode
Default value : PlacementMode.Mouse

Placement to display the tooltip

top
Type : string
Default value : 'calc(50% - 11em)'
Decorators :
@HostBinding('style.top')

Binding to locate the message on top

Accessors

itemToRender
getitemToRender()

Gets the content that should be rendered

Returns : any
import {
  AfterViewInit,
  ChangeDetectionStrategy,
  ChangeDetectorRef,
  Component,
  ElementRef,
  HostBinding,
  Injector,
  Input,
  OnInit,
} from '@angular/core';
import { ToolTipModel, PlacementMode } from '@mobilize/wms-framework';
import { Utils } from '../../utils/utilities';

/**
 * ToolTip Service holder component
 *
 * @export
 * @class ToolTipServiceComponent
 */
@Component({
  selector: 'wm-tooltip-service',
  templateUrl: './tooltip-service.component.html',
  styleUrls: ['./tooltip-service.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ToolTipServiceComponent implements OnInit, AfterViewInit {
  /**
   * Owner element to use as anchor
   *
   * @type {DOMRect}
   * @memberof ToolTipServiceComponent
   */
  public ownerTargetRect: DOMRect = null;

  /**
   * Position of the mouse at the moment of requesting the tooltip service to be displayed
   *
   * @type {DOMRect}
   * @memberof ToolTipServiceComponent
   */
  public mousePosition: DOMRect = null;

  /**
   * Placement to display the tooltip
   *
   * @type {PlacementMode}
   * @memberof ToolTipServiceComponent
   */
  public placement: PlacementMode = PlacementMode.Mouse;

  /**
   * Static custom injector to render dynamic components.
   *
   * @type {Injector}
   * @memberof ToolTipServiceComponent
   */
  customInjector: Injector;

  /**
   * Binding to locate the message on top
   *
   * @memberof ToolTipServiceComponent
   */
  @HostBinding('style.top') top = 'calc(50% - 11em)';

  /**
   * Binding to locate the message on left
   *
   * @memberof ToolTipServiceComponent
   */
  @HostBinding('style.left') left = 'calc(50% - 11em)';

  /**
   * Input model property
   *
   * @type {ToolTipModel}
   * @memberof ToolTipServiceComponent
   */
  @Input()
  model: ToolTipModel;

  /**
   * Creates an instance of ToolTipServiceComponent.
   * @param {ElementRef} elementRef
   * @memberof ToolTipServiceComponent
   */
  constructor(
    private elementRef: ElementRef,
    private injector: Injector,
    private cd: ChangeDetectorRef
  ) {}

  /**
   * Angular lifecycle
   *
   * @memberof ToolTipServiceComponent
   */
  ngOnInit(): void {
    this.assignInjector();
  }

  /**
   * Angular lifecycle
   *
   * @memberof ToolTipServiceComponent
   */
  ngAfterViewInit(): void {
    this.calculatePosition();
    this.cd.markForCheck();
  }

  /**
   * Calculates the position to be rendered
   *
   * @private
   * @memberof ToolTipServiceComponent
   */
  private calculatePosition(): void {
    const thisRect: DOMRect =
      this.elementRef?.nativeElement?.getBoundingClientRect();
    if (!!this.ownerTargetRect && !!this.mousePosition && !!thisRect) {
      //By default lets use the mouse position
      let targetLeft: number = this.mousePosition.right + 15;
      let targetTop: number = this.mousePosition.bottom + 15;
      switch (this.placement) {
        case PlacementMode.Left:
          targetLeft = this.ownerTargetRect.left - thisRect.width - 1;
          targetTop = this.ownerTargetRect.top;
          break;
        case PlacementMode.Right:
          targetLeft = this.ownerTargetRect.right + 1;
          targetTop = this.ownerTargetRect.top;
          break;
        case PlacementMode.Top:
          targetLeft = this.ownerTargetRect.left;
          targetTop = this.ownerTargetRect.top - thisRect.height - 1;
          break;
        case PlacementMode.Bottom:
          targetLeft = this.ownerTargetRect.left;
          targetTop = this.ownerTargetRect.bottom + 1;
          break;
      }

      //Corrections when the mouse position is used are different
      if (this.placement == PlacementMode.Mouse) {
        ({ targetLeft, targetTop } = this.adjustPositionByMouse(
          targetLeft,
          targetTop,
          thisRect
        ));
      } else if (
        this.placement == PlacementMode.Left ||
        this.placement == PlacementMode.Right
      ) {
        ({ targetLeft, targetTop } = this.adjustPositionHorizontally(
          targetLeft,
          targetTop,
          thisRect
        ));
      } else {
        ({ targetLeft, targetTop } = this.adjustPositionVertically(
          targetLeft,
          targetTop,
          thisRect
        ));
      }

      this.top = targetTop + 'px';
      this.left = targetLeft + 'px';
    }
  }

  /**
   * Adjust the position to not leave the limits of the screen when the position is handled by mouse position
   *
   * @private
   * @param {number} targetLeft
   * @param {number} targetTop
   * @param {DOMRect} thisRect
   * @return {*}
   * @memberof ToolTipServiceComponent
   */
  private adjustPositionByMouse(
    targetLeft: number,
    targetTop: number,
    thisRect: DOMRect
  ) {
    const missingRight = window.innerWidth - (targetLeft + thisRect.width);
    if (missingRight < 0) {
      targetLeft += missingRight;
    }

    const missingBottom = window.innerHeight - (targetTop + thisRect.height);
    if (missingBottom < 0) {
      targetTop += missingBottom;
    }
    return { targetLeft, targetTop };
  }

  /**
   * Adjust the position to not leave the limits of the screen when the position is handled to the left or to the right
   *
   * @private
   * @param {number} targetLeft
   * @param {number} targetTop
   * @param {DOMRect} thisRect
   * @return {*}
   * @memberof ToolTipServiceComponent
   */
  private adjustPositionHorizontally(
    targetLeft: number,
    targetTop: number,
    thisRect: DOMRect
  ) {
    //Message will be hidden on the right and there is enough room on the left then we move it to the left
    if (
      targetLeft + thisRect.width > window.innerWidth &&
      this.ownerTargetRect.left - thisRect.width - 1 > 0
    ) {
      targetLeft = this.ownerTargetRect.left - thisRect.width - 1;
    }
    //Message will be hidden on the left and there is enough room on the right then we move it to the right
    if (
      targetLeft < 0 &&
      this.ownerTargetRect.right + thisRect.width + 1 < window.innerWidth
    ) {
      targetLeft = this.ownerTargetRect.right + 1;
    }

    //Message will be hidden on the top so we just adjust to the 0 position
    if (targetTop < 0) {
      targetTop = 0;
    }

    //Messsage will be hidden at the bottom so we just adjust to above the bottom
    const missingBottom = window.innerHeight - (targetTop + thisRect.height);
    if (missingBottom < 0) {
      targetTop += missingBottom;
    }
    return { targetLeft, targetTop };
  }

  /**
   * Adjust the position to not leave the limits of the screen when the position is handled to the top or to the bottom
   *
   * @private
   * @param {number} targetLeft
   * @param {number} targetTop
   * @param {DOMRect} thisRect
   * @return {*}
   * @memberof ToolTipServiceComponent
   */
  private adjustPositionVertically(
    targetLeft: number,
    targetTop: number,
    thisRect: DOMRect
  ) {
    //Message will be hidden on the right so we just adjust it to the right edge
    const missingRight = window.innerWidth - (targetLeft + thisRect.width);
    if (missingRight < 0) {
      targetLeft += missingRight;
    }

    //Message will be hidden on the left so we just adjust it to the left edge
    if (targetLeft < 0) {
      targetLeft = 0;
    }

    //Message will be hidden on the top and there is enough room on the bottom then we move it to the bottom
    if (
      targetTop < 0 &&
      this.ownerTargetRect.bottom + thisRect.height + 1 < window.innerHeight
    ) {
      targetTop = this.ownerTargetRect.bottom + 1;
    }

    //Messsage will be hidden at the bottom and there is enough room on the top then we move it to the top
    if (
      targetTop + thisRect.height > window.innerHeight &&
      this.ownerTargetRect.top - thisRect.height - 1 > 0
    ) {
      targetTop = this.ownerTargetRect.top - thisRect.height - 1;
    }
    return { targetLeft, targetTop };
  }

  /**
   * Creates a new custom injector.
   *
   * @memberof ToolTipServiceComponent
   */
  assignInjector(): void {
    this.customInjector = Utils.createInjectorForDynamicComponent(
      this.model,
      this.injector
    );
  }

  /**
   * Gets the content that should be rendered
   *
   * @readonly
   * @memberof ToolTipServiceComponent
   */
  get itemToRender(): any {
    if (!this.model) return undefined;
    return { component: Utils.resolveComponentType(this.model) };
  }
}
<div class="tooltip-container">
  <ng-container *ngIf="itemToRender">
    <ng-container
      *ngComponentOutlet="itemToRender.component; injector: customInjector"
    ></ng-container>
  </ng-container>
</div>

./tooltip-service.component.scss

@import '../../scss/variables';

:host {
  position: fixed;
  box-shadow: 1px 1px #888888;
  height: auto;
  width: auto;
  z-index: $tooltip-z-index;
}
Legend
Html element
Component
Html element with directive

result-matching ""

    No results matching ""