-
Notifications
You must be signed in to change notification settings - Fork 565
/
PinchZoomView.js
125 lines (94 loc) · 3.69 KB
/
PinchZoomView.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
/**
* 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 PropTypes from 'prop-types';
import {
View,
StyleSheet,
PanResponder
} from 'react-native';
import {ViewPropTypes} from 'deprecated-react-native-prop-types';
export default class PinchZoomView extends Component {
static propTypes = {
...ViewPropTypes,
scalable: PropTypes.bool,
onScaleChanged: PropTypes.func,
};
static defaultProps = {
scalable: true,
onScaleChanged: (scale) => {
},
};
constructor(props) {
super(props);
this.state = {};
this.distant = 0;
this.gestureHandlers = PanResponder.create({
onStartShouldSetPanResponder: this._handleStartShouldSetPanResponder,
onMoveShouldSetResponderCapture: (evt, gestureState) => (true),
onMoveShouldSetPanResponder: this._handleMoveShouldSetPanResponder,
onPanResponderGrant: this._handlePanResponderGrant,
onPanResponderMove: this._handlePanResponderMove,
onPanResponderRelease: this._handlePanResponderEnd,
onPanResponderTerminationRequest: evt => false,
onPanResponderTerminate: this._handlePanResponderTerminate,
onShouldBlockNativeResponder: evt => true
});
}
_handleStartShouldSetPanResponder = (e, gestureState) => {
// don't respond to single touch to avoid shielding click on child components
return false;
};
_handleMoveShouldSetPanResponder = (e, gestureState) => {
return this.props.scalable && (e.nativeEvent.changedTouches.length >= 2 || gestureState.numberActiveTouches >= 2);
};
_handlePanResponderGrant = (e, gestureState) => {
if (e.nativeEvent.changedTouches.length >= 2 || gestureState.numberActiveTouches >= 2) {
let dx = Math.abs(e.nativeEvent.touches[0].pageX - e.nativeEvent.touches[1].pageX);
let dy = Math.abs(e.nativeEvent.touches[0].pageY - e.nativeEvent.touches[1].pageY);
this.distant = Math.sqrt(dx * dx + dy * dy);
}
};
_handlePanResponderEnd = (e, gestureState) => {
this.distant = 0;
};
_handlePanResponderTerminate = (e, gestureState) => {
this.distant = 0;
};
_handlePanResponderMove = (e, gestureState) => {
if ((e.nativeEvent.changedTouches.length >= 2 || gestureState.numberActiveTouches >= 2) && this.distant > 100) {
let dx = Math.abs(e.nativeEvent.touches[0].pageX - e.nativeEvent.touches[1].pageX);
let dy = Math.abs(e.nativeEvent.touches[0].pageY - e.nativeEvent.touches[1].pageY);
let distant = Math.sqrt(dx * dx + dy * dy);
let scale = (distant / this.distant);
let pageX = (e.nativeEvent.touches[0].pageX + e.nativeEvent.touches[1].pageX) / 2;
let pageY = (e.nativeEvent.touches[0].pageY + e.nativeEvent.touches[1].pageY) / 2;
let pinchInfo = {scale: scale, pageX: pageX, pageY: pageY};
this.props.onScaleChanged(pinchInfo);
this.distant = distant;
}
};
render() {
return (
<View
{...this.props}
{...this.gestureHandlers?.panHandlers}
style={[styles.container, this.props.style]}>
{this.props.children}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
}
});