react-swipeable
Version:
Swipe bindings for react
236 lines (198 loc) • 6.56 kB
JavaScript
'use strict';
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var React = require('react');
function getInitialState() {
return {
x: null,
y: null,
swiping: false,
start: 0
};
}
var Swipeable = React.createClass({
displayName: 'Swipeable',
propTypes: {
onSwiped: React.PropTypes.func,
onSwiping: React.PropTypes.func,
onSwipingUp: React.PropTypes.func,
onSwipingRight: React.PropTypes.func,
onSwipingDown: React.PropTypes.func,
onSwipingLeft: React.PropTypes.func,
onSwipedUp: React.PropTypes.func,
onSwipedRight: React.PropTypes.func,
onSwipedDown: React.PropTypes.func,
onSwipedLeft: React.PropTypes.func,
flickThreshold: React.PropTypes.number,
delta: React.PropTypes.number,
preventDefaultTouchmoveEvent: React.PropTypes.bool,
stopPropagation: React.PropTypes.bool,
nodeName: React.PropTypes.string,
trackMouse: React.PropTypes.bool
},
componentWillMount: function componentWillMount() {
this.swipeable = getInitialState();
},
getDefaultProps: function getDefaultProps() {
return {
flickThreshold: 0.6,
delta: 10,
preventDefaultTouchmoveEvent: true,
stopPropagation: false,
nodeName: 'div'
};
},
calculatePos: function calculatePos(e) {
var x = void 0,
y = void 0;
// If not a touch, determine point from mouse coordinates
if (e.changedTouches) {
x = e.changedTouches[0].clientX;
y = e.changedTouches[0].clientY;
} else {
x = e.clientX;
y = e.clientY;
}
var xd = this.swipeable.x - x;
var yd = this.swipeable.y - y;
var axd = Math.abs(xd);
var ayd = Math.abs(yd);
var time = Date.now() - this.swipeable.start;
var velocity = Math.sqrt(axd * axd + ayd * ayd) / time;
return {
deltaX: xd,
deltaY: yd,
absX: axd,
absY: ayd,
velocity: velocity
};
},
eventStart: function eventStart(e) {
if (typeof this.props.onMouseDown === 'function') {
this.props.onMouseDown(e);
}
if (e.type === 'mousedown' && !this.props.trackMouse) {
return;
}
if (e.touches && e.touches.length > 1) {
return;
}
// If not a touch, determine point from mouse coordinates
var touches = e.touches;
if (!touches) {
touches = [{ clientX: e.clientX, clientY: e.clientY }];
}
if (this.props.stopPropagation) e.stopPropagation();
this.swipeable = {
start: Date.now(),
x: touches[0].clientX,
y: touches[0].clientY,
swiping: false
};
},
eventMove: function eventMove(e) {
if (typeof this.props.onMouseMove === 'function') {
this.props.onMouseMove(e);
}
if (e.type === 'mousemove' && !this.props.trackMouse) {
return;
}
if (!this.swipeable.x || !this.swipeable.y || e.touches && e.touches.length > 1) {
return;
}
var cancelPageSwipe = false;
var pos = this.calculatePos(e);
if (pos.absX < this.props.delta && pos.absY < this.props.delta) {
return;
}
if (this.props.stopPropagation) e.stopPropagation();
if (this.props.onSwiping) {
this.props.onSwiping(e, pos.deltaX, pos.deltaY, pos.absX, pos.absY, pos.velocity);
}
if (pos.absX > pos.absY) {
if (pos.deltaX > 0) {
if (this.props.onSwipingLeft || this.props.onSwipedLeft) {
this.props.onSwipingLeft && this.props.onSwipingLeft(e, pos.absX);
cancelPageSwipe = true;
}
} else {
if (this.props.onSwipingRight || this.props.onSwipedRight) {
this.props.onSwipingRight && this.props.onSwipingRight(e, pos.absX);
cancelPageSwipe = true;
}
}
} else {
if (pos.deltaY > 0) {
if (this.props.onSwipingUp || this.props.onSwipedUp) {
this.props.onSwipingUp && this.props.onSwipingUp(e, pos.absY);
cancelPageSwipe = true;
}
} else {
if (this.props.onSwipingDown || this.props.onSwipedDown) {
this.props.onSwipingDown && this.props.onSwipingDown(e, pos.absY);
cancelPageSwipe = true;
}
}
}
this.swipeable.swiping = true;
if (cancelPageSwipe && this.props.preventDefaultTouchmoveEvent) {
e.preventDefault();
}
},
eventEnd: function eventEnd(e) {
if (typeof this.props.onMouseUp === 'function') {
this.props.onMouseUp(e);
}
if (e.type === 'mouseup' && !this.props.trackMouse) {
return;
}
if (this.swipeable.swiping) {
var pos = this.calculatePos(e);
if (this.props.stopPropagation) e.stopPropagation();
var isFlick = pos.velocity > this.props.flickThreshold;
this.props.onSwiped && this.props.onSwiped(e, pos.deltaX, pos.deltaY, isFlick, pos.velocity);
if (pos.absX > pos.absY) {
if (pos.deltaX > 0) {
this.props.onSwipedLeft && this.props.onSwipedLeft(e, pos.deltaX, isFlick);
} else {
this.props.onSwipedRight && this.props.onSwipedRight(e, pos.deltaX, isFlick);
}
} else {
if (pos.deltaY > 0) {
this.props.onSwipedUp && this.props.onSwipedUp(e, pos.deltaY, isFlick);
} else {
this.props.onSwipedDown && this.props.onSwipedDown(e, pos.deltaY, isFlick);
}
}
}
this.swipeable = getInitialState();
},
render: function render() {
var newProps = _extends({}, this.props, {
onTouchStart: this.eventStart,
onTouchMove: this.eventMove,
onTouchEnd: this.eventEnd,
onMouseDown: this.eventStart,
onMouseMove: this.eventMove,
onMouseUp: this.eventEnd
});
delete newProps.onSwiped;
delete newProps.onSwiping;
delete newProps.onSwipingUp;
delete newProps.onSwipingRight;
delete newProps.onSwipingDown;
delete newProps.onSwipingLeft;
delete newProps.onSwipedUp;
delete newProps.onSwipedRight;
delete newProps.onSwipedDown;
delete newProps.onSwipedLeft;
delete newProps.flickThreshold;
delete newProps.delta;
delete newProps.preventDefaultTouchmoveEvent;
delete newProps.stopPropagation;
delete newProps.nodeName;
delete newProps.children;
delete newProps.trackMouse;
return React.createElement(this.props.nodeName, newProps, this.props.children);
}
});
module.exports = Swipeable;