Touch

Angular Bootstrap 5 Touch

Use native Pointer Events to handle pinch, swipe, tap, press, pan, and rotate gestures without an additional gesture library.

Note: Read the API tab to find all available options and advanced customization

Note: Pointer Events support touch, pen, and mouse input. Add an equivalent keyboard action when the gesture performs an action that keyboard users also need.


Configuration

Angular 22 no longer provides the deprecated HammerJS integration. The examples on this page use the following standalone directive to translate native Pointer Events into gesture events. No additional package is required.

        
            
            import {
              Directive,
              ElementRef,
              EventEmitter,
              HostBinding,
              HostListener,
              Input,
              OnDestroy,
              Output,
            } from '@angular/core';

            interface PointerState {
              startX: number;
              startY: number;
              x: number;
              y: number;
              startTime: number;
            }

            interface PanEvent {
              deltaX: number;
              deltaY: number;
              preventDefault: () => void;
            }

            @Directive({
              selector: '[mdbPointerGestures]',
              standalone: true,
            })
            export class PointerGesturesDirective implements OnDestroy {
              @Input() pressDuration = 250;
              @Input() doubleTapInterval = 500;
              @Input() tapMaxDistance = 10;
              @Input() swipeThreshold = 50;
              @Input() swipeMaxDuration = 500;

              @Output() press = new EventEmitter<void>();
              @Output() tap = new EventEmitter<{ x: number; y: number }>();
              @Output() doubleTap = new EventEmitter<{ x: number; y: number }>();
              @Output() panstart = new EventEmitter<void>();
              @Output() panmove = new EventEmitter<PanEvent>();
              @Output() panleft = new EventEmitter<PanEvent>();
              @Output() panright = new EventEmitter<PanEvent>();
              @Output() panup = new EventEmitter<PanEvent>();
              @Output() pandown = new EventEmitter<PanEvent>();
              @Output() pinch = new EventEmitter<{
                ratio: number;
                origin: { x: number; y: number };
              }>();
              @Output() swipeleft = new EventEmitter<void>();
              @Output() swiperight = new EventEmitter<void>();
              @Output() swipeup = new EventEmitter<void>();
              @Output() swipedown = new EventEmitter<void>();
              @Output() rotate = new EventEmitter<{ currentAngle: number }>();

              @HostBinding('style.touch-action') touchAction = 'none';

              private pointers = new Map<number, PointerState>();
              private pressTimer: ReturnType<typeof setTimeout> | undefined;
              private pressFired = false;
              private panStarted = false;
              private lastTapTime = 0;
              private initialPinchDistance = 0;
              private initialRotation = 0;

              constructor(private elementRef: ElementRef<HTMLElement>) {}

              @HostListener('pointerdown', ['$event'])
              onPointerDown(event: PointerEvent): void {
                if (event.pointerType === 'mouse' && event.button !== 0) {
                  return;
                }

                this.elementRef.nativeElement.setPointerCapture(event.pointerId);
                this.pointers.set(event.pointerId, {
                  startX: event.clientX,
                  startY: event.clientY,
                  x: event.clientX,
                  y: event.clientY,
                  startTime: event.timeStamp,
                });

                if (this.pointers.size === 1) {
                  this.pressFired = false;
                  this.panStarted = false;
                  this.pressTimer = setTimeout(() => {
                    this.pressFired = true;
                    this.press.emit();
                  }, this.pressDuration);
                } else if (this.pointers.size === 2) {
                  this.cancelPress();
                  const [first, second] = Array.from(this.pointers.values());
                  this.initialPinchDistance = this.getDistance(first, second);
                  this.initialRotation = this.getAngle(first, second);
                }
              }

              @HostListener('pointermove', ['$event'])
              onPointerMove(event: PointerEvent): void {
                const pointer = this.pointers.get(event.pointerId);

                if (!pointer) {
                  return;
                }

                pointer.x = event.clientX;
                pointer.y = event.clientY;

                if (this.pointers.size === 2) {
                  this.emitTwoPointerGestures();
                  return;
                }

                const deltaX = pointer.x - pointer.startX;
                const deltaY = pointer.y - pointer.startY;

                if (Math.hypot(deltaX, deltaY) > this.tapMaxDistance) {
                  this.cancelPress();
                }

                if (!this.panStarted) {
                  this.panStarted = true;
                  this.panstart.emit();
                }

                const panEvent: PanEvent = {
                  deltaX,
                  deltaY,
                  preventDefault: () => event.preventDefault(),
                };

                event.preventDefault();
                this.panmove.emit(panEvent);

                if (Math.abs(deltaX) >= Math.abs(deltaY)) {
                  deltaX < 0 ? this.panleft.emit(panEvent) : this.panright.emit(panEvent);
                } else {
                  deltaY < 0 ? this.panup.emit(panEvent) : this.pandown.emit(panEvent);
                }
              }

              @HostListener('pointerup', ['$event'])
              onPointerUp(event: PointerEvent): void {
                const pointer = this.pointers.get(event.pointerId);

                if (!pointer) {
                  return;
                }

                pointer.x = event.clientX;
                pointer.y = event.clientY;
                this.cancelPress();

                if (this.pointers.size === 1) {
                  this.emitTap(pointer, event);
                  this.emitSwipe(pointer, event);
                }

                this.removePointer(event.pointerId);
              }

              @HostListener('pointercancel', ['$event'])
              onPointerCancel(event: PointerEvent): void {
                this.cancelPress();
                this.removePointer(event.pointerId);
              }

              ngOnDestroy(): void {
                this.cancelPress();
              }

              private emitTap(pointer: PointerState, event: PointerEvent): void {
                const distance = Math.hypot(
                  event.clientX - pointer.startX,
                  event.clientY - pointer.startY
                );

                if (this.pressFired || distance > this.tapMaxDistance) {
                  return;
                }

                const origin = { x: event.clientX, y: event.clientY };
                const timeSinceLastTap = event.timeStamp - this.lastTapTime;

                this.tap.emit(origin);

                if (timeSinceLastTap > 0 && timeSinceLastTap <= this.doubleTapInterval) {
                  this.doubleTap.emit(origin);
                  this.lastTapTime = 0;
                } else {
                  this.lastTapTime = event.timeStamp;
                }
              }

              private emitSwipe(pointer: PointerState, event: PointerEvent): void {
                const deltaX = event.clientX - pointer.startX;
                const deltaY = event.clientY - pointer.startY;
                const duration = event.timeStamp - pointer.startTime;

                if (
                  duration > this.swipeMaxDuration ||
                  Math.max(Math.abs(deltaX), Math.abs(deltaY)) < this.swipeThreshold
                ) {
                  return;
                }

                if (Math.abs(deltaX) >= Math.abs(deltaY)) {
                  deltaX < 0 ? this.swipeleft.emit() : this.swiperight.emit();
                } else {
                  deltaY < 0 ? this.swipeup.emit() : this.swipedown.emit();
                }
              }

              private emitTwoPointerGestures(): void {
                const [first, second] = Array.from(this.pointers.values());
                const distance = this.getDistance(first, second);
                const angle = this.getAngle(first, second);
                const bounds = this.elementRef.nativeElement.getBoundingClientRect();

                if (this.initialPinchDistance > 0) {
                  this.pinch.emit({
                    ratio: distance / this.initialPinchDistance,
                    origin: {
                      x: (first.x + second.x) / 2 - bounds.left,
                      y: (first.y + second.y) / 2 - bounds.top,
                    },
                  });
                }
                this.rotate.emit({ currentAngle: (angle - this.initialRotation) / 360 });
              }

              private getDistance(first: PointerState, second: PointerState): number {
                return Math.hypot(first.x - second.x, first.y - second.y);
              }

              private getAngle(first: PointerState, second: PointerState): number {
                return Math.atan2(second.y - first.y, second.x - first.x) * (180 / Math.PI);
              }

              private cancelPress(): void {
                clearTimeout(this.pressTimer);
                this.pressTimer = undefined;
              }

              private removePointer(pointerId: number): void {
                if (this.elementRef.nativeElement.hasPointerCapture(pointerId)) {
                  this.elementRef.nativeElement.releasePointerCapture(pointerId);
                }

                this.pointers.delete(pointerId);

                if (this.pointers.size === 0) {
                  this.panStarted = false;
                  this.initialPinchDistance = 0;
                  this.initialRotation = 0;
                }
              }
            }
          
        
    
        
            
            import { Component } from '@angular/core';
            import { PointerGesturesDirective } from './pointer-gestures.directive';

            @Component({
              selector: 'app-root',
              imports: [PointerGesturesDirective],
              templateUrl: './app.component.html',
            })
            export class AppComponent {}
          
        
    

