cross-gesture
Version:
Gesture lib for the modern browsers
371 lines • 15.1 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CrossGesture = void 0;
var utils_1 = require("./utils");
var MOVE_OUT_DISTANCE = 10;
var CrossGesture = /** @class */ (function () {
function CrossGesture(el) {
var _this = this;
// 配置
this.options = {
singleTapTimeout: 250,
longTapTimeout: 750,
};
// 事件监听回调函数
this.listenersMap = new Map();
// 之前滑动触点
this.touchPrePoints = {};
// 触摸点的滑动轨迹
this.touchPointsPath = new Map();
this.isMouseDown = false;
this.onWheel = function (evt) {
_this.dispatch('wheel', evt);
};
this.onPointerDown = function (evt) {
_this.dispatch('pointerdown', evt);
};
this.onPointerUp = function (evt) {
_this.dispatch('pointerup', evt);
};
this.onPointerMove = function (evt) {
_this.dispatch('pointermove', evt);
};
this.onMouseDown = function (evt) {
_this.isMouseDown = true;
// dispatch mousedown
_this.dispatch('mousedown', evt);
// dispatch press move
_this.dispatchPressMove(evt);
};
this.onMouseMove = function (evt) {
// dispatch mousemove
_this.dispatch('mousemove', evt);
if (!_this.isMouseDown) {
return;
}
// dispatch press move
_this.dispatchPressMove(evt);
};
this.onMouseUp = function (evt) {
_this.isMouseDown = false;
// dispatch mouseup
_this.dispatch('mouseup', evt);
};
this.onTouchStart = function (evt) {
// dispatch touchstart
_this.dispatch('touchstart', evt);
// dispatch press move
_this.dispatchPressMove(evt);
// update touch path
_this.updatePathOfPoint(evt.touches);
// 清除上一个 single tap
if (_this.singleTapTimer) {
clearTimeout(_this.singleTapTimer);
_this.singleTapTimer = undefined;
}
if (!_this.longTapTimer) {
_this.longTapPoint = evt.touches[0];
_this.longTapTimer = setTimeout(function () {
// dispatch longTap
_this.dispatch('longTap', evt);
}, _this.options.longTapTimeout);
}
};
this.onTouchMove = function (evt) {
var touches = evt.touches;
if (touches.length > 1) {
evt.preventDefault();
}
// dispatch touchmove
_this.dispatch('touchmove', evt);
// dispatch press move
_this.dispatchPressMove(evt);
// pinch
var touchPrePoints = _this.touchPrePoints.points || [];
if (touches.length > 1 && touchPrePoints && touchPrePoints.length > 1) {
var pre1 = touchPrePoints[0];
var pre2 = touchPrePoints[1];
var cur1 = touches[0];
var cur2 = touches[1];
var rect = _this.element.getBoundingClientRect();
var fromPoints = [
{
x: pre1.clientX - rect.x,
y: pre1.clientY - rect.y,
},
{
x: pre2.clientX - rect.x,
y: pre2.clientY - rect.y,
},
];
var toPoints = [
{
x: cur1.clientX - rect.x,
y: cur1.clientY - rect.y,
},
{
x: cur2.clientX - rect.x,
y: cur2.clientY - rect.y,
},
];
var rotateDeg = utils_1.getRotateDeg(fromPoints, toPoints);
var zoomCenter = {
x: (toPoints[0].x + toPoints[1].x) / 2,
y: (toPoints[0].y + toPoints[1].y) / 2,
};
var zoom = utils_1.pinchTimes(fromPoints, toPoints);
_this.dispatch('pinch', evt, {
fromPoints: fromPoints,
toPoints: toPoints,
zoomCenter: zoomCenter,
zoom: zoom,
});
_this.dispatch('rotate', evt, {
fromPoints: fromPoints,
toPoints: toPoints,
rotateCenter: zoomCenter,
rotateDeg: rotateDeg,
});
_this.dispatch('pinchAndRotate', evt, {
fromPoints: fromPoints,
toPoints: toPoints,
rotateCenter: zoomCenter,
rotateDeg: rotateDeg,
zoomCenter: zoomCenter,
zoom: zoom,
});
}
// swipe
if (touchPrePoints.length > 0 && _this.touchPrePoints.time) {
var preTouch = touchPrePoints[0];
var touch = touches[0];
var fromPoint = {
x: preTouch.clientX,
y: preTouch.clientY,
};
var toPoint = {
x: touch.clientX,
y: touch.clientY,
};
_this.dispatch('swipe', evt, utils_1.getDirectionAndSpeed(fromPoint, toPoint, Date.now() - _this.touchPrePoints.time));
}
// update touch path
_this.updatePathOfPoint(evt.touches);
for (var i = 0; i < evt.touches.length; i++) {
var touch = evt.touches[i];
// cancel longTap if move out of distance
if (_this.longTapTimer &&
_this.longTapPoint &&
_this.longTapPoint.identifier === touch.identifier &&
_this.moveOutDistance(touch.identifier)) {
clearTimeout(_this.longTapTimer);
_this.longTapTimer = undefined;
_this.longTapPoint = undefined;
}
}
};
this.onTouchEnd = function (evt) {
// dispatch touchend
_this.dispatch('touchend', evt);
// evt.changedTouches 为结束触摸的点
if (!evt.changedTouches || !evt.changedTouches.length) {
return;
}
for (var i = 0; i < evt.changedTouches.length; i++) {
var touchEnd = evt.changedTouches[i];
// 清除 long tap
if (_this.longTapPoint && _this.longTapPoint.identifier === touchEnd.identifier) {
_this.longTapTimer && clearTimeout(_this.longTapTimer);
_this.longTapTimer = undefined;
_this.longTapPoint = undefined;
}
// double tap
// singleTap event
if (evt.changedTouches.length === 1 && evt.touches.length === 0 && !_this.moveOutDistance(touchEnd.identifier)) {
_this.singleTapTimer = setTimeout(function () {
_this.singleTapTimer = undefined;
_this.dispatch('singleTap', evt);
}, _this.options.singleTapTimeout);
}
var now = Date.now();
// 滑动轨迹
var path = _this.touchPointsPath.get(touchEnd.identifier);
// tap event
// 没有超过长安时间
// 滑动没超过 10
if (path &&
path[0] &&
now - path[0].time < _this.options.longTapTimeout &&
!_this.moveOutDistance(touchEnd.identifier)) {
// dispatch tap event
_this.dispatch('tap', evt);
// double tap event
if (_this.lastTapTime && now - _this.lastTapTime < _this.options.singleTapTimeout) {
_this.singleTapTimer && clearTimeout(_this.singleTapTimer);
_this.singleTapTimer = undefined;
_this.lastTapTime = undefined;
_this.dispatch('doubleTap', evt);
}
else {
_this.lastTapTime = now;
}
}
// 清除滑动轨迹
_this.touchPointsPath.delete(touchEnd.identifier);
}
// clear touch points
_this.clearPrePoints(evt.changedTouches);
};
this.onTouchCancel = function (evt) {
var _a;
// dispatch touchcancel
_this.dispatch('touchcancel', evt);
// cancel longTap
for (var i = 0; i < evt.touches.length; i++) {
var touch = evt.touches[i];
if (((_a = _this.longTapPoint) === null || _a === void 0 ? void 0 : _a.identifier) === touch.identifier) {
_this.longTapTimer && clearTimeout(_this.longTapTimer);
_this.longTapTimer = undefined;
_this.longTapPoint = undefined;
_this.touchPointsPath.delete(touch.identifier);
}
}
// clear touch points
_this.clearPrePoints(evt.changedTouches);
};
var element = typeof el === 'string' ? document.querySelector(el) : el;
if (!element) {
throw new Error("CrossGesture: Element " + el + " does not exists on the document!");
}
this.element = element;
this.element.addEventListener('touchstart', this.onTouchStart);
this.element.addEventListener('touchmove', this.onTouchMove, { passive: false });
this.element.addEventListener('touchend', this.onTouchEnd);
this.element.addEventListener('touchcancel', this.onTouchCancel);
this.element.addEventListener('touchstart', this.onTouchStart);
this.element.addEventListener('mousedown', this.onMouseDown);
this.element.addEventListener('mousemove', this.onMouseMove);
this.element.addEventListener('mouseup', this.onMouseUp);
this.element.addEventListener('pointerdown', this.onPointerDown);
this.element.addEventListener('pointerup', this.onPointerUp);
this.element.addEventListener('pointermove', this.onPointerMove);
this.element.addEventListener('wheel', this.onWheel);
}
CrossGesture.prototype.updatePathOfPoint = function (touches) {
this.touchPrePoints = {
points: Array.from(touches),
time: Date.now(),
};
for (var i = 0; i < touches.length; i++) {
var touch = touches[i];
var path = this.touchPointsPath.get(touch.identifier);
if (!path) {
path = [];
this.touchPointsPath.set(touch.identifier, path);
}
path.push({
time: Date.now(),
pageX: touch.pageX,
pageY: touch.pageY,
});
}
};
CrossGesture.prototype.dispatch = function (eventType, evt, detail) {
var listeners = this.listenersMap.get(eventType);
if (!listeners) {
return;
}
listeners.forEach(function (l) {
l(evt, detail);
});
};
CrossGesture.prototype.moveOutDistance = function (key, distance) {
if (distance === void 0) { distance = MOVE_OUT_DISTANCE; }
var path = this.touchPointsPath.get(key);
if (!path) {
return false;
}
var firstPoint = path[0];
for (var i = 1; i < path.length; i++) {
var point = path[i];
if (point.pageX - firstPoint.pageX > distance || point.pageY - firstPoint.pageY > distance) {
return true;
}
}
return false;
};
CrossGesture.prototype.clearPrePoints = function (touches) {
if (!this.touchPrePoints.points || !this.touchPrePoints.points.length) {
return;
}
var touchesMap = new Map();
for (var i = 0; i < touches.length; i++) {
var touch = touches[i];
touchesMap.set(touch.identifier, touch);
}
this.touchPrePoints.points = this.touchPrePoints.points.filter(function (p) { return !touchesMap.has(p.identifier); });
};
CrossGesture.prototype.dispatchPressMove = function (evt) {
var touch = evt;
var rect = this.element.getBoundingClientRect();
if (touch.touches) {
if (touch.touches.length !== 1) {
return;
}
return this.dispatch('pressMove', touch, {
point: {
x: touch.touches[0].clientX - rect.x,
y: touch.touches[0].clientY - rect.y,
},
});
}
var mouse = evt;
return this.dispatch('pressMove', touch, {
point: {
x: mouse.clientX - rect.x,
y: mouse.clientY - rect.y,
},
});
};
CrossGesture.prototype.addListener = function (eventType, listener) {
var listeners = this.listenersMap.get(eventType);
if (!listeners) {
listeners = [];
this.listenersMap.set(eventType, listeners);
}
listeners.push(listener);
};
CrossGesture.prototype.removeListener = function (eventType, listener) {
var listeners = this.listenersMap.get(eventType);
if (!listeners) {
return;
}
// clear event timeout
if (eventType === 'singleTap') {
this.singleTapTimer && clearTimeout(this.singleTapTimer);
this.singleTapTimer = undefined;
}
else if (eventType === 'longTap') {
this.longTapTimer && clearTimeout(this.longTapTimer);
this.longTapTimer = undefined;
this.longTapPoint = undefined;
}
// clear listener
this.listenersMap.set(eventType, listeners.filter(function (cb) { return cb !== listener; }));
};
CrossGesture.prototype.destroy = function () {
this.singleTapTimer && clearTimeout(this.singleTapTimer);
this.longTapTimer && clearTimeout(this.longTapTimer);
this.singleTapTimer = undefined;
this.longTapTimer = undefined;
this.longTapPoint = undefined;
this.lastTapTime = undefined;
this.touchPrePoints.points = undefined;
this.touchPrePoints.time = undefined;
this.touchPointsPath.clear();
this.listenersMap.clear();
};
return CrossGesture;
}());
exports.CrossGesture = CrossGesture;
//# sourceMappingURL=index.js.map