1 | const React = require('react')
|
2 |
|
3 | const Swipeable = React.createClass({
|
4 | propTypes: {
|
5 | onSwiped: React.PropTypes.func,
|
6 | onSwiping: React.PropTypes.func,
|
7 | onSwipingUp: React.PropTypes.func,
|
8 | onSwipingRight: React.PropTypes.func,
|
9 | onSwipingDown: React.PropTypes.func,
|
10 | onSwipingLeft: React.PropTypes.func,
|
11 | onSwipedUp: React.PropTypes.func,
|
12 | onSwipedRight: React.PropTypes.func,
|
13 | onSwipedDown: React.PropTypes.func,
|
14 | onSwipedLeft: React.PropTypes.func,
|
15 | flickThreshold: React.PropTypes.number,
|
16 | delta: React.PropTypes.number,
|
17 | preventDefaultTouchmoveEvent: React.PropTypes.bool
|
18 | },
|
19 |
|
20 | getInitialState: function () {
|
21 | return {
|
22 | x: null,
|
23 | y: null,
|
24 | swiping: false,
|
25 | start: 0
|
26 | }
|
27 | },
|
28 |
|
29 | getDefaultProps: function () {
|
30 | return {
|
31 | flickThreshold: 0.6,
|
32 | delta: 10,
|
33 | preventDefaultTouchmoveEvent: true
|
34 | }
|
35 | },
|
36 |
|
37 | calculatePos: function (e) {
|
38 | const x = e.changedTouches[0].clientX
|
39 | const y = e.changedTouches[0].clientY
|
40 |
|
41 | const xd = this.state.x - x
|
42 | const yd = this.state.y - y
|
43 |
|
44 | const axd = Math.abs(xd)
|
45 | const ayd = Math.abs(yd)
|
46 |
|
47 | const time = Date.now() - this.state.start
|
48 | const velocity = Math.sqrt(axd * axd + ayd * ayd) / time
|
49 |
|
50 | return {
|
51 | deltaX: xd,
|
52 | deltaY: yd,
|
53 | absX: axd,
|
54 | absY: ayd,
|
55 | velocity: velocity
|
56 | }
|
57 | },
|
58 |
|
59 | touchStart: function (e) {
|
60 | if (e.touches.length > 1) {
|
61 | return
|
62 | }
|
63 | this.setState({
|
64 | start: Date.now(),
|
65 | x: e.touches[0].clientX,
|
66 | y: e.touches[0].clientY,
|
67 | swiping: false
|
68 | })
|
69 | },
|
70 |
|
71 | touchMove: function (e) {
|
72 | if (!this.state.x || !this.state.y || e.touches.length > 1) {
|
73 | return
|
74 | }
|
75 |
|
76 | let cancelPageSwipe = false
|
77 | const pos = this.calculatePos(e)
|
78 |
|
79 | if (pos.absX < this.props.delta && pos.absY < this.props.delta) {
|
80 | return
|
81 | }
|
82 |
|
83 | if (this.props.onSwiping) {
|
84 | this.props.onSwiping(e, pos.deltaX, pos.deltaY, pos.absX, pos.absY, pos.velocity)
|
85 | }
|
86 |
|
87 | if (pos.absX > pos.absY) {
|
88 | if (pos.deltaX > 0) {
|
89 | if (this.props.onSwipingLeft) {
|
90 | this.props.onSwipingLeft(e, pos.absX)
|
91 | cancelPageSwipe = true
|
92 | }
|
93 | } else {
|
94 | if (this.props.onSwipingRight) {
|
95 | this.props.onSwipingRight(e, pos.absX)
|
96 | cancelPageSwipe = true
|
97 | }
|
98 | }
|
99 | } else {
|
100 | if (pos.deltaY > 0) {
|
101 | if (this.props.onSwipingUp) {
|
102 | this.props.onSwipingUp(e, pos.absY)
|
103 | cancelPageSwipe = true
|
104 | }
|
105 | } else {
|
106 | if (this.props.onSwipingDown) {
|
107 | this.props.onSwipingDown(e, pos.absY)
|
108 | cancelPageSwipe = true
|
109 | }
|
110 | }
|
111 | }
|
112 |
|
113 | this.setState({ swiping: true })
|
114 |
|
115 | if (cancelPageSwipe && this.props.preventDefaultTouchmoveEvent) {
|
116 | e.preventDefault()
|
117 | }
|
118 | },
|
119 |
|
120 | touchEnd: function (ev) {
|
121 | if (this.state.swiping) {
|
122 | const pos = this.calculatePos(ev)
|
123 |
|
124 | const isFlick = pos.velocity > this.props.flickThreshold
|
125 |
|
126 | this.props.onSwiped && this.props.onSwiped(
|
127 | ev,
|
128 | pos.deltaX,
|
129 | pos.deltaY,
|
130 | isFlick
|
131 | )
|
132 |
|
133 | if (pos.absX > pos.absY) {
|
134 | if (pos.deltaX > 0) {
|
135 | this.props.onSwipedLeft && this.props.onSwipedLeft(ev, pos.deltaX, isFlick)
|
136 | } else {
|
137 | this.props.onSwipedRight && this.props.onSwipedRight(ev, pos.deltaX, isFlick)
|
138 | }
|
139 | } else {
|
140 | if (pos.deltaY > 0) {
|
141 | this.props.onSwipedUp && this.props.onSwipedUp(ev, pos.deltaY, isFlick)
|
142 | } else {
|
143 | this.props.onSwipedDown && this.props.onSwipedDown(ev, pos.deltaY, isFlick)
|
144 | }
|
145 | }
|
146 | }
|
147 |
|
148 | this.setState(this.getInitialState())
|
149 | },
|
150 |
|
151 | render: function () {
|
152 | return (
|
153 | <div {...this.props}
|
154 | onTouchStart={this.touchStart}
|
155 | onTouchMove={this.touchMove}
|
156 | onTouchEnd={this.touchEnd} >
|
157 | {this.props.children}
|
158 | </div>
|
159 | )
|
160 | }
|
161 | })
|
162 |
|
163 | module.exports = Swipeable
|