Press

Press calls the chosen method when the pointer remains down on the element for more than 250 milliseconds.

Hold the button to remove the mask from the image

        
            
            <div>
              <div class="bg-image">
                <img src="https://mdbootstrap.com/img/new/standard/city/053.webp" class="img-fluid" />
                @if (showMask) {
                  <div
                    class="mask"
                    style="background-color: rgba(0, 0, 0, 0.6)"
                    id="remove-bg"
                  >
                    <div class="d-flex justify-content-center align-items-center h-100">
                      <p id="press-text" class="text-white mb-0">
                        Hold the button to remove the mask from the image
                      </p>
                    </div>
                  </div>
                }
              </div>
              <div class="my-3">
                <button
                  mdbPointerGestures
                  type="button"
                  class="btn btn-primary btn-press"
                  (press)="onPress()"
                >
                  Tap & hold to show image
                </button>
              </div>
            </div>
          
        
    
        
            
            import { Component } from '@angular/core';

            @Component({
              selector: 'app-root',
              templateUrl: './app.component.html',
              styleUrls: ['./app.component.scss'],
            })
            export class AppComponent {
              showMask = true;

              constructor() {}

              onPress() {
                this.showMask = false;
              }
            }
          
        
    

Press duration

Set the pressDuration input to change the default press duration.

