forked from wonday/react-native-pdf
-
Notifications
You must be signed in to change notification settings - Fork 0
/
DoubleTapView.js
126 lines (98 loc) · 3.57 KB
/
DoubleTapView.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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/**
* Copyright (c) 2017-present, Wonday (@wonday.org)
* All rights reserved.
*
* This source code is licensed under the MIT-style license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';
import React, {Component} from 'react';
import {
View,
PanResponder,
ViewPropTypes,
} from 'react-native';
import PropTypes from 'prop-types';
export default class DoubleTapView extends Component {
static propTypes = {
...ViewPropTypes,
delay: PropTypes.number,
radius: PropTypes.number,
onSingleTap: PropTypes.func,
onDoubleTap: PropTypes.func,
};
static defaultProps = {
delay: 300,
radius: 50,
onSingleTap: () => {
},
onDoubleTap: () => {
},
};
constructor() {
super();
this.gestureHandlers = PanResponder.create({
onStartShouldSetPanResponder: (evt, gestureState) => (gestureState.numberActiveTouches === 1),
onStartShouldSetResponderCapture: (evt, gestureState) => (gestureState.numberActiveTouches === 1),
onMoveShouldSetPanResponder: (evt, gestureState) => (false),
onMoveShouldSetResponderCapture: (evt, gestureState) => (false),
onPanResponderTerminationRequest: (evt, gestureState) => false,
onPanResponderRelease: this.handlePanResponderRelease,
});
this.prevTouchInfo = {
prevTouchX: 0,
prevTouchY: 0,
prevTouchTimeStamp: 0,
};
this.timer = null;
}
distance = (x0, y0, x1, y1) => {
return Math.sqrt(Math.pow((x1 - x0), 2) + Math.pow((y1 - y0), 2)).toFixed(1);
};
isDoubleTap = (currentTouchTimeStamp, {x0, y0}) => {
const {prevTouchX, prevTouchY, prevTouchTimeStamp} = this.prevTouchInfo;
const dt = currentTouchTimeStamp - prevTouchTimeStamp;
const {delay, radius} = this.props;
return (prevTouchTimeStamp > 0 && dt < delay && this.distance(prevTouchX, prevTouchY, x0, y0) < radius);
};
handlePanResponderRelease = (evt, gestureState) => {
const currentTouchTimeStamp = Date.now();
const x = evt.nativeEvent.locationX;
const y = evt.nativeEvent.locationY;
if (this.timer) {
if (this.isDoubleTap(currentTouchTimeStamp, gestureState)) {
clearTimeout(this.timer);
this.timer = null;
this.props.onDoubleTap();
} else {
const {prevTouchX, prevTouchY, prevTouchTimeStamp} = this.prevTouchInfo;
const {radius} = this.props;
// if not in radius, it's a move
if (this.distance(prevTouchX, prevTouchY, gestureState.x0, gestureState.y0) < radius) {
this.timer = null;
this.props.onSingleTap(x, y);
}
}
} else {
// do not count scroll gestures as taps
if (this.distance(0, gestureState.dx, 0, gestureState.dy) < 10) {
this.timer = setTimeout(() => {
this.props.onSingleTap(x, y);
this.timer = null;
}, this.props.delay);
}
}
this.prevTouchInfo = {
prevTouchX: gestureState.x0,
prevTouchY: gestureState.y0,
prevTouchTimeStamp: currentTouchTimeStamp,
};
};
render() {
return (
<View {...this.props} {...this.gestureHandlers.panHandlers}>
{this.props.children}
</View>
);
}
}