/*!
* Copyright (c) 2017 NAVER Corp.
* @egjs/axes project is licensed under the MIT license
*
* @egjs/axes JavaScript library
*
*
* @version 2.0.0-rc.1
*
* All-in-one packaged file for ease use of '@egjs/axes' with below dependencies.
* NOTE: This is not an official distribution file and is only for user convenience.
*
*/
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define("Axes", [], factory);
else if(typeof exports === 'object')
exports["Axes"] = factory();
else
root["eg"] = root["eg"] || {}, root["eg"]["Axes"] = factory();
})(this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ }
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 3);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
var __assign = (this && this.__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;
};
Object.defineProperty(exports, "__esModule", { value: true });
;
var AxisManager = (function () {
function AxisManager(options) {
var _this = this;
this.options = options;
this._pos = Object.keys(this.options.axis).reduce(function (acc, v) {
acc[v] = _this.options.axis[v].range[0];
return acc;
}, {});
}
AxisManager.equal = function (pos1, pos2) {
for (var k in pos1) {
if (pos1[k] !== pos2[k]) {
return false;
}
}
return true;
};
AxisManager.prototype.get = function (axes) {
var _this = this;
if (axes) {
return axes.reduce(function (acc, v) {
if (v) {
acc[v] = _this._pos[v];
}
return acc;
}, {});
}
else {
return __assign({}, this._pos);
}
};
AxisManager.prototype.moveTo = function (pos) {
for (var k in pos) {
if (k) {
this._pos[k] = pos[k];
}
}
return __assign({}, this._pos);
};
AxisManager.prototype.every = function (pos, callback) {
var axisOptions = this.options.axis;
for (var k in pos) {
if (k) {
if (!callback(pos[k], k, axisOptions[k])) {
return false;
}
}
}
return true;
};
AxisManager.prototype.filter = function (pos, callback) {
var filtered = {};
var axisOptions = this.options.axis;
for (var k in pos) {
if (k) {
callback(pos[k], k, axisOptions[k]) && (filtered[k] = pos[k]);
}
}
return filtered;
};
AxisManager.prototype.map = function (pos, callback) {
var tranformed = {};
var axisOptions = this.options.axis;
for (var k in pos) {
if (k) {
tranformed[k] = callback(pos[k], k, axisOptions[k]);
}
}
return tranformed;
};
return AxisManager;
}());
exports.AxisManager = AxisManager;
;
/***/ }),
/* 1 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var Coordinate = {
getInsidePosition: function (destPos, range, circular, bounce) {
var includeBounce = !!bounce;
var targetRange = includeBounce ?
[range[0] - bounce[0], range[1] + bounce[1]] : range.concat();
var toDestPos = destPos;
if (!circular[0]) {
toDestPos = Math.max(targetRange[0], toDestPos);
}
if (!circular[1]) {
toDestPos = Math.min(targetRange[1], toDestPos);
}
return Math.min(range[1], Math.max(range[0], toDestPos));
},
// determine outside
isOutside: function (pos, range) {
return pos < range[0] || pos > range[1];
},
getDuration: function (distance, deceleration) {
var duration = Math.sqrt(distance / deceleration * 2);
// when duration is under 100, then value is zero
return duration < 100 ? 0 : duration;
},
isCircular: function (destPos, range, circular) {
return (circular[1] && destPos > range[1]) ||
(circular[0] && destPos < range[0]);
},
getCirculatedPos: function (pos, range, circular) {
var toPos = pos;
var min = range[0];
var max = range[1];
var length = max - min;
if (circular[1] && pos > max) {
toPos = (toPos - max) % length + min;
}
if (circular[0] && pos < min) {
toPos = (toPos - min) % length + max;
}
return +toPos.toFixed(5);
},
};
exports.default = Coordinate;
/***/ }),
/* 2 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.UNIQUEKEY = "__MOVABLECOORD__";
exports.SUPPORT_TOUCH = "ontouchstart" in window;
exports.TRANSFORM = (function () {
var bodyStyle = (document.head || document.getElementsByTagName("head")[0]).style;
var target = ["transform", "webkitTransform", "msTransform", "mozTransform"];
for (var i = 0, len = target.length; i < len; i++) {
if (target[i] in bodyStyle) {
return target[i];
}
}
return "";
})();
/***/ }),
/* 3 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
var _Axes = __webpack_require__(4);
var _Axes2 = _interopRequireDefault(_Axes);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
_Axes2.default.VERSION = "2.0.0-rc.1"; /**
* Copyright (c) NAVER Corp.
* egjs-axes projects are licensed under the MIT license
*/
module.exports = _Axes2.default;
/***/ }),
/* 4 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __assign = (this && this.__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;
};
Object.defineProperty(exports, "__esModule", { value: true });
var Component = __webpack_require__(5);
var AnimationManager_1 = __webpack_require__(6);
var EventManager_1 = __webpack_require__(7);
var InterruptManager_1 = __webpack_require__(8);
var AxisManager_1 = __webpack_require__(0);
var InputObserver_1 = __webpack_require__(9);
var HammerInput_1 = __webpack_require__(10);
var const_1 = __webpack_require__(2);
/**
* Copyright (c) NAVER Corp.
* egjs-axes projects are licensed under the MIT license
*/
/**
* A module used to change the information of user action entered by various input devices such as touch screen or mouse into logical coordinates within the virtual coordinate system. The coordinate information sorted by time events occurred is provided if animations are made by user actions.
* @alias eg.Axes
* @extends eg.Component
*
* @support {"ie": "10+", "ch" : "latest", "ff" : "latest", "sf" : "latest", "edge" : "latest", "ios" : "7+", "an" : "2.3+ (except 3.x)"}
*/
var Axes = (function (_super) {
__extends(Axes, _super);
function Axes(options) {
var _this = _super.call(this) || this;
_this.options = __assign({
easing: function easeOutCubic(x) {
return 1 - Math.pow(1 - x, 3);
},
interruptable: true,
maximumDuration: Infinity,
deceleration: 0.0006,
axis: {},
}, options);
_this._complementOptions();
_this._em = new EventManager_1.EventManager(_this);
_this._axm = new AxisManager_1.AxisManager(_this.options);
_this._itm = new InterruptManager_1.InterruptManager(_this.options);
_this._am = new AnimationManager_1.AnimationManager(_this.options, _this._itm, _this._em, _this._axm);
_this._io = new InputObserver_1.InputObserver(_this.options, _this._itm, _this._em, _this._axm, _this._am);
return _this;
}
/**
* set up 'css' expression
* @private
*/
Axes.prototype._complementOptions = function () {
var _this = this;
Object.keys(this.options.axis).forEach(function (axis) {
_this.options.axis[axis] = __assign({
range: [0, 100],
bounce: [0, 0],
margin: [0, 0],
circular: [false, false]
}, _this.options.axis[axis]);
["bounce", "margin", "circular"].forEach(function (v) {
var axisOption = _this.options.axis;
var key = axisOption[axis][v];
if (/string|number|boolean/.test(typeof key)) {
axisOption[axis][v] = [key, key];
}
});
});
};
Axes.prototype.mapInput = function (axes, inputType) {
var mapped;
if (typeof axes === "string") {
mapped = [axes];
}
else {
mapped = axes.concat();
}
inputType.mapAxes(mapped);
inputType.create(this._io);
return this;
};
Axes.prototype.get = function (axes) {
return this._axm.get(axes);
};
Axes.prototype.setTo = function (pos, duration) {
if (duration === void 0) { duration = 0; }
this._am.setTo(pos, duration);
return this;
};
Axes.prototype.destroy = function () {
this._em.destroy();
};
Axes.HammerInput = HammerInput_1.HammerInput;
Axes.TRANSFORM = const_1.TRANSFORM;
return Axes;
}(Component));
exports.default = Axes;
/***/ }),
/* 5 */
/***/ (function(module, exports, __webpack_require__) {
(function webpackUniversalModuleDefinition(root, factory) {
if(true)
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else if(typeof exports === 'object')
exports["Component"] = factory();
else
root["eg"] = root["eg"] || {}, root["eg"]["Component"] = factory();
})(this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ return installedModules[moduleId].exports;
/******/
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ // Flag the module as loaded
/******/ module.l = true;
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;
/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;
/******/
/******/ // identity function for calling harmony imports with the correct context
/******/ __webpack_require__.i = function(value) { return value; };
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ }
/******/ };
/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 1);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
/**
* Copyright (c) 2015 NAVER Corp.
* egjs projects are licensed under the MIT license
*/
/**
* A class used to manage events and options in a component
* @class
* @group egjs
* @name eg.Component
* @ko 컴포넌트의 이벤트와 옵션을 관리할 수 있게 하는 클래스
*
* @support {"ie": "7+", "ch" : "latest", "ff" : "latest", "sf" : "latest", "edge" : "latest", "ios" : "7+", "an" : "2.1+ (except 3.x)"}
*/
var Component = exports.Component = function () {
function Component() {
_classCallCheck(this, Component);
this._eventHandler = {};
this.options = {};
}
/**
* Sets options in a component or returns them.
* @ko 컴포넌트에 옵션을 설정하거나 옵션을 반환한다
* @method eg.Component#option
* @param {String} key The key of the option옵션의 키
* @param {Object} [value] The option value that corresponds to a given key 키에 해당하는 옵션값
* @return {eg.Component|Object} An instance, an option value, or an option object of a component itself.
- If both key and value are used to set an option, it returns an instance of a component itself.
- If only a key is specified for the parameter, it returns the option value corresponding to a given key.
- If nothing is specified, it returns an option object. 컴포넌트 자신의 인스턴스나 옵션값, 옵션 객체.
- 키와 값으로 옵션을 설정하면 컴포넌트 자신의 인스턴스를 반환한다.
- 파라미터에 키만 설정하면 키에 해당하는 옵션값을 반환한다.
- 파라미터에 아무것도 설정하지 않으면 옵션 객체를 반환한다.
* @example
class Some extends eg.Component{
}
const some = new Some({
"foo": 1,
"bar": 2
});
some.option("foo"); // return 1
some.option("foo",3); // return some instance
some.option(); // return options object.
some.option({
"foo" : 10,
"bar" : 20,
"baz" : 30
}); // return some instance.
*/
_createClass(Component, [{
key: "option",
value: function option() {
if (arguments.length >= 2) {
var _key = arguments.length <= 0 ? undefined : arguments[0];
var value = arguments.length <= 1 ? undefined : arguments[1];
this.options[_key] = value;
return this;
}
var key = arguments.length <= 0 ? undefined : arguments[0];
if (typeof key === "string") {
return this.options[key];
}
if (arguments.length === 0) {
return this.options;
}
var options = key;
this.options = options;
return this;
}
/**
* Triggers a custom event.
* @ko 커스텀 이벤트를 발생시킨다
* @method eg.Component#trigger
* @param {String} eventName The name of the custom event to be triggered 발생할 커스텀 이벤트의 이름
* @param {Object} customEvent Event data to be sent when triggering a custom event 커스텀 이벤트가 발생할 때 전달할 데이터
* @return {Boolean} Indicates whether the event has occurred. If the stop() method is called by a custom event handler, it will return false and prevent the event from occurring. 이벤트 발생 여부. 커스텀 이벤트 핸들러에서 stop() 메서드를 호출하면 'false'를 반환하고 이벤트 발생을 중단한다.
* @example
class Some extends eg.Component{
some(){
this.trigger("hi");// fire hi event.
}
}
*/
}, {
key: "trigger",
value: function trigger(eventName) {
var customEvent = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var handlerList = this._eventHandler[eventName] || [];
var hasHandlerList = handlerList.length > 0;
if (!hasHandlerList) {
return true;
}
// If detach method call in handler in first time then handeler list calls.
handlerList = handlerList.concat();
customEvent.eventType = eventName;
var isCanceled = false;
var arg = [customEvent];
var i = void 0;
customEvent.stop = function () {
return isCanceled = true;
};
for (var _len = arguments.length, restParam = Array(_len > 2 ? _len - 2 : 0), _key2 = 2; _key2 < _len; _key2++) {
restParam[_key2 - 2] = arguments[_key2];
}
if (restParam.length >= 1) {
arg = arg.concat(restParam);
}
for (i in handlerList) {
handlerList[i].apply(this, arg);
}
return !isCanceled;
}
/**
* Executed event just one time.
* @ko 이벤트가 한번만 실행된다.
* @method eg.Component#once
* @param {eventName} eventName The name of the event to be attached 등록할 이벤트의 이름
* @param {Function} handlerToAttach The handler function of the event to be attached 등록할 이벤트의 핸들러 함수
* @return {eg.Component} An instance of a component itself컴포넌트 자신의 인스턴스
* @example
class Some extends eg.Component{
hi(){
alert("hi");
}
thing(){
this.once("hi", this.hi);
}
}
var some = new Some();
some.thing();
some.trigger("hi");
// fire alert("hi");
some.trigger("hi");
// Nothing happens
*/
}, {
key: "once",
value: function once(eventName, handlerToAttach) {
if ((typeof eventName === "undefined" ? "undefined" : _typeof(eventName)) === "object" && typeof handlerToAttach === "undefined") {
var eventHash = eventName;
var i = void 0;
for (i in eventHash) {
this.once(i, eventHash[i]);
}
return this;
} else if (typeof eventName === "string" && typeof handlerToAttach === "function") {
var self = this;
this.on(eventName, function listener() {
for (var _len2 = arguments.length, arg = Array(_len2), _key3 = 0; _key3 < _len2; _key3++) {
arg[_key3] = arguments[_key3];
}
handlerToAttach.apply(self, arg);
self.off(eventName, listener);
});
}
return this;
}
/**
* Checks whether an event has been attached to a component.
* @ko 컴포넌트에 이벤트가 등록됐는지 확인한다.
* @method eg.Component#hasOn
* @param {String} eventName The name of the event to be attached 등록 여부를 확인할 이벤트의 이름
* @return {Boolean} Indicates whether the event is attached. 이벤트 등록 여부
* @example
class Some extends eg.Component{
some(){
this.hasOn("hi");// check hi event.
}
}
*/
}, {
key: "hasOn",
value: function hasOn(eventName) {
return !!this._eventHandler[eventName];
}
/**
* Attaches an event to a component.
* @ko 컴포넌트에 이벤트를 등록한다.
* @method eg.Component#on
* @param {eventName} eventName The name of the event to be attached 등록할 이벤트의 이름
* @param {Function} handlerToAttach The handler function of the event to be attached 등록할 이벤트의 핸들러 함수
* @return {eg.Component} An instance of a component itself컴포넌트 자신의 인스턴스
* @example
class Some extends eg.Component{
hi(){
console.log("hi");
}
some(){
this.on("hi",this.hi); //attach event
}
}
*/
}, {
key: "on",
value: function on(eventName, handlerToAttach) {
if ((typeof eventName === "undefined" ? "undefined" : _typeof(eventName)) === "object" && typeof handlerToAttach === "undefined") {
var eventHash = eventName;
var name = void 0;
for (name in eventHash) {
this.on(name, eventHash[name]);
}
return this;
} else if (typeof eventName === "string" && typeof handlerToAttach === "function") {
var handlerList = this._eventHandler[eventName];
if (typeof handlerList === "undefined") {
handlerList = this._eventHandler[eventName] = [];
}
handlerList.push(handlerToAttach);
}
return this;
}
/**
* Detaches an event from the component.
* @ko 컴포넌트에 등록된 이벤트를 해제한다
* @method eg.Component#off
* @param {eventName} eventName The name of the event to be detached 해제할 이벤트의 이름
* @param {Function} handlerToDetach The handler function of the event to be detached 해제할 이벤트의 핸들러 함수
* @return {eg.Component} An instance of a component itself 컴포넌트 자신의 인스턴스
* @example
class Some extends eg.Component{
hi(){
console.log("hi");
}
some(){
this.off("hi",this.hi); //detach event
}
}
*/
}, {
key: "off",
value: function off(eventName, handlerToDetach) {
// All event detach.
if (typeof eventName === "undefined") {
this._eventHandler = {};
return this;
}
// All handler of specific event detach.
if (typeof handlerToDetach === "undefined") {
if (typeof eventName === "string") {
this._eventHandler[eventName] = undefined;
return this;
} else {
var eventHash = eventName;
var name = void 0;
for (name in eventHash) {
this.off(name, eventHash[name]);
}
return this;
}
}
// The handler of specific event detach.
var handlerList = this._eventHandler[eventName];
if (handlerList) {
var k = void 0;
var handlerFunction = void 0;
for (k = 0, handlerFunction; handlerFunction = handlerList[k]; k++) {
if (handlerFunction === handlerToDetach) {
handlerList = handlerList.splice(k, 1);
break;
}
}
}
return this;
}
}]);
return Component;
}();
/***/ }),
/* 1 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
var _component = __webpack_require__(0);
module.exports = _component.Component;
/***/ })
/******/ ]);
});
//# sourceMappingURL=component.js.map
/***/ }),
/* 6 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
var __assign = (this && this.__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;
};
Object.defineProperty(exports, "__esModule", { value: true });
var Coordinate_1 = __webpack_require__(1);
var AxisManager_1 = __webpack_require__(0);
var AnimationManager = (function () {
function AnimationManager(options, itm, em, axm) {
this.options = options;
this.itm = itm;
this.em = em;
this.axm = axm;
}
AnimationManager.prototype.grab = function (axes) {
if (this._animateParam && !axes.length) {
var orgPos_1 = this.axm.get(axes);
var pos = this.axm.map(orgPos_1, function (v, k, opt) { return Coordinate_1.default.getCirculatedPos(v, opt.range, opt.circular); });
if (!this.axm.every(pos, function (v, k) { return orgPos_1[k] === v; })) {
this.em.triggerChange(this.axm.moveTo(pos), true);
}
this._animateParam = null;
this._raf && window.cancelAnimationFrame(this._raf);
this._raf = null;
// this.em.trigger("animationEnd");
}
};
AnimationManager.prototype.createAnimationParam = function (absPos, duration, inputEvent) {
if (inputEvent === void 0) { inputEvent = null; }
var maximumDuration = this.options.maximumDuration;
var depaPos = this.axm.get(Object.keys(absPos));
var destPos = this.axm.map(absPos, function (v, k, opt) {
// depaPos[k],
return Coordinate_1.default.getInsidePosition(v, opt.range, opt.circular, opt.bounce);
});
// remove unnecessary axis
destPos = this.axm.filter(destPos, function (v, k) { return depaPos[k] !== v; });
depaPos = this.axm.filter(depaPos, function (v, k) { return k in destPos; });
// destPos = this.apmCoordinate.isOutToOut(pos, destPos, min, max) ? pos : destPos;
var distance = this.axm.map(destPos, function (v, k) { return v - depaPos[k]; });
return {
depaPos: depaPos,
destPos: destPos,
isBounce: this.axm.every(destPos, function (v, k, opt) { return Coordinate_1.default.isOutside(v, opt.range); }),
isCircular: this.axm.every(destPos, function (v, k, opt) { return Coordinate_1.default.isCircular(v, opt.range, opt.circular); }),
duration: maximumDuration > duration ? duration : maximumDuration,
distance: distance,
inputEvent: inputEvent,
};
};
AnimationManager.prototype.restore = function (axes, complete, inputEvent) {
var _this = this;
if (inputEvent === void 0) { inputEvent = null; }
var pos = this.axm.get(axes);
var destPos = this.axm.map(pos, function (v, k, opt) { return Math.min(opt.range[1], Math.max(opt.range[0], v)); });
var durations = this.axm.map(destPos, function (v) { return Coordinate_1.default.getDuration(v, _this.options.deceleration); });
this.animateLoop(this.createAnimationParam(destPos, Object.keys(durations).reduce(function (max, v) { return Math.max(max, durations[v]); }, -Infinity), inputEvent), complete);
};
AnimationManager.prototype.animationEnd = function () {
this._animateParam = null;
// for Circular
this.setTo(this.axm.map(this.axm.get(), function (v, k, opt) { return Coordinate_1.default.getCirculatedPos(Math.round(v), opt.range, opt.circular); }));
this.itm.setInterrupt(false);
/**
* This event is fired when animation ends.
* @ko 에니메이션이 끝났을 때 발생한다.
* @name eg.MovableCoord#animationEnd
* @event
*/
this.em.trigger("animationEnd");
};
AnimationManager.prototype.animateLoop = function (param, complete) {
this._animateParam = __assign({}, param);
this._animateParam.startTime = new Date().getTime();
if (param.duration) {
var info_1 = this._animateParam;
var self_1 = this;
(function loop() {
self_1._raf = null;
if (self_1.frame(info_1) >= 1) {
complete();
return;
} // animationEnd
self_1._raf = window.requestAnimationFrame(loop);
})();
}
else {
this.em.triggerChange(this.axm.moveTo(param.destPos));
complete();
}
};
AnimationManager.prototype.animateTo = function (absPos, duration, inputEvent) {
var _this = this;
if (inputEvent === void 0) { inputEvent = null; }
var param = this.createAnimationParam(absPos, duration, inputEvent);
var retTrigger = this.em.trigger("animationStart", param);
// You can't stop the 'animationStart' event when 'circular' is true.
if (param.isCircular && !retTrigger) {
throw new Error("You can't stop the 'animation' event when 'circular' is true.");
}
if (retTrigger) {
var queue_1 = [];
var dequeue_1 = function () {
var task = queue_1.shift();
task && task.call(this);
};
if (!AxisManager_1.AxisManager.equal(param.depaPos, param.destPos)) {
queue_1.push(function () { return _this.animateLoop(param, dequeue_1); });
}
if (this.axm.every(param.destPos, function (v, k, opt) { return Coordinate_1.default.isOutside(v, opt.range); })) {
queue_1.push(function () { return _this.restore(Object.keys(param.destPos), dequeue_1, inputEvent); });
}
queue_1.push(function () { return _this.animationEnd(); });
dequeue_1();
}
};
// animation frame (0~1)
AnimationManager.prototype.frame = function (param) {
var curTime = new Date().getTime() - param.startTime;
var easingPer = this.easing(curTime / param.duration);
var toPos = param.depaPos;
toPos = this.axm.map(toPos, function (v, k, opt) {
v += (param.destPos[k] - v) * easingPer;
return Coordinate_1.default.getCirculatedPos(v, opt.range, opt.circular);
});
this.em.triggerChange(this.axm.moveTo(toPos));
return easingPer;
};
AnimationManager.prototype.easing = function (p) {
// console.log("easing", p, this.options.easing(p));
return p > 1 ? 1 : this.options.easing(p);
};
/**
* Moves an element to specific coordinates.
* @ko 좌표를 이동한다.
* @method eg.MovableCoord#setTo
* @param {Number} x The X coordinate to move to 이동할 x좌표
* @param {Number} y The Y coordinate to move to 이동할 y좌표
* @param {Number} [duration=0] Duration of the animation (unit: ms) 애니메이션 진행 시간(단위: ms)
* @return {eg.MovableCoord} An instance of a module itself 자신의 인스턴스
*/
AnimationManager.prototype.setTo = function (pos, duration) {
if (duration === void 0) { duration = 0; }
var axes = Object.keys(pos);
this.grab(axes);
var orgPos = this.axm.get(axes);
if (AxisManager_1.AxisManager.equal(pos, orgPos)) {
return this;
}
this.itm.setInterrupt(true);
var movedPos = this.axm.filter(pos, function (v, k) { return orgPos[k] !== v; });
if (!Object.keys(movedPos).length) {
return;
}
movedPos = this.axm.map(movedPos, function (v, k, opt) {
v = Coordinate_1.default.getInsidePosition(v, opt.range, opt.circular);
return duration ? v : Coordinate_1.default.getCirculatedPos(v, opt.range, opt.circular);
});
if (AxisManager_1.AxisManager.equal(movedPos, orgPos)) {
return this;
}
else if (duration) {
this.animateTo(movedPos, duration);
}
else {
this.em.triggerChange(this.axm.moveTo(movedPos));
this.itm.setInterrupt(false);
}
return this;
};
/**
* Moves an element from the current coordinates to specific coordinates. The change event is fired when the method is executed.
* @ko 현재 좌표를 기준으로 좌표를 이동한다. 메서드가 실행되면 change 이벤트가 발생한다
* @method eg.MovableCoord#setBy
* @param {Number} x The X coordinate to move to 이동할 x좌표
* @param {Number} y The Y coordinate to move to 이동할 y좌표
* @param {Number} [duration=0] Duration of the animation (unit: ms) 애니메이션 진행 시간(단위: ms)
* @return {eg.MovableCoord} An instance of a module itself 자신의 인스턴스
*/
AnimationManager.prototype.setBy = function (pos, duration) {
if (duration === void 0) { duration = 0; }
return this.setTo(this.axm.map(this.axm.get(Object.keys(pos)), function (v, k) { return v + pos[k]; }), duration);
};
return AnimationManager;
}());
exports.AnimationManager = AnimationManager;
;
/***/ }),
/* 7 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var EventManager = (function () {
function EventManager(axes) {
this.axes = axes;
}
EventManager.prototype.trigger = function (name, option) {
return this.axes.trigger(name, option);
};
// trigger 'change' event
EventManager.prototype.triggerChange = function (pos, event) {
if (event === void 0) { event = null; }
/**
* This event is fired when coordinate changes.
* @ko 좌표가 변경됐을 때 발생하는 이벤트
* @name eg.MovableCoord#change
* @event
*
* @param {Object} param The object of data to be sent when the event is fired 이벤트가 발생할 때 전달되는 데이터 객체
* @param {Array} param.position departure coordinate 좌표
* @param {Number} param.position.0 The X coordinate x 좌표
* @param {Number} param.pos.1 The Y coordinate y 좌표
* @param {Boolean} param.holding Indicates whether a user holds an element on the screen of the device.사용자가 기기의 화면을 누르고 있는지 여부
* @param {Object} param.hammerEvent The event information of Hammer.JS. It returns null if the event is fired through a call to the setTo() or setBy() method.Hammer.JS의 이벤트 정보. setTo() 메서드나 setBy() 메서드를 호출해 이벤트가 발생했을 때는 'null'을 반환한다.
*
*/
this.trigger("change", {
pos: pos,
holding: event !== null,
inputEvent: event,
});
};
EventManager.prototype.destroy = function () {
this.axes.off();
};
return EventManager;
}());
exports.EventManager = EventManager;
;
/***/ }),
/* 8 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var InterruptManager = (function () {
function InterruptManager(options) {
this.options = options;
this._prevented = false; // check whether the animation event was prevented
}
InterruptManager.prototype.isInterrupting = function () {
// when interruptable is 'true', return value is always 'true'.
return this.options.interruptable || this._prevented;
};
InterruptManager.prototype.isInterrupted = function () {
return !this.options.interruptable && this._prevented;
};
InterruptManager.prototype.setInterrupt = function (prevented) {
!this.options.interruptable && (this._prevented = prevented);
};
return InterruptManager;
}());
exports.InterruptManager = InterruptManager;
;
/***/ }),
/* 9 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
var __assign = (this && this.__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;
};
Object.defineProperty(exports, "__esModule", { value: true });
var AxisManager_1 = __webpack_require__(0);
var Coordinate_1 = __webpack_require__(1);
var InputObserver = (function () {
function InputObserver(options, itm, em, axm, am) {
this.options = options;
this.itm = itm;
this.em = em;
this.axm = axm;
this.am = am;
this.isOutside = false;
}
InputObserver.prototype.hold = function (inputType, event) {
if (this.itm.isInterrupted() || !inputType.axes.length) {
return;
}
this.itm.setInterrupt(true);
this.am.grab(inputType.axes);
var pos = this.axm.get();
/**
* This event is fired when a user holds an element on the screen of the device.
* @ko 사용자가 기기의 화면에 손을 대고 있을 때 발생하는 이벤트
* @event eg.MovableCoord#hold
* @param {Object} param The object of data to be sent when the event is fired이벤트가 발생할 때 전달되는 데이터 객체
* @param {Array} param.pos coordinate 좌표 정보
* @param {Number} param.pos.0 The X coordinatex 좌표
* @param {Number} param.pos.1 The Y coordinatey 좌표
* @param {Object} param.hammerEvent The event information of Hammer.JS. It returns null if the event is fired through a call to the setTo() or setBy() method.Hammer.JS의 이벤트 정보. setTo() 메서드나 setBy() 메서드를 호출해 이벤트가 발생했을 때는 'null'을 반환한다.
*
*/
this.em.trigger("hold", {
pos: pos,
inputEvent: event,
});
this.isOutside = !this.axm.every(pos, function (v, k, opt) { return !Coordinate_1.default.isOutside(v, opt.range); });
this.moveDistance = this.axm.get(inputType.axes);
};
InputObserver.prototype.change = function (inputType, event, offset) {
if (!this.itm.isInterrupting() || this.axm.every(offset, function (v) { return v === 0; })) {
return;
}
var depaPos = this.axm.get(inputType.axes);
// for outside logic
this.moveDistance = this.axm.map(this.moveDistance, function (v, k) { return v + offset[k]; });
var destPos = this.axm.map(this.moveDistance, function (v, k, opt) {
return Coordinate_1.default.getCirculatedPos(v, opt.range, opt.circular);
});
// from outside to inside
if (this.isOutside &&
this.axm.every(depaPos, function (v, k, opt) { return !Coordinate_1.default.isOutside(v, opt.range); })) {
this.isOutside = false;
}
destPos = this.atOutside(destPos, this.isOutside);
this.em.triggerChange(this.axm.moveTo(destPos), event);
};
// when move pointer is held in outside
InputObserver.prototype.atOutside = function (pos, isOutside) {
var _this = this;
if (isOutside) {
return this.axm.map(pos, function (v, k, opt) {
var tn = opt.range[0] - (opt.margin[0] + opt.bounce[0]);
var tx = opt.range[1] + (opt.margin[1] + opt.bounce[1]);
return v > tx ? tx : (v < tn ? tn : v);
});
}
else {
// when start pointer is held in inside
// get a initialization slope value to prevent smooth animation.
var initSlope_1 = this.am.easing(0.00001) / 0.00001;
return this.axm.map(pos, function (v, k, opt) {
var min = opt.range[0];
var max = opt.range[1];
var out = [opt.margin[0] + opt.bounce[0], opt.margin[1] + opt.bounce[1]];
if (out[0] === 0 && out[1] === 0) {
return v;
}
if (v < min) {
return min - _this.am.easing((min - v) / (out[0] * initSlope_1)) * out[0];
}
else if (v > max) {
return max + _this.am.easing((v - max) / (out[1] * initSlope_1)) * out[1];
}
return v;
});
}
};
InputObserver.prototype.release = function (inputType, event, offset) {
var _this = this;
if (!this.itm.isInterrupting()) {
return;
}
var pos = this.axm.get(inputType.axes);
var depaPos = this.axm.get();
var destPos = this.axm.map(offset, function (v, k, opt) {
return Coordinate_1.default.getInsidePosition(pos[k] + v, opt.range, opt.circular);
});
var isAnimate = false;
var duration = 0;
if (!AxisManager_1.AxisManager.equal(destPos, pos)) {
var durations_1 = this.axm.map(destPos, function (v, k) { return Coordinate_1.default.getDuration(Math.abs(Math.abs(v) - Math.abs(pos[k])), _this.options.deceleration); });
duration = Object.keys(durations_1).reduce(function (max, v) { return Math.max(max, durations_1[v]); }, -Infinity);
if (duration === 0) {
// console.log("--------moveTo on release---------");
this.em.triggerChange(this.axm.moveTo(destPos), event);
}
else {
isAnimate = true;
}
}
/**
* This event is fired when a user release an element on the screen of the device.
* @ko 사용자가 기기의 화면에서 손을 뗐을 때 발생하는 이벤트
* @event eg.MovableCoord#release
*
* @param {Object} param The object of data to be sent when the event is fired이벤트가 발생할 때 전달되는 데이터 객체
* @param {Array} param.depaPos The coordinates when releasing an element손을 뗐을 때의 좌표현재
* @param {Number} param.depaPos.0 The X coordinate x 좌표
* @param {Number} param.depaPos.1 The Y coordinate y 좌표
* @param {Array} param.destPos The coordinates to move to after releasing an element손을 뗀 뒤에 이동할 좌표
* @param {Number} param.destPos.0 The X coordinate x 좌표
* @param {Number} param.destPos.1 The Y coordinate y 좌표
* @param {Object} param.hammerEvent The event information of Hammer.JS. It returns null if the event is fired through a call to the setTo() or setBy() method.Hammer.JS의 이벤트 정보. setTo() 메서드나 setBy() 메서드를 호출해 이벤트가 발생했을 때는 'null'을 반환한다
*
*/
this.em.trigger("release", {
depaPos: depaPos,
destPos: __assign({}, depaPos, destPos),
inputEvent: event
});
this.moveDistance = null;
if (isAnimate) {
// console.log("--------animation---------");
this.am.animateTo(destPos, this.options.maximumDuration > duration ? duration : this.options.maximumDuration);
}
else {
this.itm.setInterrupt(false);
}
};
return InputObserver;
}());
exports.InputObserver = InputObserver;
;
/***/ }),
/* 10 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __assign = (this && this.__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;
};
Object.defineProperty(exports, "__esModule", { value: true });
var Hammer = __webpack_require__(11);
var const_1 = __webpack_require__(2);
var utils_1 = __webpack_require__(12);
var InputType_1 = __webpack_require__(13);
/**
* Hammer helps you add support for touch gestures to your page
*
* @external Hammer
* @see {@link http://hammerjs.github.io|Hammer.JS}
* @see {@link http://hammerjs.github.io/jsdoc/Hammer.html|Hammer.JS API documents}
* @see Hammer.JS applies specific CSS properties by {@link http://hammerjs.github.io/jsdoc/Hammer.defaults.cssProps.html|default} when creating an instance. The eg.MovableCoord module removes all default CSS properties provided by Hammer.JS
*/
if (typeof Hammer === "undefined") {
throw new Error("The Hammerjs must be loaded before eg.MovableCoord.\nhttp://hammerjs.github.io/");
}
var DIRECTION;
(function (DIRECTION) {
DIRECTION[DIRECTION["DIRECTION_NONE"] = 1] = "DIRECTION_NONE";
DIRECTION[DIRECTION["DIRECTION_HORIZONTAL"] = 6] = "DIRECTION_HORIZONTAL";
DIRECTION[DIRECTION["DIRECTION_VERTICAL"] = 24] = "DIRECTION_VERTICAL";
DIRECTION[DIRECTION["DIRECTION_ALL"] = 30] = "DIRECTION_ALL";
})(DIRECTION || (DIRECTION = {}));
var HammerInput = (function (_super) {
__extends(HammerInput, _super);
function HammerInput(el, options) {
var _this = _super.call(this) || this;
_this._element = utils_1.$(el);
_this.options = __assign({
inputType: ["touch", "mouse"],
scale: [1, 1],
thresholdAngle: 45
}, options);
return _this;
}
HammerInput.convertHammerInputType = function (inputType) {
var hasTouch = false;
var hasMouse = false;
var inputs = inputType || [];
inputs.forEach(function (v) {
switch (v) {
case "mouse":
hasMouse = true;
break;
case "touch": hasTouch = const_1.SUPPORT_TOUCH;
}
});
return (hasTouch && Hammer.TouchInput) ||
(hasMouse && Hammer.MouseInput) || null;
};
// get user's direction
HammerInput.getDirectionByAngle = function (angle, thresholdAngle) {
if (thresholdAngle < 0 || thresholdAngle > 90) {
return DIRECTION.DIRECTION_NONE;
}
var toAngle = Math.abs(angle);
return toAngle > thresholdAngle && toAngle < 180 - thresholdAngle ?
DIRECTION.DIRECTION_VERTICAL : DIRECTION.DIRECTION_HORIZONTAL;
};
HammerInput.getNextOffset = function (speeds, deceleration) {
var normalSpeed = Math.sqrt(speeds[0] * speeds[0] + speeds[1] * speeds[1]);
var duration = Math.abs(normalSpeed / -deceleration);
return [
speeds[0] / 2 * duration,
speeds[1] / 2 * duration
];
};
HammerInput.useDirection = function (checkType, direction, userDirection) {
if (userDirection) {
return !!(direction & DIRECTION.DIRECTION_ALL ||
(direction & checkType && userDirection & checkType));
}
else {
return !!(direction & DIRECTION.DIRECTION_ALL ||
(direction & checkType));
}
};
HammerInput.prototype.mapAxes = function (axes) {
var useHorizontal = !!axes[0];
var useVertical = !!axes[1];
if (useHorizontal && useVertical) {
this._direction = DIRECTION.DIRECTION_ALL;
}
else if (useHorizontal) {
this._direction = DIRECTION.DIRECTION_HORIZONTAL;
}
else if (useVertical) {
this._direction = DIRECTION.DIRECTION_VERTICAL;
}
else {
this._direction = DIRECTION.DIRECTION_NONE;
}
this.axes = axes;
};
HammerInput.prototype.create = function (observer) {
var _this = this;
var inputClass = HammerInput.convertHammerInputType(this.options.inputType);
if (!inputClass) {
throw new Error("Wrong inputType parameter!");
}
var keyValue = this._element[const_1.UNIQUEKEY];
if (keyValue) {
this.hammer.destroy();
}
else {
keyValue = String(Math.round(Math.random() * new Date().getTime()));
}
this.hammer = this.createHammer(inputClass)
.on("hammer.input", function (event) {
if (event.isFirst) {
observer.hold(_this, event);
}
else if (event.isFinal) {
_this.onRelease(observer, event);
}
}).on("panstart panmove", function (event) {
_this.onChange(observer, event);
});
this._element[const_1.UNIQUEKEY] = keyValue;
return this;
};
HammerInput.prototype.destroy = function () {
if (this._element[const_1.UNIQUEKEY]) {
this.hammer.off("hammer.input panstart panmove panend");
this.hammer.destroy();
delete this._element[const_1.UNIQUEKEY];
}
this.hammer = null;
this._element = null;
this.options = {};
return this;
};
HammerInput.prototype.createHammer = function (inputClass) {
try {
// create Hammer
return new Hammer.Manager(this._element, {
recognizers: [
[
Hammer.Pan, {
direction: this._direction,
threshold: 0,
},
],
],
// css properties were removed due to usablility issue
// http://hammerjs.github.io/jsdoc/Hammer.defaults.cssProps.html
cssProps: {
userSelect: "none",
touchSelect: "none",
touchCallout: "none",
userDrag: "none",
},
inputClass: inputClass,
});
}
catch (e) {
return null;
}
};
HammerInput.prototype.getOffset = function (properties, useDirection) {
var offset = [0, 0];
var scale = this.options.scale;
if (useDirection[0]) {
offset[0] = (properties[0] * scale[0]);
}
if (useDirection[1]) {
offset[1] = (properties[1] * scale[1]);
}
return offset;
};
HammerInput.prototype.onChange = function (observer, event) {
var userDirection = HammerInput.getDirectionByAngle(event.angle, this.options.thresholdAngle);
// not support offset properties in Hammerjs - start
var prevInput = this.hammer.session.prevInput;
/* eslint-disable no-param-reassign */
if (prevInput) {
event.offsetX = event.deltaX - prevInput.deltaX;
event.offsetY = event.deltaY - prevInput.deltaY;
}
else {
event.offsetX = 0;
event.offsetY = 0;
}
var offset = this.getOffset([event.offsetX, event.offsetY], [
HammerInput.useDirection(DIRECTION.DIRECTION_HORIZONTAL, this._direction, userDirection),
HammerInput.useDirection(DIRECTION.DIRECTION_VERTICAL, this._direction, userDirection)
]);
var prevent = offset.some(function (v) { return v !== 0; });
if (prevent) {
event.srcEvent.preventDefault();
event.srcEvent.stopPropagation();
}
event.preventSystemEvent = prevent;
prevent && observer.change(this, event, this.toAxis(offset));
};
HammerInput.prototype.onRelease = function (observer, event) {
var offset = this.getOffset([
Math.abs(event.velocityX) * (event.deltaX < 0 ? -1 : 1),
Math.abs(event.velocityY) * (event.deltaY < 0 ? -1 : 1)
], [
HammerInput.useDirection(DIRECTION.DIRECTION_HORIZONTAL, this._direction),
HammerInput.useDirection(DIRECTION.DIRECTION_VERTICAL, this._direction)
]);
offset = HammerInput.getNextOffset(offset, observer.options.deceleration);
observer.release(this, event, this.toAxis(offset));
};
HammerInput.prototype.toAxis = function (offset) {
var _this = this;
return offset.reduce(function (acc, v, i) {
if (_this.axes[i]) {
acc[_this.axes[i]] = v;
}
return acc;
}, {});
};
HammerInput.prototype.enable = function () {
this.hammer && (this.hammer.get("pan").options.enable = true);
};
HammerInput.prototype.disable = function () {
this.hammer && (this.hammer.get("pan").options.enable = false);
};
HammerInput.prototype.isEnable = function () {
return this.hammer && this.hammer.get("pan").options.enable;
};
return HammerInput;
}(InputType_1.InputType));
exports.HammerInput = HammerInput;
/***/ }),
/* 11 */
/***/ (function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;/*! Hammer.JS - v2.0.7 - 2016-04-22
* http://hammerjs.github.io/
*
* Copyright (c) 2016 Jorik Tangelder;
* Licensed under the MIT license */
(function(window, document, exportName, undefined) {
'use strict';
var VENDOR_PREFIXES = ['', 'webkit', 'Moz', 'MS', 'ms', 'o'];
var TEST_ELEMENT = document.createElement('div');
var TYPE_FUNCTION = 'function';
var round = Math.round;
var abs = Math.abs;
var now = Date.now;
/**
* set a timeout with a given scope
* @param {Function} fn
* @param {Number} timeout
* @param {Object} context
* @returns {number}
*/
function setTimeoutContext(fn, timeout, context) {
return setTimeout(bindFn(fn, context), timeout);
}
/**
* if the argument is an array, we want to execute the fn on each entry
* if it aint an array we don't want to do a thing.
* this is used by all the methods that accept a single and array argument.
* @param {*|Array} arg
* @param {String} fn
* @param {Object} [context]
* @returns {Boolean}
*/
function invokeArrayArg(arg, fn, context) {
if (Array.isArray(arg)) {
each(arg, context[fn], context);
return true;
}
return false;
}
/**
* walk objects and arrays
* @param {Object} obj
* @param {Function} iterator
* @param {Object} context
*/
function each(obj, iterator, context) {
var i;
if (!obj) {
return;
}
if (obj.forEach) {
obj.forEach(iterator, context);
} else if (obj.length !== undefined) {
i = 0;
while (i < obj.length) {
iterator.call(context, obj[i], i, obj);
i++;
}
} else {
for (i in obj) {
obj.hasOwnProperty(i) && iterator.call(context, obj[i], i, obj);
}
}
}
/**
* wrap a method with a deprecation warning and stack trace
* @param {Function} method
* @param {String} name
* @param {String} message
* @returns {Function} A new function wrapping the supplied method.
*/
function deprecate(method, name, message) {
var deprecationMessage = 'DEPRECATED METHOD: ' + name + '\n' + message + ' AT \n';
return function() {
var e = new Error('get-stack-trace');
var stack = e && e.stack ? e.stack.replace(/^[^\(]+?[\n$]/gm, '')
.replace(/^\s+at\s+/gm, '')
.replace(/^Object.\s*\(/gm, '{anonymous}()@') : 'Unknown Stack Trace';
var log = window.console && (window.console.warn || window.console.log);
if (log) {
log.call(window.console, deprecationMessage, stack);
}
return method.apply(this, arguments);
};
}
/**
* extend object.
* means that properties in dest will be overwritten by the ones in src.
* @param {Object} target
* @param {...Object} objects_to_assign
* @returns {Object} target
*/
var assign;
if (typeof Object.assign !== 'function') {
assign = function assign(target) {
if (target === undefined || target === null) {
throw new TypeError('Cannot convert undefined or null to object');
}
var output = Object(target);
for (var index = 1; index < arguments.length; index++) {
var source = arguments[index];
if (source !== undefined && source !== null) {
for (var nextKey in source) {
if (source.hasOwnProperty(nextKey)) {
output[nextKey] = source[nextKey];
}
}
}
}
return output;
};
} else {
assign = Object.assign;
}
/**
* extend object.
* means that properties in dest will be overwritten by the ones in src.
* @param {Object} dest
* @param {Object} src
* @param {Boolean} [merge=false]
* @returns {Object} dest
*/
var extend = deprecate(function extend(dest, src, merge) {
var keys = Object.keys(src);
var i = 0;
while (i < keys.length) {
if (!merge || (merge && dest[keys[i]] === undefined)) {
dest[keys[i]] = src[keys[i]];
}
i++;
}
return dest;
}, 'extend', 'Use `assign`.');
/**
* merge the values from src in the dest.
* means that properties that exist in dest will not be overwritten by src
* @param {Object} dest
* @param {Object} src
* @returns {Object} dest
*/
var merge = deprecate(function merge(dest, src) {
return extend(dest, src, true);
}, 'merge', 'Use `assign`.');
/**
* simple class inheritance
* @param {Function} child
* @param {Function} base
* @param {Object} [properties]
*/
function inherit(child, base, properties) {
var baseP = base.prototype,
childP;
childP = child.prototype = Object.create(baseP);
childP.constructor = child;
childP._super = baseP;
if (properties) {
assign(childP, properties);
}
}
/**
* simple function bind
* @param {Function} fn
* @param {Object} context
* @returns {Function}
*/
function bindFn(fn, context) {
return function boundFn() {
return fn.apply(context, arguments);
};
}
/**
* let a boolean value also be a function that must return a boolean
* this first item in args will be used as the context
* @param {Boolean|Function} val
* @param {Array} [args]
* @returns {Boolean}
*/
function boolOrFn(val, args) {
if (typeof val == TYPE_FUNCTION) {
return val.apply(args ? args[0] || undefined : undefined, args);
}
return val;
}
/**
* use the val2 when val1 is undefined
* @param {*} val1
* @param {*} val2
* @returns {*}
*/
function ifUndefined(val1, val2) {
return (val1 === undefined) ? val2 : val1;
}
/**
* addEventListener with multiple events at once
* @param {EventTarget} target
* @param {String} types
* @param {Function} handler
*/
function addEventListeners(target, types, handler) {
each(splitStr(types), function(type) {
target.addEventListener(type, handler, false);
});
}
/**
* removeEventListener with multiple events at once
* @param {EventTarget} target
* @param {String} types
* @param {Function} handler
*/
function removeEventListeners(target, types, handler) {
each(splitStr(types), function(type) {
target.removeEventListener(type, handler, false);
});
}
/**
* find if a node is in the given parent
* @method hasParent
* @param {HTMLElement} node
* @param {HTMLElement} parent
* @return {Boolean} found
*/
function hasParent(node, parent) {
while (node) {
if (node == parent) {
return true;
}
node = node.parentNode;
}
return false;
}
/**
* small indexOf wrapper
* @param {String} str
* @param {String} find
* @returns {Boolean} found
*/
function inStr(str, find) {
return str.indexOf(find) > -1;
}
/**
* split string on whitespace
* @param {String} str
* @returns {Array} words
*/
function splitStr(str) {
return str.trim().split(/\s+/g);
}
/**
* find if a array contains the object using indexOf or a simple polyFill
* @param {Array} src
* @param {String} find
* @param {String} [findByKey]
* @return {Boolean|Number} false when not found, or the index
*/
function inArray(src, find, findByKey) {
if (src.indexOf && !findByKey) {
return src.indexOf(find);
} else {
var i = 0;
while (i < src.length) {
if ((findByKey && src[i][findByKey] == find) || (!findByKey && src[i] === find)) {
return i;
}
i++;
}
return -1;
}
}
/**
* convert array-like objects to real arrays
* @param {Object} obj
* @returns {Array}
*/
function toArray(obj) {
return Array.prototype.slice.call(obj, 0);
}
/**
* unique array with objects based on a key (like 'id') or just by the array's value
* @param {Array} src [{id:1},{id:2},{id:1}]
* @param {String} [key]
* @param {Boolean} [sort=False]
* @returns {Array} [{id:1},{id:2}]
*/
function uniqueArray(src, key, sort) {
var results = [];
var values = [];
var i = 0;
while (i < src.length) {
var val = key ? src[i][key] : src[i];
if (inArray(values, val) < 0) {
results.push(src[i]);
}
values[i] = val;
i++;
}
if (sort) {
if (!key) {
results = results.sort();
} else {
results = results.sort(function sortUniqueArray(a, b) {
return a[key] > b[key];
});
}
}
return results;
}
/**
* get the prefixed property
* @param {Object} obj
* @param {String} property
* @returns {String|Undefined} prefixed
*/
function prefixed(obj, property) {
var prefix, prop;
var camelProp = property[0].toUpperCase() + property.slice(1);
var i = 0;
while (i < VENDOR_PREFIXES.length) {
prefix = VENDOR_PREFIXES[i];
prop = (prefix) ? prefix + camelProp : property;
if (prop in obj) {
return prop;
}
i++;
}
return undefined;
}
/**
* get a unique id
* @returns {number} uniqueId
*/
var _uniqueId = 1;
function uniqueId() {
return _uniqueId++;
}
/**
* get the window object of an element
* @param {HTMLElement} element
* @returns {DocumentView|Window}
*/
function getWindowForElement(element) {
var doc = element.ownerDocument || element;
return (doc.defaultView || doc.parentWindow || window);
}
var MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i;
var SUPPORT_TOUCH = ('ontouchstart' in window);
var SUPPORT_POINTER_EVENTS = prefixed(window, 'PointerEvent') !== undefined;
var SUPPORT_ONLY_TOUCH = SUPPORT_TOUCH && MOBILE_REGEX.test(navigator.userAgent);
var INPUT_TYPE_TOUCH = 'touch';
var INPUT_TYPE_PEN = 'pen';
var INPUT_TYPE_MOUSE = 'mouse';
var INPUT_TYPE_KINECT = 'kinect';
var COMPUTE_INTERVAL = 25;
var INPUT_START = 1;
var INPUT_MOVE = 2;
var INPUT_END = 4;
var INPUT_CANCEL = 8;
var DIRECTION_NONE = 1;
var DIRECTION_LEFT = 2;
var DIRECTION_RIGHT = 4;
var DIRECTION_UP = 8;
var DIRECTION_DOWN = 16;
var DIRECTION_HORIZONTAL = DIRECTION_LEFT | DIRECTION_RIGHT;
var DIRECTION_VERTICAL = DIRECTION_UP | DIRECTION_DOWN;
var DIRECTION_ALL = DIRECTION_HORIZONTAL | DIRECTION_VERTICAL;
var PROPS_XY = ['x', 'y'];
var PROPS_CLIENT_XY = ['clientX', 'clientY'];
/**
* create new input type manager
* @param {Manager} manager
* @param {Function} callback
* @returns {Input}
* @constructor
*/
function Input(manager, callback) {
var self = this;
this.manager = manager;
this.callback = callback;
this.element = manager.element;
this.target = manager.options.inputTarget;
// smaller wrapper around the handler, for the scope and the enabled state of the manager,
// so when disabled the input events are completely bypassed.
this.domHandler = function(ev) {
if (boolOrFn(manager.options.enable, [manager])) {
self.handler(ev);
}
};
this.init();
}
Input.prototype = {
/**
* should handle the inputEvent data and trigger the callback
* @virtual
*/
handler: function() { },
/**
* bind the events
*/
init: function() {
this.evEl && addEventListeners(this.element, this.evEl, this.domHandler);
this.evTarget && addEventListeners(this.target, this.evTarget, this.domHandler);
this.evWin && addEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler);
},
/**
* unbind the events
*/
destroy: function() {
this.evEl && removeEventListeners(this.element, this.evEl, this.domHandler);
this.evTarget && removeEventListeners(this.target, this.evTarget, this.domHandler);
this.evWin && removeEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler);
}
};
/**
* create new input type manager
* called by the Manager constructor
* @param {Hammer} manager
* @returns {Input}
*/
function createInputInstance(manager) {
var Type;
var inputClass = manager.options.inputClass;
if (inputClass) {
Type = inputClass;
} else if (SUPPORT_POINTER_EVENTS) {
Type = PointerEventInput;
} else if (SUPPORT_ONLY_TOUCH) {
Type = TouchInput;
} else if (!SUPPORT_TOUCH) {
Type = MouseInput;
} else {
Type = TouchMouseInput;
}
return new (Type)(manager, inputHandler);
}
/**
* handle input events
* @param {Manager} manager
* @param {String} eventType
* @param {Object} input
*/
function inputHandler(manager, eventType, input) {
var pointersLen = input.pointers.length;
var changedPointersLen = input.changedPointers.length;
var isFirst = (eventType & INPUT_START && (pointersLen - changedPointersLen === 0));
var isFinal = (eventType & (INPUT_END | INPUT_CANCEL) && (pointersLen - changedPointersLen === 0));
input.isFirst = !!isFirst;
input.isFinal = !!isFinal;
if (isFirst) {
manager.session = {};
}
// source event is the normalized value of the domEvents
// like 'touchstart, mouseup, pointerdown'
input.eventType = eventType;
// compute scale, rotation etc
computeInputData(manager, input);
// emit secret event
manager.emit('hammer.input', input);
manager.recognize(input);
manager.session.prevInput = input;
}
/**
* extend the data with some usable properties like scale, rotate, velocity etc
* @param {Object} manager
* @param {Object} input
*/
function computeInputData(manager, input) {
var session = manager.session;
var pointers = input.pointers;
var pointersLength = pointers.length;
// store the first input to calculate the distance and direction
if (!session.firstInput) {
session.firstInput = simpleCloneInputData(input);
}
// to compute scale and rotation we need to store the multiple touches
if (pointersLength > 1 && !session.firstMultiple) {
session.firstMultiple = simpleCloneInputData(input);
} else if (pointersLength === 1) {
session.firstMultiple = false;
}
var firstInput = session.firstInput;
var firstMultiple = session.firstMultiple;
var offsetCenter = firstMultiple ? firstMultiple.center : firstInput.center;
var center = input.center = getCenter(pointers);
input.timeStamp = now();
input.deltaTime = input.timeStamp - firstInput.timeStamp;
input.angle = getAngle(offsetCenter, center);
input.distance = getDistance(offsetCenter, center);
computeDeltaXY(session, input);
input.offsetDirection = getDirection(input.deltaX, input.deltaY);
var overallVelocity = getVelocity(input.deltaTime, input.deltaX, input.deltaY);
input.overallVelocityX = overallVelocity.x;
input.overallVelocityY = overallVelocity.y;
input.overallVelocity = (abs(overallVelocity.x) > abs(overallVelocity.y)) ? overallVelocity.x : overallVelocity.y;
input.scale = firstMultiple ? getScale(firstMultiple.pointers, pointers) : 1;
input.rotation = firstMultiple ? getRotation(firstMultiple.pointers, pointers) : 0;
input.maxPointers = !session.prevInput ? input.pointers.length : ((input.pointers.length >
session.prevInput.maxPointers) ? input.pointers.length : session.prevInput.maxPointers);
computeIntervalInputData(session, input);
// find the correct target
var target = manager.element;
if (hasParent(input.srcEvent.target, target)) {
target = input.srcEvent.target;
}
input.target = target;
}
function computeDeltaXY(session, input) {
var center = input.center;
var offset = session.offsetDelta || {};
var prevDelta = session.prevDelta || {};
var prevInput = session.prevInput || {};
if (input.eventType === INPUT_START || prevInput.eventType === INPUT_END) {
prevDelta = session.prevDelta = {
x: prevInput.deltaX || 0,
y: prevInput.deltaY || 0
};
offset = session.offsetDelta = {
x: center.x,
y: center.y
};
}
input.deltaX = prevDelta.x + (center.x - offset.x);
input.deltaY = prevDelta.y + (center.y - offset.y);
}
/**
* velocity is calculated every x ms
* @param {Object} session
* @param {Object} input
*/
function computeIntervalInputData(session, input) {
var last = session.lastInterval || input,
deltaTime = input.timeStamp - last.timeStamp,
velocity, velocityX, velocityY, direction;
if (input.eventType != INPUT_CANCEL && (deltaTime > COMPUTE_INTERVAL || last.velocity === undefined)) {
var deltaX = input.deltaX - last.deltaX;
var deltaY = input.deltaY - last.deltaY;
var v = getVelocity(deltaTime, deltaX, deltaY);
velocityX = v.x;
velocityY = v.y;
velocity = (abs(v.x) > abs(v.y)) ? v.x : v.y;
direction = getDirection(deltaX, deltaY);
session.lastInterval = input;
} else {
// use latest velocity info if it doesn't overtake a minimum period
velocity = last.velocity;
velocityX = last.velocityX;
velocityY = last.velocityY;
direction = last.direction;
}
input.velocity = velocity;
input.velocityX = velocityX;
input.velocityY = velocityY;
input.direction = direction;
}
/**
* create a simple clone from the input used for storage of firstInput and firstMultiple
* @param {Object} input
* @returns {Object} clonedInputData
*/
function simpleCloneInputData(input) {
// make a simple copy of the pointers because we will get a reference if we don't
// we only need clientXY for the calculations
var pointers = [];
var i = 0;
while (i < input.pointers.length) {
pointers[i] = {
clientX: round(input.pointers[i].clientX),
clientY: round(input.pointers[i].clientY)
};
i++;
}
return {
timeStamp: now(),
pointers: pointers,
center: getCenter(pointers),
deltaX: input.deltaX,
deltaY: input.deltaY
};
}
/**
* get the center of all the pointers
* @param {Array} pointers
* @return {Object} center contains `x` and `y` properties
*/
function getCenter(pointers) {
var pointersLength = pointers.length;
// no need to loop when only one touch
if (pointersLength === 1) {
return {
x: round(pointers[0].clientX),
y: round(pointers[0].clientY)
};
}
var x = 0, y = 0, i = 0;
while (i < pointersLength) {
x += pointers[i].clientX;
y += pointers[i].clientY;
i++;
}
return {
x: round(x / pointersLength),
y: round(y / pointersLength)
};
}
/**
* calculate the velocity between two points. unit is in px per ms.
* @param {Number} deltaTime
* @param {Number} x
* @param {Number} y
* @return {Object} velocity `x` and `y`
*/
function getVelocity(deltaTime, x, y) {
return {
x: x / deltaTime || 0,
y: y / deltaTime || 0
};
}
/**
* get the direction between two points
* @param {Number} x
* @param {Number} y
* @return {Number} direction
*/
function getDirection(x, y) {
if (x === y) {
return DIRECTION_NONE;
}
if (abs(x) >= abs(y)) {
return x < 0 ? DIRECTION_LEFT : DIRECTION_RIGHT;
}
return y < 0 ? DIRECTION_UP : DIRECTION_DOWN;
}
/**
* calculate the absolute distance between two points
* @param {Object} p1 {x, y}
* @param {Object} p2 {x, y}
* @param {Array} [props] containing x and y keys
* @return {Number} distance
*/
function getDistance(p1, p2, props) {
if (!props) {
props = PROPS_XY;
}
var x = p2[props[0]] - p1[props[0]],
y = p2[props[1]] - p1[props[1]];
return Math.sqrt((x * x) + (y * y));
}
/**
* calculate the angle between two coordinates
* @param {Object} p1
* @param {Object} p2
* @param {Array} [props] containing x and y keys
* @return {Number} angle
*/
function getAngle(p1, p2, props) {
if (!props) {
props = PROPS_XY;
}
var x = p2[props[0]] - p1[props[0]],
y = p2[props[1]] - p1[props[1]];
return Math.atan2(y, x) * 180 / Math.PI;
}
/**
* calculate the rotation degrees between two pointersets
* @param {Array} start array of pointers
* @param {Array} end array of pointers
* @return {Number} rotation
*/
function getRotation(start, end) {
return getAngle(end[1], end[0], PROPS_CLIENT_XY) + getAngle(start[1], start[0], PROPS_CLIENT_XY);
}
/**
* calculate the scale factor between two pointersets
* no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out
* @param {Array} start array of pointers
* @param {Array} end array of pointers
* @return {Number} scale
*/
function getScale(start, end) {
return getDistance(end[0], end[1], PROPS_CLIENT_XY) / getDistance(start[0], start[1], PROPS_CLIENT_XY);
}
var MOUSE_INPUT_MAP = {
mousedown: INPUT_START,
mousemove: INPUT_MOVE,
mouseup: INPUT_END
};
var MOUSE_ELEMENT_EVENTS = 'mousedown';
var MOUSE_WINDOW_EVENTS = 'mousemove mouseup';
/**
* Mouse events input
* @constructor
* @extends Input
*/
function MouseInput() {
this.evEl = MOUSE_ELEMENT_EVENTS;
this.evWin = MOUSE_WINDOW_EVENTS;
this.pressed = false; // mousedown state
Input.apply(this, arguments);
}
inherit(MouseInput, Input, {
/**
* handle mouse events
* @param {Object} ev
*/
handler: function MEhandler(ev) {
var eventType = MOUSE_INPUT_MAP[ev.type];
// on start we want to have the left mouse button down
if (eventType & INPUT_START && ev.button === 0) {
this.pressed = true;
}
if (eventType & INPUT_MOVE && ev.which !== 1) {
eventType = INPUT_END;
}
// mouse must be down
if (!this.pressed) {
return;
}
if (eventType & INPUT_END) {
this.pressed = false;
}
this.callback(this.manager, eventType, {
pointers: [ev],
changedPointers: [ev],
pointerType: INPUT_TYPE_MOUSE,
srcEvent: ev
});
}
});
var POINTER_INPUT_MAP = {
pointerdown: INPUT_START,
pointermove: INPUT_MOVE,
pointerup: INPUT_END,
pointercancel: INPUT_CANCEL,
pointerout: INPUT_CANCEL
};
// in IE10 the pointer types is defined as an enum
var IE10_POINTER_TYPE_ENUM = {
2: INPUT_TYPE_TOUCH,
3: INPUT_TYPE_PEN,
4: INPUT_TYPE_MOUSE,
5: INPUT_TYPE_KINECT // see https://twitter.com/jacobrossi/status/480596438489890816
};
var POINTER_ELEMENT_EVENTS = 'pointerdown';
var POINTER_WINDOW_EVENTS = 'pointermove pointerup pointercancel';
// IE10 has prefixed support, and case-sensitive
if (window.MSPointerEvent && !window.PointerEvent) {
POINTER_ELEMENT_EVENTS = 'MSPointerDown';
POINTER_WINDOW_EVENTS = 'MSPointerMove MSPointerUp MSPointerCancel';
}
/**
* Pointer events input
* @constructor
* @extends Input
*/
function PointerEventInput() {
this.evEl = POINTER_ELEMENT_EVENTS;
this.evWin = POINTER_WINDOW_EVENTS;
Input.apply(this, arguments);
this.store = (this.manager.session.pointerEvents = []);
}
inherit(PointerEventInput, Input, {
/**
* handle mouse events
* @param {Object} ev
*/
handler: function PEhandler(ev) {
var store = this.store;
var removePointer = false;
var eventTypeNormalized = ev.type.toLowerCase().replace('ms', '');
var eventType = POINTER_INPUT_MAP[eventTypeNormalized];
var pointerType = IE10_POINTER_TYPE_ENUM[ev.pointerType] || ev.pointerType;
var isTouch = (pointerType == INPUT_TYPE_TOUCH);
// get index of the event in the store
var storeIndex = inArray(store, ev.pointerId, 'pointerId');
// start and mouse must be down
if (eventType & INPUT_START && (ev.button === 0 || isTouch)) {
if (storeIndex < 0) {
store.push(ev);
storeIndex = store.length - 1;
}
} else if (eventType & (INPUT_END | INPUT_CANCEL)) {
removePointer = true;
}
// it not found, so the pointer hasn't been down (so it's probably a hover)
if (storeIndex < 0) {
return;
}
// update the event in the store
store[storeIndex] = ev;
this.callback(this.manager, eventType, {
pointers: store,
changedPointers: [ev],
pointerType: pointerType,
srcEvent: ev
});
if (removePointer) {
// remove from the store
store.splice(storeIndex, 1);
}
}
});
var SINGLE_TOUCH_INPUT_MAP = {
touchstart: INPUT_START,
touchmove: INPUT_MOVE,
touchend: INPUT_END,
touchcancel: INPUT_CANCEL
};
var SINGLE_TOUCH_TARGET_EVENTS = 'touchstart';
var SINGLE_TOUCH_WINDOW_EVENTS = 'touchstart touchmove touchend touchcancel';
/**
* Touch events input
* @constructor
* @extends Input
*/
function SingleTouchInput() {
this.evTarget = SINGLE_TOUCH_TARGET_EVENTS;
this.evWin = SINGLE_TOUCH_WINDOW_EVENTS;
this.started = false;
Input.apply(this, arguments);
}
inherit(SingleTouchInput, Input, {
handler: function TEhandler(ev) {
var type = SINGLE_TOUCH_INPUT_MAP[ev.type];
// should we handle the touch events?
if (type === INPUT_START) {
this.started = true;
}
if (!this.started) {
return;
}
var touches = normalizeSingleTouches.call(this, ev, type);
// when done, reset the started state
if (type & (INPUT_END | INPUT_CANCEL) && touches[0].length - touches[1].length === 0) {
this.started = false;
}
this.callback(this.manager, type, {
pointers: touches[0],
changedPointers: touches[1],
pointerType: INPUT_TYPE_TOUCH,
srcEvent: ev
});
}
});
/**
* @this {TouchInput}
* @param {Object} ev
* @param {Number} type flag
* @returns {undefined|Array} [all, changed]
*/
function normalizeSingleTouches(ev, type) {
var all = toArray(ev.touches);
var changed = toArray(ev.changedTouches);
if (type & (INPUT_END | INPUT_CANCEL)) {
all = uniqueArray(all.concat(changed), 'identifier', true);
}
return [all, changed];
}
var TOUCH_INPUT_MAP = {
touchstart: INPUT_START,
touchmove: INPUT_MOVE,
touchend: INPUT_END,
touchcancel: INPUT_CANCEL
};
var TOUCH_TARGET_EVENTS = 'touchstart touchmove touchend touchcancel';
/**
* Multi-user touch events input
* @constructor
* @extends Input
*/
function TouchInput() {
this.evTarget = TOUCH_TARGET_EVENTS;
this.targetIds = {};
Input.apply(this, arguments);
}
inherit(TouchInput, Input, {
handler: function MTEhandler(ev) {
var type = TOUCH_INPUT_MAP[ev.type];
var touches = getTouches.call(this, ev, type);
if (!touches) {
return;
}
this.callback(this.manager, type, {
pointers: touches[0],
changedPointers: touches[1],
pointerType: INPUT_TYPE_TOUCH,
srcEvent: ev
});
}
});
/**
* @this {TouchInput}
* @param {Object} ev
* @param {Number} type flag
* @returns {undefined|Array} [all, changed]
*/
function getTouches(ev, type) {
var allTouches = toArray(ev.touches);
var targetIds = this.targetIds;
// when there is only one touch, the process can be simplified
if (type & (INPUT_START | INPUT_MOVE) && allTouches.length === 1) {
targetIds[allTouches[0].identifier] = true;
return [allTouches, allTouches];
}
var i,
targetTouches,
changedTouches = toArray(ev.changedTouches),
changedTargetTouches = [],
target = this.target;
// get target touches from touches
targetTouches = allTouches.filter(function(touch) {
return hasParent(touch.target, target);
});
// collect touches
if (type === INPUT_START) {
i = 0;
while (i < targetTouches.length) {
targetIds[targetTouches[i].identifier] = true;
i++;
}
}
// filter changed touches to only contain touches that exist in the collected target ids
i = 0;
while (i < changedTouches.length) {
if (targetIds[changedTouches[i].identifier]) {
changedTargetTouches.push(changedTouches[i]);
}
// cleanup removed touches
if (type & (INPUT_END | INPUT_CANCEL)) {
delete targetIds[changedTouches[i].identifier];
}
i++;
}
if (!changedTargetTouches.length) {
return;
}
return [
// merge targetTouches with changedTargetTouches so it contains ALL touches, including 'end' and 'cancel'
uniqueArray(targetTouches.concat(changedTargetTouches), 'identifier', true),
changedTargetTouches
];
}
/**
* Combined touch and mouse input
*
* Touch has a higher priority then mouse, and while touching no mouse events are allowed.
* This because touch devices also emit mouse events while doing a touch.
*
* @constructor
* @extends Input
*/
var DEDUP_TIMEOUT = 2500;
var DEDUP_DISTANCE = 25;
function TouchMouseInput() {
Input.apply(this, arguments);
var handler = bindFn(this.handler, this);
this.touch = new TouchInput(this.manager, handler);
this.mouse = new MouseInput(this.manager, handler);
this.primaryTouch = null;
this.lastTouches = [];
}
inherit(TouchMouseInput, Input, {
/**
* handle mouse and touch events
* @param {Hammer} manager
* @param {String} inputEvent
* @param {Object} inputData
*/
handler: function TMEhandler(manager, inputEvent, inputData) {
var isTouch = (inputData.pointerType == INPUT_TYPE_TOUCH),
isMouse = (inputData.pointerType == INPUT_TYPE_MOUSE);
if (isMouse && inputData.sourceCapabilities && inputData.sourceCapabilities.firesTouchEvents) {
return;
}
// when we're in a touch event, record touches to de-dupe synthetic mouse event
if (isTouch) {
recordTouches.call(this, inputEvent, inputData);
} else if (isMouse && isSyntheticEvent.call(this, inputData)) {
return;
}
this.callback(manager, inputEvent, inputData);
},
/**
* remove the event listeners
*/
destroy: function destroy() {
this.touch.destroy();
this.mouse.destroy();
}
});
function recordTouches(eventType, eventData) {
if (eventType & INPUT_START) {
this.primaryTouch = eventData.changedPointers[0].identifier;
setLastTouch.call(this, eventData);
} else if (eventType & (INPUT_END | INPUT_CANCEL)) {
setLastTouch.call(this, eventData);
}
}
function setLastTouch(eventData) {
var touch = eventData.changedPointers[0];
if (touch.identifier === this.primaryTouch) {
var lastTouch = {x: touch.clientX, y: touch.clientY};
this.lastTouches.push(lastTouch);
var lts = this.lastTouches;
var removeLastTouch = function() {
var i = lts.indexOf(lastTouch);
if (i > -1) {
lts.splice(i, 1);
}
};
setTimeout(removeLastTouch, DEDUP_TIMEOUT);
}
}
function isSyntheticEvent(eventData) {
var x = eventData.srcEvent.clientX, y = eventData.srcEvent.clientY;
for (var i = 0; i < this.lastTouches.length; i++) {
var t = this.lastTouches[i];
var dx = Math.abs(x - t.x), dy = Math.abs(y - t.y);
if (dx <= DEDUP_DISTANCE && dy <= DEDUP_DISTANCE) {
return true;
}
}
return false;
}
var PREFIXED_TOUCH_ACTION = prefixed(TEST_ELEMENT.style, 'touchAction');
var NATIVE_TOUCH_ACTION = PREFIXED_TOUCH_ACTION !== undefined;
// magical touchAction value
var TOUCH_ACTION_COMPUTE = 'compute';
var TOUCH_ACTION_AUTO = 'auto';
var TOUCH_ACTION_MANIPULATION = 'manipulation'; // not implemented
var TOUCH_ACTION_NONE = 'none';
var TOUCH_ACTION_PAN_X = 'pan-x';
var TOUCH_ACTION_PAN_Y = 'pan-y';
var TOUCH_ACTION_MAP = getTouchActionProps();
/**
* Touch Action
* sets the touchAction property or uses the js alternative
* @param {Manager} manager
* @param {String} value
* @constructor
*/
function TouchAction(manager, value) {
this.manager = manager;
this.set(value);
}
TouchAction.prototype = {
/**
* set the touchAction value on the element or enable the polyfill
* @param {String} value
*/
set: function(value) {
// find out the touch-action by the event handlers
if (value == TOUCH_ACTION_COMPUTE) {
value = this.compute();
}
if (NATIVE_TOUCH_ACTION && this.manager.element.style && TOUCH_ACTION_MAP[value]) {
this.manager.element.style[PREFIXED_TOUCH_ACTION] = value;
}
this.actions = value.toLowerCase().trim();
},
/**
* just re-set the touchAction value
*/
update: function() {
this.set(this.manager.options.touchAction);
},
/**
* compute the value for the touchAction property based on the recognizer's settings
* @returns {String} value
*/
compute: function() {
var actions = [];
each(this.manager.recognizers, function(recognizer) {
if (boolOrFn(recognizer.options.enable, [recognizer])) {
actions = actions.concat(recognizer.getTouchAction());
}
});
return cleanTouchActions(actions.join(' '));
},
/**
* this method is called on each input cycle and provides the preventing of the browser behavior
* @param {Object} input
*/
preventDefaults: function(input) {
var srcEvent = input.srcEvent;
var direction = input.offsetDirection;
// if the touch action did prevented once this session
if (this.manager.session.prevented) {
srcEvent.preventDefault();
return;
}
var actions = this.actions;
var hasNone = inStr(actions, TOUCH_ACTION_NONE) && !TOUCH_ACTION_MAP[TOUCH_ACTION_NONE];
var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y) && !TOUCH_ACTION_MAP[TOUCH_ACTION_PAN_Y];
var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X) && !TOUCH_ACTION_MAP[TOUCH_ACTION_PAN_X];
if (hasNone) {
//do not prevent defaults if this is a tap gesture
var isTapPointer = input.pointers.length === 1;
var isTapMovement = input.distance < 2;
var isTapTouchTime = input.deltaTime < 250;
if (isTapPointer && isTapMovement && isTapTouchTime) {
return;
}
}
if (hasPanX && hasPanY) {
// `pan-x pan-y` means browser handles all scrolling/panning, do not prevent
return;
}
if (hasNone ||
(hasPanY && direction & DIRECTION_HORIZONTAL) ||
(hasPanX && direction & DIRECTION_VERTICAL)) {
return this.preventSrc(srcEvent);
}
},
/**
* call preventDefault to prevent the browser's default behavior (scrolling in most cases)
* @param {Object} srcEvent
*/
preventSrc: function(srcEvent) {
this.manager.session.prevented = true;
srcEvent.preventDefault();
}
};
/**
* when the touchActions are collected they are not a valid value, so we need to clean things up. *
* @param {String} actions
* @returns {*}
*/
function cleanTouchActions(actions) {
// none
if (inStr(actions, TOUCH_ACTION_NONE)) {
return TOUCH_ACTION_NONE;
}
var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X);
var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y);
// if both pan-x and pan-y are set (different recognizers
// for different directions, e.g. horizontal pan but vertical swipe?)
// we need none (as otherwise with pan-x pan-y combined none of these
// recognizers will work, since the browser would handle all panning
if (hasPanX && hasPanY) {
return TOUCH_ACTION_NONE;
}
// pan-x OR pan-y
if (hasPanX || hasPanY) {
return hasPanX ? TOUCH_ACTION_PAN_X : TOUCH_ACTION_PAN_Y;
}
// manipulation
if (inStr(actions, TOUCH_ACTION_MANIPULATION)) {
return TOUCH_ACTION_MANIPULATION;
}
return TOUCH_ACTION_AUTO;
}
function getTouchActionProps() {
if (!NATIVE_TOUCH_ACTION) {
return false;
}
var touchMap = {};
var cssSupports = window.CSS && window.CSS.supports;
['auto', 'manipulation', 'pan-y', 'pan-x', 'pan-x pan-y', 'none'].forEach(function(val) {
// If css.supports is not supported but there is native touch-action assume it supports
// all values. This is the case for IE 10 and 11.
touchMap[val] = cssSupports ? window.CSS.supports('touch-action', val) : true;
});
return touchMap;
}
/**
* Recognizer flow explained; *
* All recognizers have the initial state of POSSIBLE when a input session starts.
* The definition of a input session is from the first input until the last input, with all it's movement in it. *
* Example session for mouse-input: mousedown -> mousemove -> mouseup
*
* On each recognizing cycle (see Manager.recognize) the .recognize() method is executed
* which determines with state it should be.
*
* If the recognizer has the state FAILED, CANCELLED or RECOGNIZED (equals ENDED), it is reset to
* POSSIBLE to give it another change on the next cycle.
*
* Possible
* |
* +-----+---------------+
* | |
* +-----+-----+ |
* | | |
* Failed Cancelled |
* +-------+------+
* | |
* Recognized Began
* |
* Changed
* |
* Ended/Recognized
*/
var STATE_POSSIBLE = 1;
var STATE_BEGAN = 2;
var STATE_CHANGED = 4;
var STATE_ENDED = 8;
var STATE_RECOGNIZED = STATE_ENDED;
var STATE_CANCELLED = 16;
var STATE_FAILED = 32;
/**
* Recognizer
* Every recognizer needs to extend from this class.
* @constructor
* @param {Object} options
*/
function Recognizer(options) {
this.options = assign({}, this.defaults, options || {});
this.id = uniqueId();
this.manager = null;
// default is enable true
this.options.enable = ifUndefined(this.options.enable, true);
this.state = STATE_POSSIBLE;
this.simultaneous = {};
this.requireFail = [];
}
Recognizer.prototype = {
/**
* @virtual
* @type {Object}
*/
defaults: {},
/**
* set options
* @param {Object} options
* @return {Recognizer}
*/
set: function(options) {
assign(this.options, options);
// also update the touchAction, in case something changed about the directions/enabled state
this.manager && this.manager.touchAction.update();
return this;
},
/**
* recognize simultaneous with an other recognizer.
* @param {Recognizer} otherRecognizer
* @returns {Recognizer} this
*/
recognizeWith: function(otherRecognizer) {
if (invokeArrayArg(otherRecognizer, 'recognizeWith', this)) {
return this;
}
var simultaneous = this.simultaneous;
otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
if (!simultaneous[otherRecognizer.id]) {
simultaneous[otherRecognizer.id] = otherRecognizer;
otherRecognizer.recognizeWith(this);
}
return this;
},
/**
* drop the simultaneous link. it doesnt remove the link on the other recognizer.
* @param {Recognizer} otherRecognizer
* @returns {Recognizer} this
*/
dropRecognizeWith: function(otherRecognizer) {
if (invokeArrayArg(otherRecognizer, 'dropRecognizeWith', this)) {
return this;
}
otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
delete this.simultaneous[otherRecognizer.id];
return this;
},
/**
* recognizer can only run when an other is failing
* @param {Recognizer} otherRecognizer
* @returns {Recognizer} this
*/
requireFailure: function(otherRecognizer) {
if (invokeArrayArg(otherRecognizer, 'requireFailure', this)) {
return this;
}
var requireFail = this.requireFail;
otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
if (inArray(requireFail, otherRecognizer) === -1) {
requireFail.push(otherRecognizer);
otherRecognizer.requireFailure(this);
}
return this;
},
/**
* drop the requireFailure link. it does not remove the link on the other recognizer.
* @param {Recognizer} otherRecognizer
* @returns {Recognizer} this
*/
dropRequireFailure: function(otherRecognizer) {
if (invokeArrayArg(otherRecognizer, 'dropRequireFailure', this)) {
return this;
}
otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
var index = inArray(this.requireFail, otherRecognizer);
if (index > -1) {
this.requireFail.splice(index, 1);
}
return this;
},
/**
* has require failures boolean
* @returns {boolean}
*/
hasRequireFailures: function() {
return this.requireFail.length > 0;
},
/**
* if the recognizer can recognize simultaneous with an other recognizer
* @param {Recognizer} otherRecognizer
* @returns {Boolean}
*/
canRecognizeWith: function(otherRecognizer) {
return !!this.simultaneous[otherRecognizer.id];
},
/**
* You should use `tryEmit` instead of `emit` directly to check
* that all the needed recognizers has failed before emitting.
* @param {Object} input
*/
emit: function(input) {
var self = this;
var state = this.state;
function emit(event) {
self.manager.emit(event, input);
}
// 'panstart' and 'panmove'
if (state < STATE_ENDED) {
emit(self.options.event + stateStr(state));
}
emit(self.options.event); // simple 'eventName' events
if (input.additionalEvent) { // additional event(panleft, panright, pinchin, pinchout...)
emit(input.additionalEvent);
}
// panend and pancancel
if (state >= STATE_ENDED) {
emit(self.options.event + stateStr(state));
}
},
/**
* Check that all the require failure recognizers has failed,
* if true, it emits a gesture event,
* otherwise, setup the state to FAILED.
* @param {Object} input
*/
tryEmit: function(input) {
if (this.canEmit()) {
return this.emit(input);
}
// it's failing anyway
this.state = STATE_FAILED;
},
/**
* can we emit?
* @returns {boolean}
*/
canEmit: function() {
var i = 0;
while (i < this.requireFail.length) {
if (!(this.requireFail[i].state & (STATE_FAILED | STATE_POSSIBLE))) {
return false;
}
i++;
}
return true;
},
/**
* update the recognizer
* @param {Object} inputData
*/
recognize: function(inputData) {
// make a new copy of the inputData
// so we can change the inputData without messing up the other recognizers
var inputDataClone = assign({}, inputData);
// is is enabled and allow recognizing?
if (!boolOrFn(this.options.enable, [this, inputDataClone])) {
this.reset();
this.state = STATE_FAILED;
return;
}
// reset when we've reached the end
if (this.state & (STATE_RECOGNIZED | STATE_CANCELLED | STATE_FAILED)) {
this.state = STATE_POSSIBLE;
}
this.state = this.process(inputDataClone);
// the recognizer has recognized a gesture
// so trigger an event
if (this.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED | STATE_CANCELLED)) {
this.tryEmit(inputDataClone);
}
},
/**
* return the state of the recognizer
* the actual recognizing happens in this method
* @virtual
* @param {Object} inputData
* @returns {Const} STATE
*/
process: function(inputData) { }, // jshint ignore:line
/**
* return the preferred touch-action
* @virtual
* @returns {Array}
*/
getTouchAction: function() { },
/**
* called when the gesture isn't allowed to recognize
* like when another is being recognized or it is disabled
* @virtual
*/
reset: function() { }
};
/**
* get a usable string, used as event postfix
* @param {Const} state
* @returns {String} state
*/
function stateStr(state) {
if (state & STATE_CANCELLED) {
return 'cancel';
} else if (state & STATE_ENDED) {
return 'end';
} else if (state & STATE_CHANGED) {
return 'move';
} else if (state & STATE_BEGAN) {
return 'start';
}
return '';
}
/**
* direction cons to string
* @param {Const} direction
* @returns {String}
*/
function directionStr(direction) {
if (direction == DIRECTION_DOWN) {
return 'down';
} else if (direction == DIRECTION_UP) {
return 'up';
} else if (direction == DIRECTION_LEFT) {
return 'left';
} else if (direction == DIRECTION_RIGHT) {
return 'right';
}
return '';
}
/**
* get a recognizer by name if it is bound to a manager
* @param {Recognizer|String} otherRecognizer
* @param {Recognizer} recognizer
* @returns {Recognizer}
*/
function getRecognizerByNameIfManager(otherRecognizer, recognizer) {
var manager = recognizer.manager;
if (manager) {
return manager.get(otherRecognizer);
}
return otherRecognizer;
}
/**
* This recognizer is just used as a base for the simple attribute recognizers.
* @constructor
* @extends Recognizer
*/
function AttrRecognizer() {
Recognizer.apply(this, arguments);
}
inherit(AttrRecognizer, Recognizer, {
/**
* @namespace
* @memberof AttrRecognizer
*/
defaults: {
/**
* @type {Number}
* @default 1
*/
pointers: 1
},
/**
* Used to check if it the recognizer receives valid input, like input.distance > 10.
* @memberof AttrRecognizer
* @param {Object} input
* @returns {Boolean} recognized
*/
attrTest: function(input) {
var optionPointers = this.options.pointers;
return optionPointers === 0 || input.pointers.length === optionPointers;
},
/**
* Process the input and return the state for the recognizer
* @memberof AttrRecognizer
* @param {Object} input
* @returns {*} State
*/
process: function(input) {
var state = this.state;
var eventType = input.eventType;
var isRecognized = state & (STATE_BEGAN | STATE_CHANGED);
var isValid = this.attrTest(input);
// on cancel input and we've recognized before, return STATE_CANCELLED
if (isRecognized && (eventType & INPUT_CANCEL || !isValid)) {
return state | STATE_CANCELLED;
} else if (isRecognized || isValid) {
if (eventType & INPUT_END) {
return state | STATE_ENDED;
} else if (!(state & STATE_BEGAN)) {
return STATE_BEGAN;
}
return state | STATE_CHANGED;
}
return STATE_FAILED;
}
});
/**
* Pan
* Recognized when the pointer is down and moved in the allowed direction.
* @constructor
* @extends AttrRecognizer
*/
function PanRecognizer() {
AttrRecognizer.apply(this, arguments);
this.pX = null;
this.pY = null;
}
inherit(PanRecognizer, AttrRecognizer, {
/**
* @namespace
* @memberof PanRecognizer
*/
defaults: {
event: 'pan',
threshold: 10,
pointers: 1,
direction: DIRECTION_ALL
},
getTouchAction: function() {
var direction = this.options.direction;
var actions = [];
if (direction & DIRECTION_HORIZONTAL) {
actions.push(TOUCH_ACTION_PAN_Y);
}
if (direction & DIRECTION_VERTICAL) {
actions.push(TOUCH_ACTION_PAN_X);
}
return actions;
},
directionTest: function(input) {
var options = this.options;
var hasMoved = true;
var distance = input.distance;
var direction = input.direction;
var x = input.deltaX;
var y = input.deltaY;
// lock to axis?
if (!(direction & options.direction)) {
if (options.direction & DIRECTION_HORIZONTAL) {
direction = (x === 0) ? DIRECTION_NONE : (x < 0) ? DIRECTION_LEFT : DIRECTION_RIGHT;
hasMoved = x != this.pX;
distance = Math.abs(input.deltaX);
} else {
direction = (y === 0) ? DIRECTION_NONE : (y < 0) ? DIRECTION_UP : DIRECTION_DOWN;
hasMoved = y != this.pY;
distance = Math.abs(input.deltaY);
}
}
input.direction = direction;
return hasMoved && distance > options.threshold && direction & options.direction;
},
attrTest: function(input) {
return AttrRecognizer.prototype.attrTest.call(this, input) &&
(this.state & STATE_BEGAN || (!(this.state & STATE_BEGAN) && this.directionTest(input)));
},
emit: function(input) {
this.pX = input.deltaX;
this.pY = input.deltaY;
var direction = directionStr(input.direction);
if (direction) {
input.additionalEvent = this.options.event + direction;
}
this._super.emit.call(this, input);
}
});
/**
* Pinch
* Recognized when two or more pointers are moving toward (zoom-in) or away from each other (zoom-out).
* @constructor
* @extends AttrRecognizer
*/
function PinchRecognizer() {
AttrRecognizer.apply(this, arguments);
}
inherit(PinchRecognizer, AttrRecognizer, {
/**
* @namespace
* @memberof PinchRecognizer
*/
defaults: {
event: 'pinch',
threshold: 0,
pointers: 2
},
getTouchAction: function() {
return [TOUCH_ACTION_NONE];
},
attrTest: function(input) {
return this._super.attrTest.call(this, input) &&
(Math.abs(input.scale - 1) > this.options.threshold || this.state & STATE_BEGAN);
},
emit: function(input) {
if (input.scale !== 1) {
var inOut = input.scale < 1 ? 'in' : 'out';
input.additionalEvent = this.options.event + inOut;
}
this._super.emit.call(this, input);
}
});
/**
* Press
* Recognized when the pointer is down for x ms without any movement.
* @constructor
* @extends Recognizer
*/
function PressRecognizer() {
Recognizer.apply(this, arguments);
this._timer = null;
this._input = null;
}
inherit(PressRecognizer, Recognizer, {
/**
* @namespace
* @memberof PressRecognizer
*/
defaults: {
event: 'press',
pointers: 1,
time: 251, // minimal time of the pointer to be pressed
threshold: 9 // a minimal movement is ok, but keep it low
},
getTouchAction: function() {
return [TOUCH_ACTION_AUTO];
},
process: function(input) {
var options = this.options;
var validPointers = input.pointers.length === options.pointers;
var validMovement = input.distance < options.threshold;
var validTime = input.deltaTime > options.time;
this._input = input;
// we only allow little movement
// and we've reached an end event, so a tap is possible
if (!validMovement || !validPointers || (input.eventType & (INPUT_END | INPUT_CANCEL) && !validTime)) {
this.reset();
} else if (input.eventType & INPUT_START) {
this.reset();
this._timer = setTimeoutContext(function() {
this.state = STATE_RECOGNIZED;
this.tryEmit();
}, options.time, this);
} else if (input.eventType & INPUT_END) {
return STATE_RECOGNIZED;
}
return STATE_FAILED;
},
reset: function() {
clearTimeout(this._timer);
},
emit: function(input) {
if (this.state !== STATE_RECOGNIZED) {
return;
}
if (input && (input.eventType & INPUT_END)) {
this.manager.emit(this.options.event + 'up', input);
} else {
this._input.timeStamp = now();
this.manager.emit(this.options.event, this._input);
}
}
});
/**
* Rotate
* Recognized when two or more pointer are moving in a circular motion.
* @constructor
* @extends AttrRecognizer
*/
function RotateRecognizer() {
AttrRecognizer.apply(this, arguments);
}
inherit(RotateRecognizer, AttrRecognizer, {
/**
* @namespace
* @memberof RotateRecognizer
*/
defaults: {
event: 'rotate',
threshold: 0,
pointers: 2
},
getTouchAction: function() {
return [TOUCH_ACTION_NONE];
},
attrTest: function(input) {
return this._super.attrTest.call(this, input) &&
(Math.abs(input.rotation) > this.options.threshold || this.state & STATE_BEGAN);
}
});
/**
* Swipe
* Recognized when the pointer is moving fast (velocity), with enough distance in the allowed direction.
* @constructor
* @extends AttrRecognizer
*/
function SwipeRecognizer() {
AttrRecognizer.apply(this, arguments);
}
inherit(SwipeRecognizer, AttrRecognizer, {
/**
* @namespace
* @memberof SwipeRecognizer
*/
defaults: {
event: 'swipe',
threshold: 10,
velocity: 0.3,
direction: DIRECTION_HORIZONTAL | DIRECTION_VERTICAL,
pointers: 1
},
getTouchAction: function() {
return PanRecognizer.prototype.getTouchAction.call(this);
},
attrTest: function(input) {
var direction = this.options.direction;
var velocity;
if (direction & (DIRECTION_HORIZONTAL | DIRECTION_VERTICAL)) {
velocity = input.overallVelocity;
} else if (direction & DIRECTION_HORIZONTAL) {
velocity = input.overallVelocityX;
} else if (direction & DIRECTION_VERTICAL) {
velocity = input.overallVelocityY;
}
return this._super.attrTest.call(this, input) &&
direction & input.offsetDirection &&
input.distance > this.options.threshold &&
input.maxPointers == this.options.pointers &&
abs(velocity) > this.options.velocity && input.eventType & INPUT_END;
},
emit: function(input) {
var direction = directionStr(input.offsetDirection);
if (direction) {
this.manager.emit(this.options.event + direction, input);
}
this.manager.emit(this.options.event, input);
}
});
/**
* A tap is ecognized when the pointer is doing a small tap/click. Multiple taps are recognized if they occur
* between the given interval and position. The delay option can be used to recognize multi-taps without firing
* a single tap.
*
* The eventData from the emitted event contains the property `tapCount`, which contains the amount of
* multi-taps being recognized.
* @constructor
* @extends Recognizer
*/
function TapRecognizer() {
Recognizer.apply(this, arguments);
// previous time and center,
// used for tap counting
this.pTime = false;
this.pCenter = false;
this._timer = null;
this._input = null;
this.count = 0;
}
inherit(TapRecognizer, Recognizer, {
/**
* @namespace
* @memberof PinchRecognizer
*/
defaults: {
event: 'tap',
pointers: 1,
taps: 1,
interval: 300, // max time between the multi-tap taps
time: 250, // max time of the pointer to be down (like finger on the screen)
threshold: 9, // a minimal movement is ok, but keep it low
posThreshold: 10 // a multi-tap can be a bit off the initial position
},
getTouchAction: function() {
return [TOUCH_ACTION_MANIPULATION];
},
process: function(input) {
var options = this.options;
var validPointers = input.pointers.length === options.pointers;
var validMovement = input.distance < options.threshold;
var validTouchTime = input.deltaTime < options.time;
this.reset();
if ((input.eventType & INPUT_START) && (this.count === 0)) {
return this.failTimeout();
}
// we only allow little movement
// and we've reached an end event, so a tap is possible
if (validMovement && validTouchTime && validPointers) {
if (input.eventType != INPUT_END) {
return this.failTimeout();
}
var validInterval = this.pTime ? (input.timeStamp - this.pTime < options.interval) : true;
var validMultiTap = !this.pCenter || getDistance(this.pCenter, input.center) < options.posThreshold;
this.pTime = input.timeStamp;
this.pCenter = input.center;
if (!validMultiTap || !validInterval) {
this.count = 1;
} else {
this.count += 1;
}
this._input = input;
// if tap count matches we have recognized it,
// else it has began recognizing...
var tapCount = this.count % options.taps;
if (tapCount === 0) {
// no failing requirements, immediately trigger the tap event
// or wait as long as the multitap interval to trigger
if (!this.hasRequireFailures()) {
return STATE_RECOGNIZED;
} else {
this._timer = setTimeoutContext(function() {
this.state = STATE_RECOGNIZED;
this.tryEmit();
}, options.interval, this);
return STATE_BEGAN;
}
}
}
return STATE_FAILED;
},
failTimeout: function() {
this._timer = setTimeoutContext(function() {
this.state = STATE_FAILED;
}, this.options.interval, this);
return STATE_FAILED;
},
reset: function() {
clearTimeout(this._timer);
},
emit: function() {
if (this.state == STATE_RECOGNIZED) {
this._input.tapCount = this.count;
this.manager.emit(this.options.event, this._input);
}
}
});
/**
* Simple way to create a manager with a default set of recognizers.
* @param {HTMLElement} element
* @param {Object} [options]
* @constructor
*/
function Hammer(element, options) {
options = options || {};
options.recognizers = ifUndefined(options.recognizers, Hammer.defaults.preset);
return new Manager(element, options);
}
/**
* @const {string}
*/
Hammer.VERSION = '2.0.7';
/**
* default settings
* @namespace
*/
Hammer.defaults = {
/**
* set if DOM events are being triggered.
* But this is slower and unused by simple implementations, so disabled by default.
* @type {Boolean}
* @default false
*/
domEvents: false,
/**
* The value for the touchAction property/fallback.
* When set to `compute` it will magically set the correct value based on the added recognizers.
* @type {String}
* @default compute
*/
touchAction: TOUCH_ACTION_COMPUTE,
/**
* @type {Boolean}
* @default true
*/
enable: true,
/**
* EXPERIMENTAL FEATURE -- can be removed/changed
* Change the parent input target element.
* If Null, then it is being set the to main element.
* @type {Null|EventTarget}
* @default null
*/
inputTarget: null,
/**
* force an input class
* @type {Null|Function}
* @default null
*/
inputClass: null,
/**
* Default recognizer setup when calling `Hammer()`
* When creating a new Manager these will be skipped.
* @type {Array}
*/
preset: [
// RecognizerClass, options, [recognizeWith, ...], [requireFailure, ...]
[RotateRecognizer, {enable: false}],
[PinchRecognizer, {enable: false}, ['rotate']],
[SwipeRecognizer, {direction: DIRECTION_HORIZONTAL}],
[PanRecognizer, {direction: DIRECTION_HORIZONTAL}, ['swipe']],
[TapRecognizer],
[TapRecognizer, {event: 'doubletap', taps: 2}, ['tap']],
[PressRecognizer]
],
/**
* Some CSS properties can be used to improve the working of Hammer.
* Add them to this method and they will be set when creating a new Manager.
* @namespace
*/
cssProps: {
/**
* Disables text selection to improve the dragging gesture. Mainly for desktop browsers.
* @type {String}
* @default 'none'
*/
userSelect: 'none',
/**
* Disable the Windows Phone grippers when pressing an element.
* @type {String}
* @default 'none'
*/
touchSelect: 'none',
/**
* Disables the default callout shown when you touch and hold a touch target.
* On iOS, when you touch and hold a touch target such as a link, Safari displays
* a callout containing information about the link. This property allows you to disable that callout.
* @type {String}
* @default 'none'
*/
touchCallout: 'none',
/**
* Specifies whether zooming is enabled. Used by IE10>
* @type {String}
* @default 'none'
*/
contentZooming: 'none',
/**
* Specifies that an entire element should be draggable instead of its contents. Mainly for desktop browsers.
* @type {String}
* @default 'none'
*/
userDrag: 'none',
/**
* Overrides the highlight color shown when the user taps a link or a JavaScript
* clickable element in iOS. This property obeys the alpha value, if specified.
* @type {String}
* @default 'rgba(0,0,0,0)'
*/
tapHighlightColor: 'rgba(0,0,0,0)'
}
};
var STOP = 1;
var FORCED_STOP = 2;
/**
* Manager
* @param {HTMLElement} element
* @param {Object} [options]
* @constructor
*/
function Manager(element, options) {
this.options = assign({}, Hammer.defaults, options || {});
this.options.inputTarget = this.options.inputTarget || element;
this.handlers = {};
this.session = {};
this.recognizers = [];
this.oldCssProps = {};
this.element = element;
this.input = createInputInstance(this);
this.touchAction = new TouchAction(this, this.options.touchAction);
toggleCssProps(this, true);
each(this.options.recognizers, function(item) {
var recognizer = this.add(new (item[0])(item[1]));
item[2] && recognizer.recognizeWith(item[2]);
item[3] && recognizer.requireFailure(item[3]);
}, this);
}
Manager.prototype = {
/**
* set options
* @param {Object} options
* @returns {Manager}
*/
set: function(options) {
assign(this.options, options);
// Options that need a little more setup
if (options.touchAction) {
this.touchAction.update();
}
if (options.inputTarget) {
// Clean up existing event listeners and reinitialize
this.input.destroy();
this.input.target = options.inputTarget;
this.input.init();
}
return this;
},
/**
* stop recognizing for this session.
* This session will be discarded, when a new [input]start event is fired.
* When forced, the recognizer cycle is stopped immediately.
* @param {Boolean} [force]
*/
stop: function(force) {
this.session.stopped = force ? FORCED_STOP : STOP;
},
/**
* run the recognizers!
* called by the inputHandler function on every movement of the pointers (touches)
* it walks through all the recognizers and tries to detect the gesture that is being made
* @param {Object} inputData
*/
recognize: function(inputData) {
var session = this.session;
if (session.stopped) {
return;
}
// run the touch-action polyfill
this.touchAction.preventDefaults(inputData);
var recognizer;
var recognizers = this.recognizers;
// this holds the recognizer that is being recognized.
// so the recognizer's state needs to be BEGAN, CHANGED, ENDED or RECOGNIZED
// if no recognizer is detecting a thing, it is set to `null`
var curRecognizer = session.curRecognizer;
// reset when the last recognizer is recognized
// or when we're in a new session
if (!curRecognizer || (curRecognizer && curRecognizer.state & STATE_RECOGNIZED)) {
curRecognizer = session.curRecognizer = null;
}
var i = 0;
while (i < recognizers.length) {
recognizer = recognizers[i];
// find out if we are allowed try to recognize the input for this one.
// 1. allow if the session is NOT forced stopped (see the .stop() method)
// 2. allow if we still haven't recognized a gesture in this session, or the this recognizer is the one
// that is being recognized.
// 3. allow if the recognizer is allowed to run simultaneous with the current recognized recognizer.
// this can be setup with the `recognizeWith()` method on the recognizer.
if (session.stopped !== FORCED_STOP && ( // 1
!curRecognizer || recognizer == curRecognizer || // 2
recognizer.canRecognizeWith(curRecognizer))) { // 3
recognizer.recognize(inputData);
} else {
recognizer.reset();
}
// if the recognizer has been recognizing the input as a valid gesture, we want to store this one as the
// current active recognizer. but only if we don't already have an active recognizer
if (!curRecognizer && recognizer.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED)) {
curRecognizer = session.curRecognizer = recognizer;
}
i++;
}
},
/**
* get a recognizer by its event name.
* @param {Recognizer|String} recognizer
* @returns {Recognizer|Null}
*/
get: function(recognizer) {
if (recognizer instanceof Recognizer) {
return recognizer;
}
var recognizers = this.recognizers;
for (var i = 0; i < recognizers.length; i++) {
if (recognizers[i].options.event == recognizer) {
return recognizers[i];
}
}
return null;
},
/**
* add a recognizer to the manager
* existing recognizers with the same event name will be removed
* @param {Recognizer} recognizer
* @returns {Recognizer|Manager}
*/
add: function(recognizer) {
if (invokeArrayArg(recognizer, 'add', this)) {
return this;
}
// remove existing
var existing = this.get(recognizer.options.event);
if (existing) {
this.remove(existing);
}
this.recognizers.push(recognizer);
recognizer.manager = this;
this.touchAction.update();
return recognizer;
},
/**
* remove a recognizer by name or instance
* @param {Recognizer|String} recognizer
* @returns {Manager}
*/
remove: function(recognizer) {
if (invokeArrayArg(recognizer, 'remove', this)) {
return this;
}
recognizer = this.get(recognizer);
// let's make sure this recognizer exists
if (recognizer) {
var recognizers = this.recognizers;
var index = inArray(recognizers, recognizer);
if (index !== -1) {
recognizers.splice(index, 1);
this.touchAction.update();
}
}
return this;
},
/**
* bind event
* @param {String} events
* @param {Function} handler
* @returns {EventEmitter} this
*/
on: function(events, handler) {
if (events === undefined) {
return;
}
if (handler === undefined) {
return;
}
var handlers = this.handlers;
each(splitStr(events), function(event) {
handlers[event] = handlers[event] || [];
handlers[event].push(handler);
});
return this;
},
/**
* unbind event, leave emit blank to remove all handlers
* @param {String} events
* @param {Function} [handler]
* @returns {EventEmitter} this
*/
off: function(events, handler) {
if (events === undefined) {
return;
}
var handlers = this.handlers;
each(splitStr(events), function(event) {
if (!handler) {
delete handlers[event];
} else {
handlers[event] && handlers[event].splice(inArray(handlers[event], handler), 1);
}
});
return this;
},
/**
* emit event to the listeners
* @param {String} event
* @param {Object} data
*/
emit: function(event, data) {
// we also want to trigger dom events
if (this.options.domEvents) {
triggerDomEvent(event, data);
}
// no handlers, so skip it all
var handlers = this.handlers[event] && this.handlers[event].slice();
if (!handlers || !handlers.length) {
return;
}
data.type = event;
data.preventDefault = function() {
data.srcEvent.preventDefault();
};
var i = 0;
while (i < handlers.length) {
handlers[i](data);
i++;
}
},
/**
* destroy the manager and unbinds all events
* it doesn't unbind dom events, that is the user own responsibility
*/
destroy: function() {
this.element && toggleCssProps(this, false);
this.handlers = {};
this.session = {};
this.input.destroy();
this.element = null;
}
};
/**
* add/remove the css properties as defined in manager.options.cssProps
* @param {Manager} manager
* @param {Boolean} add
*/
function toggleCssProps(manager, add) {
var element = manager.element;
if (!element.style) {
return;
}
var prop;
each(manager.options.cssProps, function(value, name) {
prop = prefixed(element.style, name);
if (add) {
manager.oldCssProps[prop] = element.style[prop];
element.style[prop] = value;
} else {
element.style[prop] = manager.oldCssProps[prop] || '';
}
});
if (!add) {
manager.oldCssProps = {};
}
}
/**
* trigger dom event
* @param {String} event
* @param {Object} data
*/
function triggerDomEvent(event, data) {
var gestureEvent = document.createEvent('Event');
gestureEvent.initEvent(event, true, true);
gestureEvent.gesture = data;
data.target.dispatchEvent(gestureEvent);
}
assign(Hammer, {
INPUT_START: INPUT_START,
INPUT_MOVE: INPUT_MOVE,
INPUT_END: INPUT_END,
INPUT_CANCEL: INPUT_CANCEL,
STATE_POSSIBLE: STATE_POSSIBLE,
STATE_BEGAN: STATE_BEGAN,
STATE_CHANGED: STATE_CHANGED,
STATE_ENDED: STATE_ENDED,
STATE_RECOGNIZED: STATE_RECOGNIZED,
STATE_CANCELLED: STATE_CANCELLED,
STATE_FAILED: STATE_FAILED,
DIRECTION_NONE: DIRECTION_NONE,
DIRECTION_LEFT: DIRECTION_LEFT,
DIRECTION_RIGHT: DIRECTION_RIGHT,
DIRECTION_UP: DIRECTION_UP,
DIRECTION_DOWN: DIRECTION_DOWN,
DIRECTION_HORIZONTAL: DIRECTION_HORIZONTAL,
DIRECTION_VERTICAL: DIRECTION_VERTICAL,
DIRECTION_ALL: DIRECTION_ALL,
Manager: Manager,
Input: Input,
TouchAction: TouchAction,
TouchInput: TouchInput,
MouseInput: MouseInput,
PointerEventInput: PointerEventInput,
TouchMouseInput: TouchMouseInput,
SingleTouchInput: SingleTouchInput,
Recognizer: Recognizer,
AttrRecognizer: AttrRecognizer,
Tap: TapRecognizer,
Pan: PanRecognizer,
Swipe: SwipeRecognizer,
Pinch: PinchRecognizer,
Rotate: RotateRecognizer,
Press: PressRecognizer,
on: addEventListeners,
off: removeEventListeners,
each: each,
merge: merge,
extend: extend,
assign: assign,
inherit: inherit,
bindFn: bindFn,
prefixed: prefixed
});
// this prevents errors when Hammer is loaded in the presence of an AMD
// style loader but by script tag, not by the loader.
var freeGlobal = (typeof window !== 'undefined' ? window : (typeof self !== 'undefined' ? self : {})); // jshint ignore:line
freeGlobal.Hammer = Hammer;
if (true) {
!(__WEBPACK_AMD_DEFINE_RESULT__ = function() {
return Hammer;
}.call(exports, __webpack_require__, exports, module),
__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
} else if (typeof module != 'undefined' && module.exports) {
module.exports = Hammer;
} else {
window[exportName] = Hammer;
}
})(window, document, 'Hammer');
/***/ }),
/* 12 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
// declare var jQuery: any;
Object.defineProperty(exports, "__esModule", { value: true });
function $(param, multi) {
if (multi === void 0) { multi = false; }
var el;
if (typeof param === "string") {
// check if string is HTML tag format
var match = param.match(/^<([a-z]+)\s*([^>]*)>/);
// creating element
if (match) {
var dummy = document.createElement("div");
dummy.innerHTML = param;
el = Array.prototype.slice.call(dummy.childNodes);
}
else {
el = Array.prototype.slice.call(document.querySelectorAll(param));
}
if (!multi) {
el = el.length >= 1 ? el[0] : undefined;
}
}
else if (param.nodeName &&
(param.nodeType === 1 || param.nodeType === 9)) {
el = param;
}
else if (("jQuery" in window && param instanceof jQuery) ||
param.constructor.prototype.jquery) {
el = multi ? param.toArray() : param.get(0);
}
return el;
}
exports.$ = $;
/***/ }),
/* 13 */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var InputType = (function () {
function InputType() {
}
InputType.prototype.mapAxes = function (axes) {
this.axes = axes;
};
return InputType;
}());
exports.InputType = InputType;
/***/ })
/******/ ]);
});