-
Notifications
You must be signed in to change notification settings - Fork 0
/
mapbox-glExtras.js
111 lines (100 loc) · 3.83 KB
/
mapbox-glExtras.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import { Map, MapTouchEvent, Point } from "mapbox-gl";
export class TouchPitchHandler {
/**
* min x distance to recognize pitch gesture
*/
private static readonly MIN_DIFF_X = 55;
/**
* max x distance to recognize pitch gesture -
* this is in order to allow rotate when the fingers are spread apart enough
* and both have the "same" y value
*/
private static readonly MAX_DIFF_X = 200;
/**
* max y distance to recognize pitch gesture
*/
private static readonly MAX_DIFF_Y = 100;
/**
* min distance threshold the fingers drifted from the original touch -
* this is in order to recognize zoom gesture
*/
private static readonly MIN_DIFF = 30;
/**
* delay for pitch, in case it's a zoom gesture
*/
private static readonly DELAY = 160;
private startEventData: MapTouchEvent;
private point: Point;
private pitch: number;
private startTiming: number;
private startDistance: number;
constructor(private readonly map: Map) {
this.startEventData = null;
this.point = null;
this.pitch = null;
this.startDistance = null;
this.startTiming = null;
}
public enable() {
this.map.on("touchstart", (touchEvent: MapTouchEvent) => {
this.handleTouchStart(touchEvent);
});
this.map.on("touchmove", (touchEvent: MapTouchEvent) => {
this.handleTouchMove(touchEvent);
});
this.map.on("touchend", () => {
this.resetInteractions();
})
this.map.on("touchcancel", () => {
this.resetInteractions();
});
}
private handleTouchStart(touchEvent: MapTouchEvent) {
if (touchEvent.points.length !== 2) {
return;
}
const diffY = touchEvent.points[0].y - touchEvent.points[1].y;
const diffX = touchEvent.points[0].x - touchEvent.points[1].x;
if (Math.abs(diffX) < TouchPitchInteraction.MIN_DIFF_X
|| Math.abs(diffY) > TouchPitchInteraction.MAX_DIFF_Y
|| Math.abs(diffX) > TouchPitchInteraction.MAX_DIFF_X) {
return;
}
touchEvent.originalEvent.preventDefault(); // prevent browser refresh on pull down
this.map.touchZoomRotate.disable(); // disable native touch controls
this.map.dragPan.disable();
this.point = touchEvent.point;
this.pitch = this.map.getPitch();
this.startTiming = Date.now();
this.startDistance = Math.hypot(diffX, diffY);
this.startEventData = touchEvent;
}
private handleTouchMove(touchEvent: MapTouchEvent) {
if (this.point == null || this.pitch === null) {
return;
}
touchEvent.preventDefault();
touchEvent.originalEvent.preventDefault();
const diffY = touchEvent.points[0].y - touchEvent.points[1].y;
const diffX = touchEvent.points[0].x - touchEvent.points[1].x;
const distance = Math.hypot(diffX, diffY);
let isTimePassed = Date.now() - this.startTiming >= TouchPitchInteraction.DELAY;
if (Math.abs(distance - this.startDistance) >= TouchPitchInteraction.MIN_DIFF) {
let eventData = isTimePassed ? touchEvent.originalEvent : this.startEventData.originalEvent;
this.resetInteractions();
(this.map.touchZoomRotate as any).onStart(eventData);
return;
}
if (isTimePassed) {
const diff = (this.point.y - touchEvent.point.y) * 0.5;
this.map.setPitch(this.pitch + diff);
}
}
private resetInteractions() {
if (this.point) {
this.map.touchZoomRotate.enable();
this.map.dragPan.enable();
}
this.point = null;
}
}