@gdjiami/hooks
Version:
react hooks for mygzb.com
251 lines (250 loc) • 9.81 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var react_1 = require("react");
var useInstance_1 = tslib_1.__importDefault(require("./useInstance"));
var useMultiTouchGesture_1 = tslib_1.__importDefault(require("./useMultiTouchGesture"));
var useRefProps_1 = tslib_1.__importDefault(require("./useRefProps"));
var useOnUnmount_1 = tslib_1.__importDefault(require("./useOnUnmount"));
var SwipeDirection;
(function (SwipeDirection) {
SwipeDirection["Up"] = "up";
SwipeDirection["Down"] = "down";
SwipeDirection["Left"] = "left";
SwipeDirection["Right"] = "right";
})(SwipeDirection = exports.SwipeDirection || (exports.SwipeDirection = {}));
/**
* 获取向量的距离
*/
function getLen(vector) {
return Math.sqrt(Math.pow(vector.x, 2) + Math.pow(vector.y, 2));
}
function dot(v1, v2) {
return v1.x * v2.x + v1.y * v2.y;
}
function cross(v1, v2) {
return v1.x * v2.y - v2.x * v1.y;
}
function getAngle(v1, v2) {
var mr = getLen(v1) * getLen(v2);
if (mr === 0)
return 0;
var r = dot(v1, v2) / mr;
if (r > 1)
r = 1;
return Math.acos(r);
}
/**
* 获取swipe的方向
*/
function getSwipeDirection(from, to) {
return Math.abs(from.x - to.x) > Math.abs(from.y - to.y)
? from.x > to.x // 水平
? SwipeDirection.Left
: SwipeDirection.Right
: from.y > to.y
? SwipeDirection.Up
: SwipeDirection.Down;
}
/**
* 获取旋转的角度
*/
function getRotateAngle(v1, v2) {
var angle = getAngle(v1, v2);
if (cross(v1, v2) > 0) {
angle *= -1;
}
return (angle * 180) / Math.PI;
}
function useTouch(options) {
var _a = tslib_1.__read(useInstance_1.default(function () { return ({
isSingleTap: false,
isDoubleTap: false,
}); }), 1), state = _a[0];
var optionRef = useRefProps_1.default(options);
var ref = options.ref || react_1.useRef();
var cancelLongTap = react_1.useCallback(function () {
clearTimeout(state.longTapTimeout);
}, []);
var cancelAfterLongTapTimeout = react_1.useCallback(function () {
clearTimeout(state.afterLongTapTimeout);
}, []);
var cancelSingleTap = react_1.useCallback(function () {
clearTimeout(state.singleTapTimeout);
}, []);
useOnUnmount_1.default(function () {
cancelLongTap();
cancelAfterLongTapTimeout();
cancelSingleTap();
});
useMultiTouchGesture_1.default({
ref: ref,
onDown: function (info) {
if (optionRef.current.onDown) {
optionRef.current.onDown(info);
}
var now = (state.start = Date.now());
var len = info.touches.length;
var x1 = (state.x1 = info.touches[0].pageX);
var y1 = (state.y1 = info.touches[0].pageY);
var delta = now - (state.last || now);
// 可能是双击: 时间间隔在250ms内, 且移动范围小于20
if (state.preTapPosition) {
state.isDoubleTap =
delta > 0 &&
delta <= 250 &&
Math.abs(state.preTapPosition.x - x1) < 30 &&
Math.abs(state.preTapPosition.y - y1) < 30;
if (state.isDoubleTap) {
cancelSingleTap();
}
}
state.preTapPosition = { x: x1, y: y1 };
state.last = now;
if (len > 1) {
// 多点触摸. 取消tap
cancelLongTap();
cancelSingleTap();
// pinch 手势
var v = {
x: info.touches[1].pageX - x1,
y: info.touches[1].pageY - y1,
};
state.preV = v;
state.pinchStartLen = getLen(v);
state.multiTouch = true;
}
else {
state.isSingleTap = true;
}
// 长按事件
state.preventTap = false;
if (!state.multiTouch) {
state.longTapTimeout = window.setTimeout(function () {
if (optionRef.current.onLongTap) {
optionRef.current.onLongTap(info.touches[0]);
}
// 禁止长按之后tap事件
state.preventTap = true;
}, 750);
}
},
onMove: function (info) {
if (optionRef.current.onMove) {
optionRef.current.onMove(info);
}
var len = info.touches.length;
var currentX = info.touches[0].pageX;
var currentY = info.touches[0].pageY;
var preV = state.preV;
// 触摸点移动, 不再为tap
state.isSingleTap = false;
state.isDoubleTap = false;
cancelLongTap();
if (len > 1) {
var secCurrentX = info.touches[1].pageX;
var secCurrentY = info.touches[1].pageY;
var v = {
x: secCurrentX - currentX,
y: secCurrentY - currentY,
};
if (preV != null) {
if (state.pinchStartLen &&
state.pinchStartLen > 0 &&
optionRef.current.onPinch) {
// 触发的pinch事件
var center = {
x: (secCurrentX + currentX) / 2,
y: (secCurrentY + currentY) / 2,
};
var scale = getLen(v) / state.pinchStartLen;
optionRef.current.onPinch({ center: center, scale: scale });
}
if (optionRef.current.onRotate) {
// 触发rotate 事件
var angle = getRotateAngle(v, preV);
optionRef.current.onRotate({ angle: angle });
}
}
state.preV = v;
state.multiTouch = true;
}
else {
// 移动事件
if (optionRef.current.onPressMove) {
optionRef.current.onPressMove(info.touches[0]);
}
if (info.touches[0].distance > 15) {
state.preventTap = true;
}
}
// 记录最后移动的位置
state.x2 = currentX;
state.y2 = currentY;
},
onUp: function (info) {
if (optionRef.current.onUp) {
optionRef.current.onUp(info);
}
cancelLongTap();
if (!state.multiTouch) {
// 单点触摸
if ((state.x2 && Math.abs(state.x1 - state.x2) > 30) ||
(state.y2 && Math.abs(state.y1 - state.y2) > 30)) {
/**
* swipe: 移动距离超过30px
*/
var direction = getSwipeDirection({ x: state.x1, y: state.y1 }, { x: state.x2, y: state.y2 });
var distance = direction === SwipeDirection.Left ||
direction === SwipeDirection.Right
? Math.abs(state.x1 - state.x2)
: Math.abs(state.y1 - state.y2);
if (optionRef.current.onSwipe) {
optionRef.current.onSwipe({ direction: direction, distance: distance });
}
}
else {
// long tap已经触发或者出现移动
if (state.preventTap) {
state.preventTap = false;
}
else {
if (optionRef.current.onTap) {
/**
* tap
*/
optionRef.current.onTap(info.changedTouches[0]);
}
if (state.isDoubleTap) {
/**
* double tap
*/
if (optionRef.current.onDoubleTap) {
optionRef.current.onDoubleTap(info.changedTouches[0]);
}
cancelSingleTap();
state.isDoubleTap = false;
}
else if (state.isSingleTap) {
/**
* single tap: 如果250ms内 没有再发起点击, 则为单击
*/
state.singleTapTimeout = window.setTimeout(function () {
if (optionRef.current.onSingleTap) {
optionRef.current.onSingleTap(info.changedTouches[0]);
}
}, 250);
state.isSingleTap = false;
}
}
}
}
state.preV = undefined;
state.pinchStartLen = undefined;
state.x1 = state.y1 = state.x2 = state.y2 = undefined;
state.multiTouch = info.touches.length !== 0;
},
});
return { ref: ref };
}
exports.default = useTouch;