Skip to content

Instantly share code, notes, and snippets.

@iammerrick
Last active August 31, 2018 16:42
Show Gist options
  • Save iammerrick/1979118ae810936e18b0db3f65819733 to your computer and use it in GitHub Desktop.
Save iammerrick/1979118ae810936e18b0db3f65819733 to your computer and use it in GitHub Desktop.
Panning Mobile Web
export const getPointRelativeToElement = (point, element) => {
const rect = element.getBoundingClientRect();
return {
x: point.x - rect.left,
y: point.y - rect.top,
};
};
export const getDistanceBetweenPoints = (pointA, pointB) => (
Math.sqrt(Math.pow(pointA.y - pointB.y, 2) + Math.pow(pointA.x - pointB.x, 2))
);
import React from 'react';
import ReactDOM from 'react-dom';
import { getPointRelativeToElement, getDistanceBetweenPoints } from 'utilities/geometry';
const THRESHOLD = 10;
const pointFromTouch = (touch) => ({ x: touch.clientX, y: touch.clientY });
class PanGesture extends React.Component {
constructor() {
super(...arguments);
this.handleTouchStart = this.handleTouchStart.bind(this);
this.handleTouchMove = this.handleTouchMove.bind(this);
this.handleTouchEnd = this.handleTouchEnd.bind(this);
this.startPoint = null;
this.point = null;
this.isRecognizing = false;
}
componentDidMount() {
this.el = ReactDOM.findDOMNode(this);
if (this.props.when) {
this.listen();
}
}
componentWillReceiveProps(next) {
if (this.props.when !== next.when) {
if (next.when) {
this.listen();
} else {
this.unlisten();
}
}
}
componentWillUnmount() {
this.unlisten();
}
listen() {
this.el.addEventListener('touchstart', this.handleTouchStart, false);
this.el.addEventListener('touchmove', this.handleTouchMove, false);
this.el.addEventListener('touchend', this.handleTouchEnd, false);
}
unlisten() {
this.el.removeEventListener('touchstart', this.handleTouchStart, false);
this.el.removeEventListener('touchmove', this.handleTouchMove, false);
this.el.removeEventListener('touchend', this.handleTouchEnd, false);
}
handleTouchStart(event) {
if (event.touches.length !== 1) return null;
this.startPoint = this.point = pointFromTouch(event.touches[0]);
}
handleTouchMove(event) {
if (event.touches.length !== 1 || !this.startPoint) return null;
this.point = getPointRelativeToElement(pointFromTouch(event.touches[0]), this.el);
if (this.isRecognizing) {
this.props.onPan(this.point.x, this.point.y);
} else {
if (getDistanceBetweenPoints(this.startPoint, this.point) >= THRESHOLD) {
this.isRecognizing = true;
}
}
}
handleTouchEnd() {
if (this.point) {
this.props.onPanEnd(this.point.x, this.point.y);
}
this.point = null;
this.startPoint = null;
this.isRecognizing = false;
}
render() {
return React.Children.only(this.props.children);
}
}
PanGesture.propTypes = {
onPanEnd: React.PropTypes.func.isRequired,
onPan: React.PropTypes.func.isRequired,
};
export default PanGesture;
<PanGesture onPan={this.handlePan} onPanEnd={this.handlePanEnd} when={this.state.scale === 1}>
</PanGesture>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment