@egjs/axes
Version:
A module used to change the information of user action entered by various input devices such as touch screen or mouse into the logical virtual coordinates. You can easily create a UI that responds to user actions.
263 lines • 11.7 kB
JavaScript
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
import { $, isCssPropsFromAxes, setCssProps, revertCssProps, useDirection, getDirection, } from "../utils";
import { IS_IOS_SAFARI, IOS_EDGE_THRESHOLD, DIRECTION_NONE, DIRECTION_VERTICAL, DIRECTION_HORIZONTAL, MOUSE_LEFT, ANY, } from "../const";
import { convertInputType, getAddEventOptions, toAxis, } from "./InputType";
export var getDirectionByAngle = function (angle, thresholdAngle) {
if (thresholdAngle < 0 || thresholdAngle > 90) {
return DIRECTION_NONE;
}
var toAngle = Math.abs(angle);
return toAngle > thresholdAngle && toAngle < 180 - thresholdAngle
? DIRECTION_VERTICAL
: DIRECTION_HORIZONTAL;
};
var PanInput = (function () {
function PanInput(el, options) {
var _this = this;
this.axes = [];
this.element = null;
this._enabled = false;
this._activeEvent = null;
this._atRightEdge = false;
this._rightEdgeTimer = 0;
this._dragged = false;
this._isOverThreshold = false;
this._preventClickWhenDragged = function (e) {
if (_this._dragged) {
e.preventDefault();
e.stopPropagation();
}
_this._dragged = false;
};
this._voidFunction = function () { };
this.element = $(el);
this.options = __assign({ inputType: ["touch", "mouse", "pointer"], inputKey: [ANY], inputButton: [MOUSE_LEFT], scale: [1, 1], thresholdAngle: 45, threshold: 0, preventClickOnDrag: false, preventDefaultOnDrag: false, iOSEdgeSwipeThreshold: IOS_EDGE_THRESHOLD, releaseOnScroll: false, touchAction: null }, options);
this._onPanstart = this._onPanstart.bind(this);
this._onPanmove = this._onPanmove.bind(this);
this._onPanend = this._onPanend.bind(this);
}
PanInput.prototype.mapAxes = function (axes) {
this._direction = getDirection(!!axes[0], !!axes[1]);
this.axes = axes;
};
PanInput.prototype.connect = function (observer) {
if (this._activeEvent) {
this._detachElementEvent();
this._detachWindowEvent(this._activeEvent);
}
this._attachElementEvent(observer);
return this;
};
PanInput.prototype.disconnect = function () {
this._detachElementEvent();
this._detachWindowEvent(this._activeEvent);
this._direction = DIRECTION_NONE;
return this;
};
PanInput.prototype.destroy = function () {
this.disconnect();
this.element = null;
};
PanInput.prototype.enable = function () {
var activeEvent = convertInputType(this.options.inputType);
if (!activeEvent) {
throw new Error("PanInput cannot be enabled if there is no available input event.");
}
else if (!this._enabled) {
this._enabled = true;
this._originalCssProps = setCssProps(this.element, this.options, this._direction);
}
return this;
};
PanInput.prototype.disable = function () {
if (this._enabled) {
this._enabled = false;
if (!isCssPropsFromAxes(this._originalCssProps)) {
revertCssProps(this.element, this._originalCssProps);
}
}
return this;
};
PanInput.prototype.isEnabled = function () {
return this._enabled;
};
PanInput.prototype.release = function () {
var activeEvent = this._activeEvent;
var prevEvent = activeEvent.prevEvent;
activeEvent.onRelease();
this._observer.release(this, prevEvent, [0, 0]);
this._detachWindowEvent(activeEvent);
return this;
};
PanInput.prototype._onPanstart = function (event) {
var _a = this.options, inputKey = _a.inputKey, inputButton = _a.inputButton, preventDefaultOnDrag = _a.preventDefaultOnDrag;
var activeEvent = this._activeEvent;
var panEvent = activeEvent.onEventStart(event, inputKey, inputButton);
if (!panEvent ||
!this._enabled ||
activeEvent.getTouches(event, inputButton) > 1) {
return;
}
if (panEvent.srcEvent.cancelable !== false) {
var edgeThreshold = this.options.iOSEdgeSwipeThreshold;
this._dragged = false;
this._isOverThreshold = false;
this._observer.hold(this, panEvent);
this._atRightEdge =
IS_IOS_SAFARI && panEvent.center.x > window.innerWidth - edgeThreshold;
this._attachWindowEvent(activeEvent);
(preventDefaultOnDrag && panEvent.srcEvent.type !== "touchstart") && panEvent.srcEvent.preventDefault();
activeEvent.prevEvent = panEvent;
}
};
PanInput.prototype._onPanmove = function (event) {
var _this = this;
var _a = this.options, iOSEdgeSwipeThreshold = _a.iOSEdgeSwipeThreshold, preventClickOnDrag = _a.preventClickOnDrag, releaseOnScroll = _a.releaseOnScroll, inputKey = _a.inputKey, inputButton = _a.inputButton, threshold = _a.threshold, thresholdAngle = _a.thresholdAngle;
var activeEvent = this._activeEvent;
var panEvent = activeEvent.onEventMove(event, inputKey, inputButton);
var touches = activeEvent.getTouches(event, inputButton);
if (touches === 0 ||
(releaseOnScroll && panEvent && !panEvent.srcEvent.cancelable)) {
this._onPanend(event);
return;
}
if (!panEvent || !this._enabled || touches > 1) {
return;
}
var userDirection = getDirectionByAngle(panEvent.angle, thresholdAngle);
var useHorizontal = useDirection(DIRECTION_HORIZONTAL, this._direction, userDirection);
var useVertical = useDirection(DIRECTION_VERTICAL, this._direction, userDirection);
if (activeEvent.prevEvent && IS_IOS_SAFARI) {
var swipeLeftToRight = panEvent.center.x < 0;
if (swipeLeftToRight) {
this.release();
return;
}
else if (this._atRightEdge) {
clearTimeout(this._rightEdgeTimer);
var swipeRightToLeft = panEvent.deltaX < -iOSEdgeSwipeThreshold;
if (swipeRightToLeft) {
this._atRightEdge = false;
}
else {
this._rightEdgeTimer = window.setTimeout(function () { return _this.release(); }, 100);
}
}
}
var distance = this._getDistance([panEvent.deltaX, panEvent.deltaY], [useHorizontal, useVertical]);
var offset = this._getOffset([panEvent.offsetX, panEvent.offsetY], [useHorizontal, useVertical]);
var prevent = offset.some(function (v) { return v !== 0; });
if (prevent) {
if (panEvent.srcEvent.cancelable !== false) {
panEvent.srcEvent.preventDefault();
}
panEvent.srcEvent.stopPropagation();
}
panEvent.preventSystemEvent = prevent;
if (prevent && (this._isOverThreshold || distance >= threshold)) {
this._dragged = preventClickOnDrag;
this._isOverThreshold = true;
this._observer.change(this, panEvent, toAxis(this.axes, offset));
}
activeEvent.prevEvent = panEvent;
};
PanInput.prototype._onPanend = function (event) {
var inputButton = this.options.inputButton;
var activeEvent = this._activeEvent;
activeEvent.onEventEnd(event);
if (!this._enabled || activeEvent.getTouches(event, inputButton) !== 0) {
return;
}
this._detachWindowEvent(activeEvent);
clearTimeout(this._rightEdgeTimer);
var prevEvent = activeEvent.prevEvent;
var velocity = this._isOverThreshold ? this._getOffset([
Math.abs(prevEvent.velocityX) * prevEvent.directionX,
Math.abs(prevEvent.velocityY) * prevEvent.directionY,
], [
useDirection(DIRECTION_HORIZONTAL, this._direction),
useDirection(DIRECTION_VERTICAL, this._direction),
]) : [0, 0];
activeEvent.onRelease();
this._observer.release(this, prevEvent, velocity);
};
PanInput.prototype._attachWindowEvent = function (activeEvent) {
var _this = this;
activeEvent === null || activeEvent === void 0 ? void 0 : activeEvent.move.forEach(function (event) {
window.addEventListener(event, _this._onPanmove, getAddEventOptions(event));
});
activeEvent === null || activeEvent === void 0 ? void 0 : activeEvent.end.forEach(function (event) {
window.addEventListener(event, _this._onPanend, getAddEventOptions(event));
});
};
PanInput.prototype._detachWindowEvent = function (activeEvent) {
var _this = this;
activeEvent === null || activeEvent === void 0 ? void 0 : activeEvent.move.forEach(function (event) {
window.removeEventListener(event, _this._onPanmove);
});
activeEvent === null || activeEvent === void 0 ? void 0 : activeEvent.end.forEach(function (event) {
window.removeEventListener(event, _this._onPanend);
});
};
PanInput.prototype._getOffset = function (properties, direction) {
var scale = this.options.scale;
return [
direction[0] ? properties[0] * scale[0] : 0,
direction[1] ? properties[1] * scale[1] : 0,
];
};
PanInput.prototype._getDistance = function (delta, direction) {
return Math.sqrt(Number(direction[0]) * Math.pow(delta[0], 2) +
Number(direction[1]) * Math.pow(delta[1], 2));
};
PanInput.prototype._attachElementEvent = function (observer) {
var _this = this;
var activeEvent = convertInputType(this.options.inputType);
var element = this.element;
if (!activeEvent) {
return;
}
if (!element) {
throw new Error("Element to connect input does not exist.");
}
this._observer = observer;
this.enable();
this._activeEvent = activeEvent;
element.addEventListener("click", this._preventClickWhenDragged, true);
activeEvent.start.forEach(function (event) {
element.addEventListener(event, _this._onPanstart);
});
activeEvent.move.forEach(function (event) {
element.addEventListener(event, _this._voidFunction);
});
};
PanInput.prototype._detachElementEvent = function () {
var _this = this;
var activeEvent = this._activeEvent;
var element = this.element;
if (element) {
element.removeEventListener("click", this._preventClickWhenDragged, true);
activeEvent === null || activeEvent === void 0 ? void 0 : activeEvent.start.forEach(function (event) {
element.removeEventListener(event, _this._onPanstart);
});
activeEvent === null || activeEvent === void 0 ? void 0 : activeEvent.move.forEach(function (event) {
element.removeEventListener(event, _this._voidFunction);
});
}
this.disable();
this._observer = null;
};
return PanInput;
}());
export { PanInput };
//# sourceMappingURL=PanInput.js.map