maplibre-gl
Version:
BSD licensed community fork of mapbox-gl, a WebGL interactive maps library
124 lines (100 loc) • 3.63 kB
text/typescript
import Point from '@mapbox/point-geometry';
import {indexTouches} from './handler_util';
import type Map from '../map';
import {GestureOptions} from '../map';
export default class TouchPanHandler {
_enabled: boolean;
_active: boolean;
_touches: {
[k in string | number]: Point;
};
_minTouches: number;
_clickTolerance: number;
_sum: Point;
_map: Map;
_cancelCooperativeMessage: boolean;
constructor(options: {
clickTolerance: number;
cooperativeGestures: boolean | GestureOptions;
}, map: Map) {
this._minTouches = options.cooperativeGestures ? 2 : 1;
this._clickTolerance = options.clickTolerance || 1;
this._map = map;
this.reset();
}
reset() {
this._active = false;
this._touches = {};
this._sum = new Point(0, 0);
// Put a delay on the cooperative gesture message so it's less twitchy
setTimeout(() => {
this._cancelCooperativeMessage = false;
}, 200);
}
touchstart(e: TouchEvent, points: Array<Point>, mapTouches: Array<Touch>) {
return this._calculateTransform(e, points, mapTouches);
}
touchmove(e: TouchEvent, points: Array<Point>, mapTouches: Array<Touch>) {
if (this._map._cooperativeGestures) {
if (this._minTouches === 2 && mapTouches.length < 2 && !this._cancelCooperativeMessage) {
// If coop gesture enabled, show panning info to user
this._map._onCooperativeGesture(e, false, mapTouches.length);
} else if (!this._cancelCooperativeMessage) {
// If user is successfully navigating, we don't need this warning until the touch resets
this._cancelCooperativeMessage = true;
}
}
if (!this._active || mapTouches.length < this._minTouches) return;
e.preventDefault();
return this._calculateTransform(e, points, mapTouches);
}
touchend(e: TouchEvent, points: Array<Point>, mapTouches: Array<Touch>) {
this._calculateTransform(e, points, mapTouches);
if (this._active && mapTouches.length < this._minTouches) {
this.reset();
}
}
touchcancel() {
this.reset();
}
_calculateTransform(e: TouchEvent, points: Array<Point>, mapTouches: Array<Touch>) {
if (mapTouches.length > 0) this._active = true;
const touches = indexTouches(mapTouches, points);
const touchPointSum = new Point(0, 0);
const touchDeltaSum = new Point(0, 0);
let touchDeltaCount = 0;
for (const identifier in touches) {
const point = touches[identifier];
const prevPoint = this._touches[identifier];
if (prevPoint) {
touchPointSum._add(point);
touchDeltaSum._add(point.sub(prevPoint));
touchDeltaCount++;
touches[identifier] = point;
}
}
this._touches = touches;
if (touchDeltaCount < this._minTouches || !touchDeltaSum.mag()) return;
const panDelta = touchDeltaSum.div(touchDeltaCount);
this._sum._add(panDelta);
if (this._sum.mag() < this._clickTolerance) return;
const around = touchPointSum.div(touchDeltaCount);
return {
around,
panDelta
};
}
enable() {
this._enabled = true;
}
disable() {
this._enabled = false;
this.reset();
}
isEnabled() {
return this._enabled;
}
isActive() {
return this._active;
}
}