c3-tooltipTrigger.ts 3.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. import { Directive, forwardRef, Input, AfterViewInit, ElementRef, ViewContainerRef, OnDestroy, NgZone } from '@angular/core';
  2. import { NG_VALUE_ACCESSOR } from '@angular/forms';
  3. import { C3Tooltip } from './c3-tooltip.component';
  4. import { Overlay, OverlayConfig, ScrollDispatcher, OverlayRef } from '@angular/cdk/overlay';
  5. import { Platform } from '@angular/cdk/platform';
  6. import { TemplatePortal } from '@angular/cdk/portal';
  7. import { coerceBooleanProperty } from '@angular/cdk/coercion';
  8. export const MAT_AUTOCOMPLETE_VALUE_ACCESSOR: any = {
  9. provide: NG_VALUE_ACCESSOR,
  10. useExisting: forwardRef(() => C3TooltipTrigger),
  11. multi: true
  12. };
  13. @Directive({
  14. selector: '[c3Tooltip]',
  15. exportAs: 'c3TooltipTrigger',
  16. providers: [MAT_AUTOCOMPLETE_VALUE_ACCESSOR]
  17. })
  18. export class C3TooltipTrigger implements AfterViewInit, OnDestroy {
  19. overlayRef: OverlayRef | null;
  20. /** The timeout ID of any current timer set to show the tooltip */
  21. _showTimeoutId: number | null;
  22. /** The timeout ID of any current timer set to hide the tooltip */
  23. _hideTimeoutId: number | null;
  24. private _manualListeners = new Map<string, EventListenerOrEventListenerObject>();
  25. private _tooltipClass: string | string[] | Set<string> | { [key: string]: any };
  26. private _tootipDisabled: boolean = false;
  27. @Input('c3Tooltip') tooltip: C3Tooltip;
  28. @Input('c3TooltipDisabled')
  29. get tooltipDisabled(): boolean { return this._tootipDisabled; }
  30. set tooltipDisabled(value: boolean) {
  31. this._tootipDisabled = coerceBooleanProperty(value)
  32. };
  33. @Input('c3TooltipShowDelay') showDelay = 0;
  34. @Input('c3TooltipHideDelay') hideDelay = 0;
  35. @Input('c3TooltipClass')
  36. get tooltipClass() { return this._tooltipClass; }
  37. set tooltipClass(value: string | string[] | Set<string> | { [key: string]: any }) {
  38. this._tooltipClass = value;
  39. if (this.tooltip) {
  40. this.tooltip.tooltipClass = this._tooltipClass;
  41. this.tooltip._markForCheck()
  42. }
  43. }
  44. constructor(
  45. private _element: ElementRef<HTMLElement>,
  46. private _overlay: Overlay,
  47. platform: Platform,
  48. private _ngZone: NgZone,
  49. private _scrollDispatcher: ScrollDispatcher,
  50. private _viewContainerRef: ViewContainerRef) {
  51. if (!platform.IOS && !platform.ANDROID) {
  52. this._manualListeners
  53. .set('mouseenter', () => this.show())
  54. .set('mouseleave', () => this.hide());
  55. }
  56. }
  57. ngAfterViewInit() {
  58. this._manualListeners.forEach((listener, event) => this._element.nativeElement.addEventListener(event, listener));
  59. }
  60. ngOnDestroy() {
  61. this._manualListeners.forEach((listener, event) => {
  62. this._element.nativeElement.removeEventListener(event, listener);
  63. });
  64. this._manualListeners.clear();
  65. }
  66. show(delay: number = this.showDelay) {
  67. if (this.tooltipDisabled) {
  68. return;
  69. }
  70. if (this._hideTimeoutId) {
  71. clearTimeout(this._hideTimeoutId);
  72. this._hideTimeoutId = null;
  73. }
  74. this._showTimeoutId = window.setTimeout(() => {
  75. this._showTimeoutId = null;
  76. const overlayRef = this._overlay.create(this.getOverlayConfig());
  77. const portal = new TemplatePortal(this.tooltip.template, this._viewContainerRef);
  78. overlayRef.attach(portal);
  79. this.overlayRef = overlayRef;
  80. }, delay);
  81. }
  82. hide(delay: number = this.hideDelay) {
  83. if (this._showTimeoutId) {
  84. clearTimeout(this._showTimeoutId);
  85. this._showTimeoutId = null;
  86. }
  87. this._hideTimeoutId = window.setTimeout(() => {
  88. this._hideTimeoutId = null;
  89. if (this.overlayRef && this.overlayRef.hasAttached())
  90. this.overlayRef.detach();
  91. }, delay);
  92. }
  93. private getOverlayConfig(): OverlayConfig {
  94. const positionStrategy = this._overlay.position()
  95. .flexibleConnectedTo(this._element)
  96. .withPositions([{
  97. originX: 'start',
  98. originY: 'top',
  99. overlayX: 'center',
  100. overlayY: 'bottom',
  101. }])
  102. .withViewportMargin(8);
  103. return new OverlayConfig({
  104. positionStrategy
  105. })
  106. }
  107. }