Hold the button for 5s to remove mask from the image

        
            
              <div>
                <div class="bg-image">
                  <img src="https://mdbootstrap.com/img/new/standard/city/053.webp" class="img-fluid" />
                  @if (showMask) {
                    <div
                      class="mask"
                      style="background-color: rgba(0, 0, 0, 0.6)"
                      id="remove-bg"
                    >
                      <div class="d-flex justify-content-center align-items-center h-100">
                        <p id="press-text" class="text-white mb-0">
                          Hold the button for 5s to remove mask from the imag
                        </p>
                      </div>
                    </div>
                  }
                </div>
                <div class="my-3">
                  <button
                    mdbPointerGestures
                    type="button"
                    class="btn btn-primary btn-press"
                    [pressDuration]="5000"
                    (press)="onPress()"
                  >
                    Tap & hold to show image
                  </button>
                </div>
              </div>
            
        
    
        
            
              import { Component } from '@angular/core';

              @Component({
                selector: 'app-root',
                templateUrl: './app.component.html',
                styleUrls: ['./app.component.scss'],
              })
              export class AppComponent {
                showMask = true;

                constructor() {}

                onPress() {
                  this.showMask = false;
                }
              }
            
        
    

Tap

The callback on tap event is called with an object containing origin field - the x and y coordinates of the user's touch.

Tap button to change a color

        
            
            <div>
              <div class="bg-image">
                <img src="https://mdbootstrap.com/img/new/standard/city/053.webp" class="img-fluid" />
                <div class="mask" [ngStyle]="{ 'background-color': background }" id="bg-tap">
                  <div class="d-flex justify-content-center align-items-center h-100">
                    <p class="text-white mb-0">Tap button to change a color</p>
                  </div>
                </div>
              </div>
              <div class="my-3">
                <button
                  mdbPointerGestures
                  type="button"
                  class="btn btn-primary btn-tap"
                  (tap)="onTap()"
                >
                  Tap to change a color
                </button>
              </div>
            </div>
          
        
    
        
            
            import { Component } from '@angular/core';

            @Component({
              selector: 'app-root',
              templateUrl: './app.component.html',
              styleUrls: ['./app.component.scss'],
            })
            export class AppComponent {
              background = 'rgba(0, 0, 0, 0.6)';

              constructor() {}

              generateColor(): string {
                return `rgba(${this.getRandomNumber()},${this.getRandomNumber()},${this.getRandomNumber()},.4)`;
              }

              getRandomNumber(): number {
                return Math.floor(Math.random() * 255) + 1;
              }

              onTap() {
                this.background = this.generateColor();
              }
            }
          
        
    

Double Tap

Set default taps to touch event.

