UNPKG

@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
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