ag-grid
Version:
Advanced Data Grid / Data Table supporting Javascript / React / AngularJS / Web Components
172 lines (134 loc) • 5.31 kB
text/typescript
import { EventService } from "../eventService";
import { IEventEmitter } from "../interfaces/iEventEmitter";
import { Utils as _ } from "../utils";
import { AgEvent } from "../events";
export interface TapEvent extends AgEvent {
touchStart: Touch;
}
export interface LongTapEvent extends AgEvent {
touchStart: Touch;
touchEvent: TouchEvent;
}
export class TouchListener implements IEventEmitter {
public static EVENT_TAP = "tap";
public static EVENT_DOUBLE_TAP = "doubleTap";
public static EVENT_LONG_TAP = "longTap";
private static DOUBLE_TAP_MILLIS = 500;
private eElement: HTMLElement;
private destroyFuncs: Function[] = [];
private moved: boolean;
private touching = false;
private touchStart: Touch;
private lastTapTime: number;
private eventService: EventService = new EventService();
// private mostRecentTouch: Touch;
private preventMouseClick: boolean;
constructor(eElement: HTMLElement, preventMouseClick = false) {
this.eElement = eElement;
this.preventMouseClick = preventMouseClick;
let startListener = this.onTouchStart.bind(this);
let moveListener = this.onTouchMove.bind(this);
let endListener = this.onTouchEnd.bind(this);
this.eElement.addEventListener("touchstart", startListener, <any>{ passive: true });
this.eElement.addEventListener("touchmove", moveListener, <any>{ passive: true });
// we set passive=false, as we want to prevent default on this event
this.eElement.addEventListener("touchend", endListener, <any>{ passive: false });
this.destroyFuncs.push(() => {
this.eElement.addEventListener("touchstart", startListener, <any>{ passive: true });
this.eElement.addEventListener("touchmove", moveListener, <any>{ passive: true });
this.eElement.addEventListener("touchend", endListener, <any>{ passive: false });
});
}
private getActiveTouch(touchList: TouchList): Touch {
for (let i = 0; i < touchList.length; i++) {
let matches = touchList[i].identifier === this.touchStart.identifier;
if (matches) {
return touchList[i];
}
}
return null;
}
public addEventListener(eventType: string, listener: Function): void {
this.eventService.addEventListener(eventType, listener);
}
public removeEventListener(eventType: string, listener: Function): void {
this.eventService.removeEventListener(eventType, listener);
}
private onTouchStart(touchEvent: TouchEvent): void {
// only looking at one touch point at any time
if (this.touching) {
return;
}
this.touchStart = touchEvent.touches[0];
this.touching = true;
this.moved = false;
let touchStartCopy = this.touchStart;
setTimeout(() => {
let touchesMatch = this.touchStart === touchStartCopy;
if (this.touching && touchesMatch && !this.moved) {
this.moved = true;
let event: LongTapEvent = {
type: TouchListener.EVENT_LONG_TAP,
touchStart: this.touchStart,
touchEvent: touchEvent
};
this.eventService.dispatchEvent(event);
}
}, 500);
}
private onTouchMove(touchEvent: TouchEvent): void {
if (!this.touching) {
return;
}
let touch = this.getActiveTouch(touchEvent.touches);
if (!touch) {
return;
}
let eventIsFarAway = !_.areEventsNear(touch, this.touchStart, 4);
if (eventIsFarAway) {
this.moved = true;
}
}
private onTouchEnd(touchEvent: TouchEvent): void {
if (!this.touching) {
return;
}
if (!this.moved) {
let event: TapEvent = {
type: TouchListener.EVENT_TAP,
touchStart: this.touchStart
};
this.eventService.dispatchEvent(event);
this.checkForDoubleTap();
// stops the tap from also been processed as a mouse click
if (this.preventMouseClick) {
touchEvent.preventDefault();
}
}
this.touching = false;
}
private checkForDoubleTap(): void {
let now = new Date().getTime();
if (this.lastTapTime>0) {
// if previous tap, see if duration is short enough to be considered double tap
let interval = now - this.lastTapTime;
if (interval > TouchListener.DOUBLE_TAP_MILLIS) {
// dispatch double tap event
let event: TapEvent = {
type: TouchListener.EVENT_DOUBLE_TAP,
touchStart: this.touchStart
};
this.eventService.dispatchEvent(event);
// this stops a tripple tap ending up as two double taps
this.lastTapTime = null;
} else {
this.lastTapTime = now;
}
} else {
this.lastTapTime = now;
}
}
public destroy(): void {
this.destroyFuncs.forEach(func => func());
}
}