Change background color with 2 taps

        
            
              <div>
                <div class="bg-image">
                  <img src="https://mdbootstrap.com/img/new/standard/city/053.webp" class="img-fluid" />
                  <div class="mask" [ngStyle]="{ 'background-color': background }" id="bg-tap">
                    <div class="d-flex justify-content-center align-items-center h-100">
                      <p class="text-white mb-0">Tap button to change a color</p>
                    </div>
                  </div>
                </div>
                <div class="my-3">
                  <button
                    mdbPointerGestures
                    type="button"
                    class="btn btn-primary btn-tap"
                    (doubleTap)="onTap()"
                  >
                    Tap to change a color
                  </button>
                </div>
              </div>
            
        
    
        
            
              import { Component } from '@angular/core';

              @Component({
                selector: 'app-root',
                templateUrl: './app.component.html',
                styleUrls: ['./app.component.scss'],
              })
              export class AppComponent {
                background = 'rgba(0, 0, 0, 0.6)';

                constructor() {}

                generateColor(): string {
                  return `rgba(${this.getRandomNumber()},${this.getRandomNumber()},${this.getRandomNumber()},.4)`;
                }

                getRandomNumber(): number {
                  return Math.floor(Math.random() * 255) + 1;
                }

                onTap() {
                  this.background = this.generateColor();
                }
              }
            
        
    

Pan

The pan event is useful for dragging elements. While the pointer moves, the directive emits the horizontal and vertical distance from its starting position.

        
            
            <div>
              <div class="bg-image" id="pan">
                <img
                  mdbPointerGestures
                  [ngStyle]="{ transform: panTransform }"
                  (panstart)="onPanStart()"
                  (panmove)="onPanMove($event)"
                  src="https://mdbootstrap.com/img/new/standard/city/053.webp"
                  class="img-fluid"
                  id="img-pan"
                />
              </div>
            </div>
          
        
    
        
            
            import { Component } from '@angular/core';

            @Component({
              selector: 'app-root',
              templateUrl: './app.component.html',
              styleUrls: ['./app.component.scss'],
            })
            export class AppComponent {
              x = 0;
              y = 0;
              startX = 0;
              startY = 0;

              panTransform: string;

              constructor() {}

              onPanStart() {
                this.startX = this.x;
                this.startY = this.y;
              }

              onPanMove(event: any) {
                event.preventDefault();
                this.x = this.startX + event.deltaX;
                this.y = this.startY + event.deltaY;
                this.panTransform = this.getTransform(this.x, this.y);
              }

              getTransform(x: number, y: number): string {
                return `translate(${x}px, ${y}px)`;
              }
            }
          
        
    

Pan Left

Pan with only left direction

        
            
              <div>
                <div class="bg-image" id="pan">
                  <img
                    mdbPointerGestures
                    [ngStyle]="{ transform: panTransform }"
                    (panstart)="onPanStart()"
                    (panleft)="onPanLeft($event)"
                    src="https://mdbootstrap.com/img/new/standard/city/053.webp"
                    class="img-fluid"
                    id="img-pan"
                  />
                </div>
              </div>
            
        
    
        
            
              import { Component } from '@angular/core';

              @Component({
                selector: 'app-root',
                templateUrl: './app.component.html',
                styleUrls: ['./app.component.scss'],
              })
              export class AppComponent {
                x = 0;
                y = 0;
                startX = 0;
                startY = 0;
                panTransform: string;

                constructor() {}

                onPanStart() {
                  this.startX = this.x;
                  this.startY = this.y;
                }

                onPanLeft(event: any) {
                  event.preventDefault();
                  this.x = this.startX + event.deltaX;
                  this.panTransform = this.getTransform(this.x, 0);
                }

                getTransform(x: number, y: number): string {
                  return `translate(${x}px, ${y}px)`;
                }
              }
            
        
    

Pan Right

Pan with only right direction

        
            
              <div>
                <div class="bg-image" id="pan">
                  <img
                    mdbPointerGestures
                    [ngStyle]="{ transform: panTransform }"
                    (panstart)="onPanStart()"
                    (panright)="onPanRight($event)"
                    src="https://mdbootstrap.com/img/new/standard/city/053.webp"
                    class="img-fluid"
                    id="img-pan"
                  />
                </div>
              </div>
            
        
    
        
            
              import { Component } from '@angular/core';

              @Component({
                selector: 'app-root',
                templateUrl: './app.component.html',
                styleUrls: ['./app.component.scss'],
              })
              export class AppComponent {
                x = 0;
                y = 0;
                startX = 0;
                startY = 0;
                panTransform: string;

                constructor() {}

                onPanStart() {
                  this.startX = this.x;
                  this.startY = this.y;
                }

                onPanRight(event: any) {
                  event.preventDefault();
                  this.x = this.startX + event.deltaX;
                  this.panTransform = this.getTransform(this.x, 0);
                }

                getTransform(x: number, y: number): string {
                  return `translate(${x}px, ${y}px)`;
                }
              }
            
        
    

Pan Up/Down

Pan with only up/down direction

        
            
              <div>
                <div class="bg-image" id="pan">
                  <img
                    mdbPointerGestures
                    [ngStyle]="{ transform: panTransform }"
                    (panstart)="onPanStart()"
                    (panup)="onPanUp($event)"
                    (pandown)="onPanDown($event)"
                    src="https://mdbootstrap.com/img/new/standard/city/053.webp"
                    class="img-fluid"
                    id="img-pan"
                  />
                </div>
              </div>
            
        
    
        
            
              import { Component } from '@angular/core';

              @Component({
                selector: 'app-root',
                templateUrl: './app.component.html',
                styleUrls: ['./app.component.scss'],
              })
              export class AppComponent {
                x = 0;
                y = 0;
                startX = 0;
                startY = 0;
                panTransform: string;

                constructor() {}

                onPanStart() {
                  this.startX = this.x;
                  this.startY = this.y;
                }

                onPanUp(event: any) {
                  event.preventDefault();
                  this.y = this.startY + event.deltaY;
                  this.panTransform = this.getTransform(0, this.y);
                }

                onPanDown(event: any) {
                  event.preventDefault();
                  this.y = this.startY + event.deltaY;
                  this.panTransform = this.getTransform(0, this.y);
                }

                getTransform(x: number, y: number): string {
                  return `translate(${x}px, ${y}px)`;
                }
              }
            
        
    

Pinch

The pinch event provides the ratio between the current and initial pointer distance. It also provides the midpoint between the pointers, which can be used as the transform origin.

        
            
              <div>
                <div class="bg-image" id="pan">
                  <img
                    mdbPointerGestures
                    [ngStyle]="{
                      transform: pinchTransform,
                      'transform-origin': pinchTransformOrigin
                    }"
                    (pinch)="onPinch($event)"
                    src="https://mdbootstrap.com/img/new/standard/city/053.webp"
                    class="img-fluid"
                  />
                </div>
              </div>
            
        
    
        
            
              import { Component } from '@angular/core';

              @Component({
                selector: 'app-root',
                templateUrl: './app.component.html',
                styleUrls: ['./app.component.scss'],
              })
              export class AppComponent {
                pinchTransform: string;
                pinchTransformOrigin: string;

                constructor() {}

                onPinch(event: any) {
                  this.pinchTransform = `scale(${event.ratio})`;
                  this.pinchTransformOrigin = `${event.origin.x}px ${event.origin.y}px`;
                }
              }
            
        
    

Swipe Left/Right

The directive compares the pointer's start and end positions and emits an event for the detected swipe direction.

This example shows example with left and right

Swipe Left-Right to change a color

        
            
            <div>
              <div
                mdbPointerGestures
                class="bg-image"
                (swiperight)="onSwipeRight()"
                (swipeleft)="onSwipeLeft()"
              >
                <img src="https://mdbootstrap.com/img/new/standard/city/053.webp" class="img-fluid" />
                <div
                  class="mask"
                  [ngStyle]="{ 'background-color': background }"
                  id="swipe-left-right"
                >
                  <div class="d-flex justify-content-center align-items-center h-100">
                    <p class="text-white mb-0">Swipe Left-Right to change a color</p>
                  </div>
                </div>
              </div>
            </div>
          
        
    
        
            
            import { Component } from '@angular/core';

            @Component({
              selector: 'app-root',
              templateUrl: './app.component.html',
              styleUrls: ['./app.component.scss'],
            })
            export class AppComponent {
              background = 'rgba(0, 0, 0, 0.6)';

              constructor() {}

              generateColor(): string {
                return `rgba(${this.getRandomNumber()},${this.getRandomNumber()},${this.getRandomNumber()},.4)`;
              }

              getRandomNumber(): number {
                return Math.floor(Math.random() * 255) + 1;
              }

              onSwipeLeft() {
                this.background = this.generateColor();
              }

              onSwipeRight() {
                this.background = this.generateColor();
              }
            }
          
        
    

Swipe Up/Down

Bind the swipeup and swipedown outputs to handle vertical swipes.

Swipe Up-Down to change a color

        
            
            <div>
              <div
                mdbPointerGestures
                class="bg-image"
                (swipeup)="onSwipeUp()"
                (swipedown)="onSwipeDown()"
              >
                <img src="https://mdbootstrap.com/img/new/standard/city/053.webp" class="img-fluid" />
                <div
                  class="mask"
                  [ngStyle]="{ 'background-color': background }"
                  id="swipe-left-right"
                >
                  <div class="d-flex justify-content-center align-items-center h-100">
                    <p class="text-white mb-0">Swipe Up-Down to change a color</p>
                  </div>
                </div>
              </div>
            </div>
          
        
    
        
            
            import { Component } from '@angular/core';

            @Component({
              selector: 'app-root',
              templateUrl: './app.component.html',
              styleUrls: ['./app.component.scss'],
            })
            export class AppComponent {
              background = 'rgba(0, 0, 0, 0.6)';

              constructor() {}

              generateColor(): string {
                return `rgba(${this.getRandomNumber()},${this.getRandomNumber()},${this.getRandomNumber()},.4)`;
              }

              getRandomNumber(): number {
                return Math.floor(Math.random() * 255) + 1;
              }

              onSwipeUp() {
                this.background = this.generateColor();
              }

              onSwipeDown() {
                this.background = this.generateColor();
              }
            }
          
        
    

Rotate

Move two pointers around each other to rotate the image.

        
            
            <div>
              <div class="bg-image">
                <img
                  mdbPointerGestures
                  [ngStyle]="{ transform: rotateTransform }"
                  src="https://mdbootstrap.com/img/new/standard/city/053.webp"
                  class="img-fluid"
                  id="rotate"
                  (rotate)="onRotate($event)"
                />
              </div>
            </div>
          
        
    
        
            
            import { Component } from '@angular/core';

            @Component({
              selector: 'app-root',
              templateUrl: './app.component.html',
              styleUrls: ['./app.component.scss'],
            })
            export class AppComponent {
              rotateTransform: string;

              constructor() {}

              onRotate(event: any) {
                this.rotateTransform = `rotate(${event.currentAngle}turn)`;
              }
            }
          
        
    

GET

UP TO 98% OFF

Check out our bundles and get up to 98% off PRO components.

Touch - API


Import

Copy the PointerGesturesDirective from the Configuration section of the Examples tab, then import it into the component that handles gestures.

        
            
        import { Component } from '@angular/core';
        import { PointerGesturesDirective } from './pointer-gestures.directive';

        @Component({
          selector: 'app-root',
          imports: [PointerGesturesDirective],
          templateUrl: './app.component.html',
        })
        export class AppComponent {}
      
        
    

Options

Name Type Default Description
pressDuration number 250 Defines how long the pointer must remain down before the directive emits press.
doubleTapInterval number 500 Defines the maximum delay in milliseconds between two taps.
tapMaxDistance number 10 Defines how far the pointer can move in pixels and still count as a tap.
swipeThreshold number 50 Defines the minimum swipe distance in pixels.
swipeMaxDuration number 500 Defines the maximum swipe duration in milliseconds.

Outputs

Name Type Description
tap EventEmitter<{ x: number; y: number }> Emits when the pointer is released without exceeding the movement limit.
doubleTap EventEmitter<{ x: number; y: number }> Emits after two taps within the configured interval.
press EventEmitter<void> Emits after the pointer remains down for the configured duration.
panstart EventEmitter<void> Emits when a one-pointer pan starts.
panmove, panleft, panright, panup, pandown EventEmitter<PanEvent> Emits the horizontal and vertical distance from the pointer's start position.
pinch EventEmitter<{ ratio: number; origin: { x: number; y: number } }> Emits the distance ratio and midpoint for a two-pointer pinch.
swipeleft, swiperight, swipeup, swipedown EventEmitter<void> Emits when a pointer movement meets the swipe distance and duration limits.
rotate EventEmitter<{ currentAngle: number }> Emits the rotation between two pointers as a fraction of one turn.
        
            
          <button
            mdbPointerGestures
            type="button"
            class="btn btn-primary"
            [pressDuration]="500"
            (press)="onPress()"
          >
            Press and hold
          </button>
        
        
    
        
            
          import { Component } from '@angular/core';
          import { PointerGesturesDirective } from './pointer-gestures.directive';

          @Component({
            selector: 'app-root',
            imports: [PointerGesturesDirective],
            templateUrl: './app.component.html',
          })
          export class AppComponent {
            onPress(): void {
              console.log('Pressed');
            }
          }