UNPKG

209 kBJavaScriptView Raw
1/*
2Copyright (c) 2015 NAVER Corp.
3name: @egjs/axes
4license: MIT
5author: NAVER Corp.
6repository: https://github.com/naver/egjs-axes
7version: 2.8.0
8*/
9(function (global, factory) {
10 typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
11 typeof define === 'function' && define.amd ? define(factory) :
12 (global.eg = global.eg || {}, global.eg.Axes = factory());
13}(this, (function () { 'use strict';
14
15 /*! *****************************************************************************
16 Copyright (c) Microsoft Corporation. All rights reserved.
17 Licensed under the Apache License, Version 2.0 (the "License"); you may not use
18 this file except in compliance with the License. You may obtain a copy of the
19 License at http://www.apache.org/licenses/LICENSE-2.0
20
21 THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
22 KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
23 WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
24 MERCHANTABLITY OR NON-INFRINGEMENT.
25
26 See the Apache Version 2.0 License for specific language governing permissions
27 and limitations under the License.
28 ***************************************************************************** */
29
30 /* global Reflect, Promise */
31 var extendStatics = function (d, b) {
32 extendStatics = Object.setPrototypeOf || {
33 __proto__: []
34 } instanceof Array && function (d, b) {
35 d.__proto__ = b;
36 } || function (d, b) {
37 for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
38 };
39
40 return extendStatics(d, b);
41 };
42
43 function __extends(d, b) {
44 extendStatics(d, b);
45
46 function __() {
47 this.constructor = d;
48 }
49
50 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
51 }
52 var __assign = function () {
53 __assign = Object.assign || function __assign(t) {
54 for (var s, i = 1, n = arguments.length; i < n; i++) {
55 s = arguments[i];
56
57 for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
58 }
59
60 return t;
61 };
62
63 return __assign.apply(this, arguments);
64 };
65
66 /*
67 Copyright (c) NAVER Corp.
68 name: @egjs/component
69 license: MIT
70 author: NAVER Corp.
71 repository: https://github.com/naver/egjs-component
72 version: 2.2.2
73 */
74 /*! *****************************************************************************
75 Copyright (c) Microsoft Corporation.
76
77 Permission to use, copy, modify, and/or distribute this software for any
78 purpose with or without fee is hereby granted.
79
80 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
81 REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
82 AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
83 INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
84 LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
85 OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
86 PERFORMANCE OF THIS SOFTWARE.
87 ***************************************************************************** */
88 function __values$1(o) {
89 var s = typeof Symbol === "function" && Symbol.iterator,
90 m = s && o[s],
91 i = 0;
92 if (m) return m.call(o);
93 if (o && typeof o.length === "number") return {
94 next: function () {
95 if (o && i >= o.length) o = void 0;
96 return {
97 value: o && o[i++],
98 done: !o
99 };
100 }
101 };
102 throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
103 }
104
105 /*
106 * Copyright (c) 2015 NAVER Corp.
107 * egjs projects are licensed under the MIT license
108 */
109
110 function isUndefined(value) {
111 return typeof value === "undefined";
112 }
113 /**
114 * A class used to manage events in a component
115 * @ko 컴포넌트의 이벤트을 관리할 수 있게 하는 클래스
116 * @alias eg.Component
117 */
118
119
120 var Component =
121 /*#__PURE__*/
122 function () {
123 /**
124 * @support {"ie": "7+", "ch" : "latest", "ff" : "latest", "sf" : "latest", "edge" : "latest", "ios" : "7+", "an" : "2.1+ (except 3.x)"}
125 */
126 function Component() {
127 /**
128 * @deprecated
129 * @private
130 */
131 this.options = {};
132 this._eventHandler = {};
133 }
134 /**
135 * Triggers a custom event.
136 * @ko 커스텀 이벤트를 발생시킨다
137 * @param {string} eventName The name of the custom event to be triggered <ko>발생할 커스텀 이벤트의 이름</ko>
138 * @param {object} customEvent Event data to be sent when triggering a custom event <ko>커스텀 이벤트가 발생할 때 전달할 데이터</ko>
139 * @param {any[]} restParam Additional parameters when triggering a custom event <ko>커스텀 이벤트가 발생할 때 필요시 추가적으로 전달할 데이터</ko>
140 * @return 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. <a href="https://github.com/naver/egjs-component/wiki/How-to-make-Component-event-design%3F">Ref</a> <ko>이벤트 발생 여부. 커스텀 이벤트 핸들러에서 stop() 메서드를 호출하면 'false'를 반환하고 이벤트 발생을 중단한다. <a href="https://github.com/naver/egjs-component/wiki/How-to-make-Component-event-design%3F">참고</a></ko>
141 * @example
142 * ```
143 * class Some extends eg.Component {
144 * some(){
145 * if(this.trigger("beforeHi")){ // When event call to stop return false.
146 * this.trigger("hi");// fire hi event.
147 * }
148 * }
149 * }
150 *
151 * const some = new Some();
152 * some.on("beforeHi", (e) => {
153 * if(condition){
154 * e.stop(); // When event call to stop, `hi` event not call.
155 * }
156 * });
157 * some.on("hi", (e) => {
158 * // `currentTarget` is component instance.
159 * console.log(some === e.currentTarget); // true
160 * });
161 * // If you want to more know event design. You can see article.
162 * // https://github.com/naver/egjs-component/wiki/How-to-make-Component-event-design%3F
163 * ```
164 */
165
166
167 var __proto = Component.prototype;
168
169 __proto.trigger = function (eventName) {
170 var _this = this;
171
172 var params = [];
173
174 for (var _i = 1; _i < arguments.length; _i++) {
175 params[_i - 1] = arguments[_i];
176 }
177
178 var handlerList = this._eventHandler[eventName] || [];
179 var hasHandlerList = handlerList.length > 0;
180
181 if (!hasHandlerList) {
182 return true;
183 }
184
185 var customEvent = params[0] || {};
186 var restParams = params.slice(1); // If detach method call in handler in first time then handler list calls.
187
188 handlerList = handlerList.concat();
189 var isCanceled = false; // This should be done like this to pass previous tests
190
191 customEvent.eventType = eventName;
192
193 customEvent.stop = function () {
194 isCanceled = true;
195 };
196
197 customEvent.currentTarget = this;
198 var arg = [customEvent];
199
200 if (restParams.length >= 1) {
201 arg = arg.concat(restParams);
202 }
203
204 handlerList.forEach(function (handler) {
205 handler.apply(_this, arg);
206 });
207 return !isCanceled;
208 };
209 /**
210 * Executed event just one time.
211 * @ko 이벤트가 한번만 실행된다.
212 * @param {string} eventName The name of the event to be attached <ko>등록할 이벤트의 이름</ko>
213 * @param {function} handlerToAttach The handler function of the event to be attached <ko>등록할 이벤트의 핸들러 함수</ko>
214 * @return An instance of a component itself<ko>컴포넌트 자신의 인스턴스</ko>
215 * @example
216 * ```
217 * class Some extends eg.Component {
218 * hi() {
219 * alert("hi");
220 * }
221 * thing() {
222 * this.once("hi", this.hi);
223 * }
224 *
225 * var some = new Some();
226 * some.thing();
227 * some.trigger("hi");
228 * // fire alert("hi");
229 * some.trigger("hi");
230 * // Nothing happens
231 * ```
232 */
233
234
235 __proto.once = function (eventName, handlerToAttach) {
236 var _this = this;
237
238 if (typeof eventName === "object" && isUndefined(handlerToAttach)) {
239 var eventHash = eventName;
240
241 for (var key in eventHash) {
242 this.once(key, eventHash[key]);
243 }
244
245 return this;
246 } else if (typeof eventName === "string" && typeof handlerToAttach === "function") {
247 var listener_1 = function () {
248 var args = [];
249
250 for (var _i = 0; _i < arguments.length; _i++) {
251 args[_i] = arguments[_i];
252 }
253
254 handlerToAttach.apply(_this, args);
255
256 _this.off(eventName, listener_1);
257 };
258
259 this.on(eventName, listener_1);
260 }
261
262 return this;
263 };
264 /**
265 * Checks whether an event has been attached to a component.
266 * @ko 컴포넌트에 이벤트가 등록됐는지 확인한다.
267 * @param {string} eventName The name of the event to be attached <ko>등록 여부를 확인할 이벤트의 이름</ko>
268 * @return {boolean} Indicates whether the event is attached. <ko>이벤트 등록 여부</ko>
269 * @example
270 * ```
271 * class Some extends eg.Component {
272 * some() {
273 * this.hasOn("hi");// check hi event.
274 * }
275 * }
276 * ```
277 */
278
279
280 __proto.hasOn = function (eventName) {
281 return !!this._eventHandler[eventName];
282 };
283 /**
284 * Attaches an event to a component.
285 * @ko 컴포넌트에 이벤트를 등록한다.
286 * @param {string} eventName The name of the event to be attached <ko>등록할 이벤트의 이름</ko>
287 * @param {function} handlerToAttach The handler function of the event to be attached <ko>등록할 이벤트의 핸들러 함수</ko>
288 * @return An instance of a component itself<ko>컴포넌트 자신의 인스턴스</ko>
289 * @example
290 * ```
291 * class Some extends eg.Component {
292 * hi() {
293 * console.log("hi");
294 * }
295 * some() {
296 * this.on("hi",this.hi); //attach event
297 * }
298 * }
299 * ```
300 */
301
302
303 __proto.on = function (eventName, handlerToAttach) {
304 if (typeof eventName === "object" && isUndefined(handlerToAttach)) {
305 var eventHash = eventName;
306
307 for (var name in eventHash) {
308 this.on(name, eventHash[name]);
309 }
310
311 return this;
312 } else if (typeof eventName === "string" && typeof handlerToAttach === "function") {
313 var handlerList = this._eventHandler[eventName];
314
315 if (isUndefined(handlerList)) {
316 this._eventHandler[eventName] = [];
317 handlerList = this._eventHandler[eventName];
318 }
319
320 handlerList.push(handlerToAttach);
321 }
322
323 return this;
324 };
325 /**
326 * Detaches an event from the component.
327 * @ko 컴포넌트에 등록된 이벤트를 해제한다
328 * @param {string} eventName The name of the event to be detached <ko>해제할 이벤트의 이름</ko>
329 * @param {function} handlerToDetach The handler function of the event to be detached <ko>해제할 이벤트의 핸들러 함수</ko>
330 * @return An instance of a component itself <ko>컴포넌트 자신의 인스턴스</ko>
331 * @example
332 * ```
333 * class Some extends eg.Component {
334 * hi() {
335 * console.log("hi");
336 * }
337 * some() {
338 * this.off("hi",this.hi); //detach event
339 * }
340 * }
341 * ```
342 */
343
344
345 __proto.off = function (eventName, handlerToDetach) {
346 var e_1, _a; // Detach all event handlers.
347
348
349 if (isUndefined(eventName)) {
350 this._eventHandler = {};
351 return this;
352 } // Detach all handlers for eventname or detach event handlers by object.
353
354
355 if (isUndefined(handlerToDetach)) {
356 if (typeof eventName === "string") {
357 delete this._eventHandler[eventName];
358 return this;
359 } else {
360 var eventHash = eventName;
361
362 for (var name in eventHash) {
363 this.off(name, eventHash[name]);
364 }
365
366 return this;
367 }
368 } // Detach single event handler
369
370
371 var handlerList = this._eventHandler[eventName];
372
373 if (handlerList) {
374 var idx = 0;
375
376 try {
377 for (var handlerList_1 = __values$1(handlerList), handlerList_1_1 = handlerList_1.next(); !handlerList_1_1.done; handlerList_1_1 = handlerList_1.next()) {
378 var handlerFunction = handlerList_1_1.value;
379
380 if (handlerFunction === handlerToDetach) {
381 handlerList.splice(idx, 1);
382 break;
383 }
384
385 idx++;
386 }
387 } catch (e_1_1) {
388 e_1 = {
389 error: e_1_1
390 };
391 } finally {
392 try {
393 if (handlerList_1_1 && !handlerList_1_1.done && (_a = handlerList_1.return)) _a.call(handlerList_1);
394 } finally {
395 if (e_1) throw e_1.error;
396 }
397 }
398 }
399
400 return this;
401 };
402 /**
403 * Version info string
404 * @ko 버전정보 문자열
405 * @name VERSION
406 * @static
407 * @example
408 * eg.Component.VERSION; // ex) 2.0.0
409 * @memberof eg.Component
410 */
411
412
413 Component.VERSION = "2.2.2";
414 return Component;
415 }();
416
417 function getInsidePosition(destPos, range, circular, bounce) {
418 var toDestPos = destPos;
419 var targetRange = [circular[0] ? range[0] : bounce ? range[0] - bounce[0] : range[0], circular[1] ? range[1] : bounce ? range[1] + bounce[1] : range[1]];
420 toDestPos = Math.max(targetRange[0], toDestPos);
421 toDestPos = Math.min(targetRange[1], toDestPos);
422 return toDestPos;
423 } // determine outside
424
425 function isOutside(pos, range) {
426 return pos < range[0] || pos > range[1];
427 }
428 function getDuration(distance, deceleration) {
429 var duration = Math.sqrt(distance / deceleration * 2); // when duration is under 100, then value is zero
430
431 return duration < 100 ? 0 : duration;
432 }
433 function isCircularable(destPos, range, circular) {
434 return circular[1] && destPos > range[1] || circular[0] && destPos < range[0];
435 }
436 function getCirculatedPos(pos, range, circular) {
437 var toPos = pos;
438 var min = range[0];
439 var max = range[1];
440 var length = max - min;
441
442 if (circular[1] && pos > max) {
443 // right
444 toPos = (toPos - max) % length + min;
445 }
446
447 if (circular[0] && pos < min) {
448 // left
449 toPos = (toPos - min) % length + max;
450 }
451
452 return toPos;
453 }
454
455 /* eslint-disable no-new-func, no-nested-ternary */
456 var win;
457
458 if (typeof window === "undefined") {
459 // window is undefined in node.js
460 win = {
461 navigator: {
462 userAgent: ""
463 }
464 };
465 } else {
466 win = window;
467 }
468
469 function toArray(nodes) {
470 // const el = Array.prototype.slice.call(nodes);
471 // for IE8
472 var el = [];
473
474 for (var i = 0, len = nodes.length; i < len; i++) {
475 el.push(nodes[i]);
476 }
477
478 return el;
479 }
480 function $(param, multi) {
481 if (multi === void 0) {
482 multi = false;
483 }
484
485 var el;
486
487 if (typeof param === "string") {
488 // String (HTML, Selector)
489 // check if string is HTML tag format
490 var match = param.match(/^<([a-z]+)\s*([^>]*)>/); // creating element
491
492 if (match) {
493 // HTML
494 var dummy = document.createElement("div");
495 dummy.innerHTML = param;
496 el = toArray(dummy.childNodes);
497 } else {
498 // Selector
499 el = toArray(document.querySelectorAll(param));
500 }
501
502 if (!multi) {
503 el = el.length >= 1 ? el[0] : undefined;
504 }
505 } else if (param === win) {
506 // window
507 el = param;
508 } else if (param.nodeName && (param.nodeType === 1 || param.nodeType === 9)) {
509 // HTMLElement, Document
510 el = param;
511 } else if ("jQuery" in win && param instanceof jQuery || param.constructor.prototype.jquery) {
512 // jQuery
513 el = multi ? param.toArray() : param.get(0);
514 } else if (Array.isArray(param)) {
515 el = param.map(function (v) {
516 return $(v);
517 });
518
519 if (!multi) {
520 el = el.length >= 1 ? el[0] : undefined;
521 }
522 }
523
524 return el;
525 }
526 var raf = win.requestAnimationFrame || win.webkitRequestAnimationFrame;
527 var caf = win.cancelAnimationFrame || win.webkitCancelAnimationFrame;
528
529 if (raf && !caf) {
530 var keyInfo_1 = {};
531 var oldraf_1 = raf;
532
533 raf = function (callback) {
534 function wrapCallback(timestamp) {
535 if (keyInfo_1[key]) {
536 callback(timestamp);
537 }
538 }
539
540 var key = oldraf_1(wrapCallback);
541 keyInfo_1[key] = true;
542 return key;
543 };
544
545 caf = function (key) {
546 delete keyInfo_1[key];
547 };
548 } else if (!(raf && caf)) {
549 raf = function (callback) {
550 return win.setTimeout(function () {
551 callback(win.performance && win.performance.now && win.performance.now() || new Date().getTime());
552 }, 16);
553 };
554
555 caf = win.clearTimeout;
556 }
557 /**
558 * A polyfill for the window.requestAnimationFrame() method.
559 * @see https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame
560 * @private
561 */
562
563
564 function requestAnimationFrame(fp) {
565 return raf(fp);
566 }
567 /**
568 * A polyfill for the window.cancelAnimationFrame() method. It cancels an animation executed through a call to the requestAnimationFrame() method.
569 * @param {Number} key − The ID value returned through a call to the requestAnimationFrame() method. <ko>requestAnimationFrame() 메서드가 반환한 아이디 값</ko>
570 * @see https://developer.mozilla.org/en-US/docs/Web/API/Window/cancelAnimationFrame
571 * @private
572 */
573
574 function cancelAnimationFrame(key) {
575 caf(key);
576 }
577 function map(obj, callback) {
578 var tranformed = {};
579
580 for (var k in obj) {
581 k && (tranformed[k] = callback(obj[k], k));
582 }
583
584 return tranformed;
585 }
586 function filter(obj, callback) {
587 var filtered = {};
588
589 for (var k in obj) {
590 k && callback(obj[k], k) && (filtered[k] = obj[k]);
591 }
592
593 return filtered;
594 }
595 function every(obj, callback) {
596 for (var k in obj) {
597 if (k && !callback(obj[k], k)) {
598 return false;
599 }
600 }
601
602 return true;
603 }
604 function equal(target, base) {
605 return every(target, function (v, k) {
606 return v === base[k];
607 });
608 }
609 var roundNumFunc = {};
610 function roundNumber(num, roundUnit) {
611 // Cache for performance
612 if (!roundNumFunc[roundUnit]) {
613 roundNumFunc[roundUnit] = getRoundFunc(roundUnit);
614 }
615
616 return roundNumFunc[roundUnit](num);
617 }
618 function roundNumbers(num, roundUnit) {
619 if (!num || !roundUnit) {
620 return num;
621 }
622
623 var isNumber = typeof roundUnit === "number";
624 return map(num, function (value, key) {
625 return roundNumber(value, isNumber ? roundUnit : roundUnit[key]);
626 });
627 }
628 function getDecimalPlace(val) {
629 if (!isFinite(val)) {
630 return 0;
631 }
632
633 var v = val + "";
634
635 if (v.indexOf("e") >= 0) {
636 // Exponential Format
637 // 1e-10, 1e-12
638 var p = 0;
639 var e = 1;
640
641 while (Math.round(val * e) / e !== val) {
642 e *= 10;
643 p++;
644 }
645
646 return p;
647 } // In general, following has performance benefit.
648 // https://jsperf.com/precision-calculation
649
650
651 return v.indexOf(".") >= 0 ? v.length - v.indexOf(".") - 1 : 0;
652 }
653 function inversePow(n) {
654 // replace Math.pow(10, -n) to solve floating point issue.
655 // eg. Math.pow(10, -4) => 0.00009999999999999999
656 return 1 / Math.pow(10, n);
657 }
658 function getRoundFunc(v) {
659 var p = v < 1 ? Math.pow(10, getDecimalPlace(v)) : 1;
660 return function (n) {
661 if (v === 0) {
662 return 0;
663 }
664
665 return Math.round(Math.round(n / v) * v * p) / p;
666 };
667 }
668
669 function minMax(value, min, max) {
670 return Math.max(Math.min(value, max), min);
671 }
672
673 var AnimationManager =
674 /*#__PURE__*/
675 function () {
676 function AnimationManager(_a) {
677 var options = _a.options,
678 itm = _a.itm,
679 em = _a.em,
680 axm = _a.axm;
681 this.options = options;
682 this.itm = itm;
683 this.em = em;
684 this.axm = axm;
685 this.animationEnd = this.animationEnd.bind(this);
686 }
687
688 var __proto = AnimationManager.prototype;
689
690 __proto.getDuration = function (depaPos, destPos, wishDuration) {
691 var _this = this;
692
693 var duration;
694
695 if (typeof wishDuration !== "undefined") {
696 duration = wishDuration;
697 } else {
698 var durations_1 = map(destPos, function (v, k) {
699 return getDuration(Math.abs(v - depaPos[k]), _this.options.deceleration);
700 });
701 duration = Object.keys(durations_1).reduce(function (max, v) {
702 return Math.max(max, durations_1[v]);
703 }, -Infinity);
704 }
705
706 return minMax(duration, this.options.minimumDuration, this.options.maximumDuration);
707 };
708
709 __proto.createAnimationParam = function (pos, duration, option) {
710 var depaPos = this.axm.get();
711 var destPos = pos;
712 var inputEvent = option && option.event || null;
713 return {
714 depaPos: depaPos,
715 destPos: destPos,
716 duration: minMax(duration, this.options.minimumDuration, this.options.maximumDuration),
717 delta: this.axm.getDelta(depaPos, destPos),
718 inputEvent: inputEvent,
719 input: option && option.input || null,
720 isTrusted: !!inputEvent,
721 done: this.animationEnd
722 };
723 };
724
725 __proto.grab = function (axes, option) {
726 if (this._animateParam && axes.length) {
727 var orgPos_1 = this.axm.get(axes);
728 var pos = this.axm.map(orgPos_1, function (v, opt) {
729 return getCirculatedPos(v, opt.range, opt.circular);
730 });
731
732 if (!every(pos, function (v, k) {
733 return orgPos_1[k] === v;
734 })) {
735 this.em.triggerChange(pos, false, orgPos_1, option, !!option);
736 }
737
738 this._animateParam = null;
739 this._raf && cancelAnimationFrame(this._raf);
740 this._raf = null;
741 this.em.triggerAnimationEnd(!!(option && option.event));
742 }
743 };
744
745 __proto.getEventInfo = function () {
746 if (this._animateParam && this._animateParam.input && this._animateParam.inputEvent) {
747 return {
748 input: this._animateParam.input,
749 event: this._animateParam.inputEvent
750 };
751 } else {
752 return null;
753 }
754 };
755
756 __proto.restore = function (option) {
757 var pos = this.axm.get();
758 var destPos = this.axm.map(pos, function (v, opt) {
759 return Math.min(opt.range[1], Math.max(opt.range[0], v));
760 });
761 this.animateTo(destPos, this.getDuration(pos, destPos), option);
762 };
763
764 __proto.animationEnd = function () {
765 var beforeParam = this.getEventInfo();
766 this._animateParam = null; // for Circular
767
768 var circularTargets = this.axm.filter(this.axm.get(), function (v, opt) {
769 return isCircularable(v, opt.range, opt.circular);
770 });
771 Object.keys(circularTargets).length > 0 && this.setTo(this.axm.map(circularTargets, function (v, opt) {
772 return getCirculatedPos(v, opt.range, opt.circular);
773 }));
774 this.itm.setInterrupt(false);
775 this.em.triggerAnimationEnd(!!beforeParam);
776
777 if (this.axm.isOutside()) {
778 this.restore(beforeParam);
779 } else {
780 this.finish(!!beforeParam);
781 }
782 };
783
784 __proto.finish = function (isTrusted) {
785 this._animateParam = null;
786 this.itm.setInterrupt(false);
787 this.em.triggerFinish(isTrusted);
788 };
789
790 __proto.animateLoop = function (param, complete) {
791 if (param.duration) {
792 this._animateParam = __assign({}, param);
793 var info_1 = this._animateParam;
794 var self_1 = this;
795 var destPos_1 = info_1.destPos;
796 var prevPos_1 = info_1.depaPos;
797 var prevEasingPer_1 = 0;
798 var directions_1 = map(prevPos_1, function (value, key) {
799 return value <= destPos_1[key] ? 1 : -1;
800 });
801 var originalIntendedPos_1 = map(destPos_1, function (v) {
802 return v;
803 });
804 var prevTime_1 = new Date().getTime();
805 info_1.startTime = prevTime_1;
806
807 (function loop() {
808 self_1._raf = null;
809 var currentTime = new Date().getTime();
810 var ratio = (currentTime - info_1.startTime) / param.duration;
811 var easingPer = self_1.easing(ratio);
812 var toPos = self_1.axm.map(prevPos_1, function (pos, options, key) {
813 var nextPos = ratio >= 1 ? destPos_1[key] : pos + info_1.delta[key] * (easingPer - prevEasingPer_1); // Subtract distance from distance already moved.
814 // Recalculate the remaining distance.
815 // Fix the bouncing phenomenon by changing the range.
816
817 var circulatedPos = getCirculatedPos(nextPos, options.range, options.circular);
818
819 if (nextPos !== circulatedPos) {
820 // circular
821 var rangeOffset = directions_1[key] * (options.range[1] - options.range[0]);
822 destPos_1[key] -= rangeOffset;
823 prevPos_1[key] -= rangeOffset;
824 }
825
826 return circulatedPos;
827 });
828 var isCanceled = !self_1.em.triggerChange(toPos, false, prevPos_1);
829 prevPos_1 = toPos;
830 prevTime_1 = currentTime;
831 prevEasingPer_1 = easingPer;
832
833 if (easingPer >= 1) {
834 destPos_1 = self_1.getFinalPos(destPos_1, originalIntendedPos_1);
835
836 if (!equal(destPos_1, self_1.axm.get(Object.keys(destPos_1)))) {
837 self_1.em.triggerChange(destPos_1, true, prevPos_1);
838 }
839
840 complete();
841 return;
842 } else if (isCanceled) {
843 self_1.finish(false);
844 } else {
845 // animationEnd
846 self_1._raf = requestAnimationFrame(loop);
847 }
848 })();
849 } else {
850 this.em.triggerChange(param.destPos, true);
851 complete();
852 }
853 };
854 /**
855 * Get estimated final value.
856 *
857 * If destPos is within the 'error range' of the original intended position, the initial intended position is returned.
858 * - eg. original intended pos: 100, destPos: 100.0000000004 ==> return 100;
859 * If dest Pos is outside the 'range of error' compared to the originally intended pos, it is returned rounded based on the originally intended pos.
860 * - eg. original intended pos: 100.123 destPos: 50.12345 => return 50.123
861 *
862 * @param originalIntendedPos
863 * @param destPos
864 */
865
866
867 __proto.getFinalPos = function (destPos, originalIntendedPos) {
868 var _this = this; // compare destPos and originalIntendedPos
869
870
871 var ERROR_LIMIT = 0.000001;
872 var finalPos = map(destPos, function (value, key) {
873 if (value >= originalIntendedPos[key] - ERROR_LIMIT && value <= originalIntendedPos[key] + ERROR_LIMIT) {
874 // In error range, return original intended
875 return originalIntendedPos[key];
876 } else {
877 // Out of error range, return rounded pos.
878 var roundUnit = _this.getRoundUnit(value, key);
879
880 var result = roundNumber(value, roundUnit);
881 return result;
882 }
883 });
884 return finalPos;
885 };
886
887 __proto.getRoundUnit = function (val, key) {
888 var roundUnit = this.options.round; // manual mode
889
890 var minRoundUnit = null; // auto mode
891 // auto mode
892
893 if (!roundUnit) {
894 // Get minimum round unit
895 var options = this.axm.getAxisOptions(key);
896 minRoundUnit = inversePow(Math.max(getDecimalPlace(options.range[0]), getDecimalPlace(options.range[1]), getDecimalPlace(val)));
897 }
898
899 return minRoundUnit || roundUnit;
900 };
901
902 __proto.getUserControll = function (param) {
903 var userWish = param.setTo();
904 userWish.destPos = this.axm.get(userWish.destPos);
905 userWish.duration = minMax(userWish.duration, this.options.minimumDuration, this.options.maximumDuration);
906 return userWish;
907 };
908
909 __proto.animateTo = function (destPos, duration, option) {
910 var _this = this;
911
912 var param = this.createAnimationParam(destPos, duration, option);
913
914 var depaPos = __assign({}, param.depaPos);
915
916 var retTrigger = this.em.triggerAnimationStart(param); // to control
917
918 var userWish = this.getUserControll(param); // You can't stop the 'animationStart' event when 'circular' is true.
919
920 if (!retTrigger && this.axm.every(userWish.destPos, function (v, opt) {
921 return isCircularable(v, opt.range, opt.circular);
922 })) {
923 console.warn("You can't stop the 'animation' event when 'circular' is true.");
924 }
925
926 if (retTrigger && !equal(userWish.destPos, depaPos)) {
927 var inputEvent = option && option.event || null;
928 this.animateLoop({
929 depaPos: depaPos,
930 destPos: userWish.destPos,
931 duration: userWish.duration,
932 delta: this.axm.getDelta(depaPos, userWish.destPos),
933 isTrusted: !!inputEvent,
934 inputEvent: inputEvent,
935 input: option && option.input || null
936 }, function () {
937 return _this.animationEnd();
938 });
939 }
940 };
941
942 __proto.easing = function (p) {
943 return p > 1 ? 1 : this.options.easing(p);
944 };
945
946 __proto.setTo = function (pos, duration) {
947 if (duration === void 0) {
948 duration = 0;
949 }
950
951 var axes = Object.keys(pos);
952 this.grab(axes);
953 var orgPos = this.axm.get(axes);
954
955 if (equal(pos, orgPos)) {
956 return this;
957 }
958
959 this.itm.setInterrupt(true);
960 var movedPos = filter(pos, function (v, k) {
961 return orgPos[k] !== v;
962 });
963
964 if (!Object.keys(movedPos).length) {
965 return this;
966 }
967
968 movedPos = this.axm.map(movedPos, function (v, opt) {
969 var range = opt.range,
970 circular = opt.circular;
971
972 if (circular && (circular[0] || circular[1])) {
973 return v;
974 } else {
975 return getInsidePosition(v, range, circular);
976 }
977 });
978
979 if (equal(movedPos, orgPos)) {
980 return this;
981 }
982
983 if (duration > 0) {
984 this.animateTo(movedPos, duration);
985 } else {
986 this.em.triggerChange(movedPos);
987 this.finish(false);
988 }
989
990 return this;
991 };
992
993 __proto.setBy = function (pos, duration) {
994 if (duration === void 0) {
995 duration = 0;
996 }
997
998 return this.setTo(map(this.axm.get(Object.keys(pos)), function (v, k) {
999 return v + pos[k];
1000 }), duration);
1001 };
1002
1003 return AnimationManager;
1004 }();
1005
1006 var EventManager =
1007 /*#__PURE__*/
1008 function () {
1009 function EventManager(axes) {
1010 this.axes = axes;
1011 }
1012 /**
1013 * This event is fired when a user holds an element on the screen of the device.
1014 * @ko 사용자가 기기의 화면에 손을 대고 있을 때 발생하는 이벤트
1015 * @name eg.Axes#hold
1016 * @event
1017 * @type {object}
1018 * @property {Object.<string, number>} pos coordinate <ko>좌표 정보</ko>
1019 * @property {Object} input The instance of inputType where the event occurred<ko>이벤트가 발생한 inputType 인스턴스</ko>
1020 * @property {Object} inputEvent The event object received from inputType <ko>inputType으로 부터 받은 이벤트 객체</ko>
1021 * @property {Boolean} isTrusted Returns true if an event was generated by the user action, or false if it was caused by a script or API call <ko>사용자의 액션에 의해 이벤트가 발생하였으면 true, 스크립트나 API호출에 의해 발생하였을 경우에는 false를 반환한다.</ko>
1022 *
1023 * @example
1024 * const axes = new eg.Axes({
1025 * "x": {
1026 * range: [0, 100]
1027 * },
1028 * "zoom": {
1029 * range: [50, 30]
1030 * }
1031 * }).on("hold", function(event) {
1032 * // event.pos
1033 * // event.input
1034 * // event.inputEvent
1035 * // isTrusted
1036 * });
1037 */
1038
1039
1040 var __proto = EventManager.prototype;
1041
1042 __proto.triggerHold = function (pos, option) {
1043 var roundPos = this.getRoundPos(pos).roundPos;
1044 this.axes.trigger("hold", {
1045 pos: roundPos,
1046 input: option.input || null,
1047 inputEvent: option.event || null,
1048 isTrusted: true
1049 });
1050 };
1051 /**
1052 * Specifies the coordinates to move after the 'change' event. It works when the holding value of the change event is true.
1053 * @ko 'change' 이벤트 이후 이동할 좌표를 지정한다. change이벤트의 holding 값이 true일 경우에 동작한다
1054 * @name set
1055 * @function
1056 * @param {Object.<string, number>} pos The coordinate to move to <ko>이동할 좌표</ko>
1057 * @example
1058 * const axes = new eg.Axes({
1059 * "x": {
1060 * range: [0, 100]
1061 * },
1062 * "zoom": {
1063 * range: [50, 30]
1064 * }
1065 * }).on("change", function(event) {
1066 * event.holding && event.set({x: 10});
1067 * });
1068 */
1069
1070 /** Specifies the animation coordinates to move after the 'release' or 'animationStart' events.
1071 * @ko 'release' 또는 'animationStart' 이벤트 이후 이동할 좌표를 지정한다.
1072 * @name setTo
1073 * @function
1074 * @param {Object.<string, number>} pos The coordinate to move to <ko>이동할 좌표</ko>
1075 * @param {Number} [duration] Duration of the animation (unit: ms) <ko>애니메이션 진행 시간(단위: ms)</ko>
1076 * @example
1077 * const axes = new eg.Axes({
1078 * "x": {
1079 * range: [0, 100]
1080 * },
1081 * "zoom": {
1082 * range: [50, 30]
1083 * }
1084 * }).on("animationStart", function(event) {
1085 * event.setTo({x: 10}, 2000);
1086 * });
1087 */
1088
1089 /**
1090 * This event is fired when a user release an element on the screen of the device.
1091 * @ko 사용자가 기기의 화면에서 손을 뗐을 때 발생하는 이벤트
1092 * @name eg.Axes#release
1093 * @event
1094 * @type {object}
1095 * @property {Object.<string, number>} depaPos The coordinates when releasing an element<ko>손을 뗐을 때의 좌표 </ko>
1096 * @property {Object.<string, number>} destPos The coordinates to move to after releasing an element<ko>손을 뗀 뒤에 이동할 좌표</ko>
1097 * @property {Object.<string, number>} delta The movement variation of coordinate <ko>좌표의 변화량</ko>
1098 * @property {Object} inputEvent The event object received from inputType <ko>inputType으로 부터 받은 이벤트 객체</ko>
1099 * @property {Object} input The instance of inputType where the event occurred<ko>이벤트가 발생한 inputType 인스턴스</ko>
1100 * @property {setTo} setTo Specifies the animation coordinates to move after the event <ko>이벤트 이후 이동할 애니메이션 좌표를 지정한다</ko>
1101 * @property {Boolean} isTrusted Returns true if an event was generated by the user action, or false if it was caused by a script or API call <ko>사용자의 액션에 의해 이벤트가 발생하였으면 true, 스크립트나 API호출에 의해 발생하였을 경우에는 false를 반환한다.</ko>
1102 *
1103 * @example
1104 * const axes = new eg.Axes({
1105 * "x": {
1106 * range: [0, 100]
1107 * },
1108 * "zoom": {
1109 * range: [50, 30]
1110 * }
1111 * }).on("release", function(event) {
1112 * // event.depaPos
1113 * // event.destPos
1114 * // event.delta
1115 * // event.input
1116 * // event.inputEvent
1117 * // event.setTo
1118 * // event.isTrusted
1119 *
1120 * // if you want to change the animation coordinates to move after the 'release' event.
1121 * event.setTo({x: 10}, 2000);
1122 * });
1123 */
1124
1125
1126 __proto.triggerRelease = function (param) {
1127 var _a = this.getRoundPos(param.destPos, param.depaPos),
1128 roundPos = _a.roundPos,
1129 roundDepa = _a.roundDepa;
1130
1131 param.destPos = roundPos;
1132 param.depaPos = roundDepa;
1133 param.setTo = this.createUserControll(param.destPos, param.duration);
1134 this.axes.trigger("release", param);
1135 };
1136 /**
1137 * This event is fired when coordinate changes.
1138 * @ko 좌표가 변경됐을 때 발생하는 이벤트
1139 * @name eg.Axes#change
1140 * @event
1141 * @type {object}
1142 * @property {Object.<string, number>} pos The coordinate <ko>좌표</ko>
1143 * @property {Object.<string, number>} delta The movement variation of coordinate <ko>좌표의 변화량</ko>
1144 * @property {Boolean} holding Indicates whether a user holds an element on the screen of the device.<ko>사용자가 기기의 화면을 누르고 있는지 여부</ko>
1145 * @property {Object} input The instance of inputType where the event occurred. If the value is changed by animation, it returns 'null'.<ko>이벤트가 발생한 inputType 인스턴스. 애니메이션에 의해 값이 변경될 경우에는 'null'을 반환한다.</ko>
1146 * @property {Object} inputEvent The event object received from inputType. If the value is changed by animation, it returns 'null'.<ko>inputType으로 부터 받은 이벤트 객체. 애니메이션에 의해 값이 변경될 경우에는 'null'을 반환한다.</ko>
1147 * @property {set} set Specifies the coordinates to move after the event. It works when the holding value is true <ko>이벤트 이후 이동할 좌표를 지정한다. holding 값이 true일 경우에 동작한다.</ko>
1148 * @property {Boolean} isTrusted Returns true if an event was generated by the user action, or false if it was caused by a script or API call <ko>사용자의 액션에 의해 이벤트가 발생하였으면 true, 스크립트나 API호출에 의해 발생하였을 경우에는 false를 반환한다.</ko>
1149 *
1150 * @example
1151 * const axes = new eg.Axes({
1152 * "x": {
1153 * range: [0, 100]
1154 * },
1155 * "zoom": {
1156 * range: [50, 30]
1157 * }
1158 * }).on("change", function(event) {
1159 * // event.pos
1160 * // event.delta
1161 * // event.input
1162 * // event.inputEvent
1163 * // event.holding
1164 * // event.set
1165 * // event.isTrusted
1166 *
1167 * // if you want to change the coordinates to move after the 'change' event.
1168 * // it works when the holding value of the change event is true.
1169 * event.holding && event.set({x: 10});
1170 * });
1171 */
1172
1173
1174 __proto.triggerChange = function (pos, isAccurate, depaPos, option, holding) {
1175 if (holding === void 0) {
1176 holding = false;
1177 }
1178
1179 var am = this.am;
1180 var axm = am.axm;
1181 var eventInfo = am.getEventInfo();
1182
1183 var _a = this.getRoundPos(pos, depaPos),
1184 roundPos = _a.roundPos,
1185 roundDepa = _a.roundDepa;
1186
1187 var moveTo = axm.moveTo(roundPos, roundDepa);
1188 var inputEvent = option && option.event || eventInfo && eventInfo.event || null;
1189 var param = {
1190 pos: moveTo.pos,
1191 delta: moveTo.delta,
1192 holding: holding,
1193 inputEvent: inputEvent,
1194 isTrusted: !!inputEvent,
1195 input: option && option.input || eventInfo && eventInfo.input || null,
1196 set: inputEvent ? this.createUserControll(moveTo.pos) : function () {}
1197 };
1198 var result = this.axes.trigger("change", param);
1199 inputEvent && axm.set(param.set()["destPos"]);
1200 return result;
1201 };
1202 /**
1203 * This event is fired when animation starts.
1204 * @ko 에니메이션이 시작할 때 발생한다.
1205 * @name eg.Axes#animationStart
1206 * @event
1207 * @type {object}
1208 * @property {Object.<string, number>} depaPos The coordinates when animation starts<ko>애니메이션이 시작 되었을 때의 좌표 </ko>
1209 * @property {Object.<string, number>} destPos The coordinates to move to. If you change this value, you can run the animation<ko>이동할 좌표. 이값을 변경하여 애니메이션을 동작시킬수 있다</ko>
1210 * @property {Object.<string, number>} delta The movement variation of coordinate <ko>좌표의 변화량</ko>
1211 * @property {Number} duration Duration of the animation (unit: ms). If you change this value, you can control the animation duration time.<ko>애니메이션 진행 시간(단위: ms). 이값을 변경하여 애니메이션의 이동시간을 조절할 수 있다.</ko>
1212 * @property {Object} input The instance of inputType where the event occurred. If the value is changed by animation, it returns 'null'.<ko>이벤트가 발생한 inputType 인스턴스. 애니메이션에 의해 값이 변경될 경우에는 'null'을 반환한다.</ko>
1213 * @property {Object} inputEvent The event object received from inputType <ko>inputType으로 부터 받은 이벤트 객체</ko>
1214 * @property {setTo} setTo Specifies the animation coordinates to move after the event <ko>이벤트 이후 이동할 애니메이션 좌표를 지정한다</ko>
1215 * @property {Boolean} isTrusted Returns true if an event was generated by the user action, or false if it was caused by a script or API call <ko>사용자의 액션에 의해 이벤트가 발생하였으면 true, 스크립트나 API호출에 의해 발생하였을 경우에는 false를 반환한다.</ko>
1216 *
1217 * @example
1218 * const axes = new eg.Axes({
1219 * "x": {
1220 * range: [0, 100]
1221 * },
1222 * "zoom": {
1223 * range: [50, 30]
1224 * }
1225 * }).on("release", function(event) {
1226 * // event.depaPos
1227 * // event.destPos
1228 * // event.delta
1229 * // event.input
1230 * // event.inputEvent
1231 * // event.setTo
1232 * // event.isTrusted
1233 *
1234 * // if you want to change the animation coordinates to move after the 'animationStart' event.
1235 * event.setTo({x: 10}, 2000);
1236 * });
1237 */
1238
1239
1240 __proto.triggerAnimationStart = function (param) {
1241 var _a = this.getRoundPos(param.destPos, param.depaPos),
1242 roundPos = _a.roundPos,
1243 roundDepa = _a.roundDepa;
1244
1245 param.destPos = roundPos;
1246 param.depaPos = roundDepa;
1247 param.setTo = this.createUserControll(param.destPos, param.duration);
1248 return this.axes.trigger("animationStart", param);
1249 };
1250 /**
1251 * This event is fired when animation ends.
1252 * @ko 에니메이션이 끝났을 때 발생한다.
1253 * @name eg.Axes#animationEnd
1254 * @event
1255 * @type {object}
1256 * @property {Boolean} isTrusted Returns true if an event was generated by the user action, or false if it was caused by a script or API call <ko>사용자의 액션에 의해 이벤트가 발생하였으면 true, 스크립트나 API호출에 의해 발생하였을 경우에는 false를 반환한다.</ko>
1257 *
1258 * @example
1259 * const axes = new eg.Axes({
1260 * "x": {
1261 * range: [0, 100]
1262 * },
1263 * "zoom": {
1264 * range: [50, 30]
1265 * }
1266 * }).on("animationEnd", function(event) {
1267 * // event.isTrusted
1268 * });
1269 */
1270
1271
1272 __proto.triggerAnimationEnd = function (isTrusted) {
1273 if (isTrusted === void 0) {
1274 isTrusted = false;
1275 }
1276
1277 this.axes.trigger("animationEnd", {
1278 isTrusted: isTrusted
1279 });
1280 };
1281 /**
1282 * This event is fired when all actions have been completed.
1283 * @ko 에니메이션이 끝났을 때 발생한다.
1284 * @name eg.Axes#finish
1285 * @event
1286 * @type {object}
1287 * @property {Boolean} isTrusted Returns true if an event was generated by the user action, or false if it was caused by a script or API call <ko>사용자의 액션에 의해 이벤트가 발생하였으면 true, 스크립트나 API호출에 의해 발생하였을 경우에는 false를 반환한다.</ko>
1288 *
1289 * @example
1290 * const axes = new eg.Axes({
1291 * "x": {
1292 * range: [0, 100]
1293 * },
1294 * "zoom": {
1295 * range: [50, 30]
1296 * }
1297 * }).on("finish", function(event) {
1298 * // event.isTrusted
1299 * });
1300 */
1301
1302
1303 __proto.triggerFinish = function (isTrusted) {
1304 if (isTrusted === void 0) {
1305 isTrusted = false;
1306 }
1307
1308 this.axes.trigger("finish", {
1309 isTrusted: isTrusted
1310 });
1311 };
1312
1313 __proto.createUserControll = function (pos, duration) {
1314 if (duration === void 0) {
1315 duration = 0;
1316 } // to controll
1317
1318
1319 var userControl = {
1320 destPos: __assign({}, pos),
1321 duration: duration
1322 };
1323 return function (toPos, userDuration) {
1324 toPos && (userControl.destPos = __assign({}, toPos));
1325 userDuration !== undefined && (userControl.duration = userDuration);
1326 return userControl;
1327 };
1328 };
1329
1330 __proto.setAnimationManager = function (am) {
1331 this.am = am;
1332 };
1333
1334 __proto.destroy = function () {
1335 this.axes.off();
1336 };
1337
1338 __proto.getRoundPos = function (pos, depaPos) {
1339 // round value if round exist
1340 var roundUnit = this.axes.options.round; // if (round == null) {
1341 // return {pos, depaPos}; // undefined, undefined
1342 // }
1343
1344 return {
1345 roundPos: roundNumbers(pos, roundUnit),
1346 roundDepa: roundNumbers(depaPos, roundUnit)
1347 };
1348 };
1349
1350 return EventManager;
1351 }();
1352
1353 var InterruptManager =
1354 /*#__PURE__*/
1355 function () {
1356 function InterruptManager(options) {
1357 this.options = options;
1358 this._prevented = false; // check whether the animation event was prevented
1359 }
1360
1361 var __proto = InterruptManager.prototype;
1362
1363 __proto.isInterrupting = function () {
1364 // when interruptable is 'true', return value is always 'true'.
1365 return this.options.interruptable || this._prevented;
1366 };
1367
1368 __proto.isInterrupted = function () {
1369 return !this.options.interruptable && this._prevented;
1370 };
1371
1372 __proto.setInterrupt = function (prevented) {
1373 !this.options.interruptable && (this._prevented = prevented);
1374 };
1375
1376 return InterruptManager;
1377 }();
1378
1379 var AxisManager =
1380 /*#__PURE__*/
1381 function () {
1382 function AxisManager(axis, options) {
1383 var _this = this;
1384
1385 this.axis = axis;
1386 this.options = options;
1387
1388 this._complementOptions();
1389
1390 this._pos = Object.keys(this.axis).reduce(function (acc, v) {
1391 acc[v] = _this.axis[v].range[0];
1392 return acc;
1393 }, {});
1394 }
1395 /**
1396 * set up 'css' expression
1397 * @private
1398 */
1399
1400
1401 var __proto = AxisManager.prototype;
1402
1403 __proto._complementOptions = function () {
1404 var _this = this;
1405
1406 Object.keys(this.axis).forEach(function (axis) {
1407 _this.axis[axis] = __assign({
1408 range: [0, 100],
1409 bounce: [0, 0],
1410 circular: [false, false]
1411 }, _this.axis[axis]);
1412 ["bounce", "circular"].forEach(function (v) {
1413 var axisOption = _this.axis;
1414 var key = axisOption[axis][v];
1415
1416 if (/string|number|boolean/.test(typeof key)) {
1417 axisOption[axis][v] = [key, key];
1418 }
1419 });
1420 });
1421 };
1422
1423 __proto.getDelta = function (depaPos, destPos) {
1424 var fullDepaPos = this.get(depaPos);
1425 return map(this.get(destPos), function (v, k) {
1426 return v - fullDepaPos[k];
1427 });
1428 };
1429
1430 __proto.get = function (axes) {
1431 var _this = this;
1432
1433 if (axes && Array.isArray(axes)) {
1434 return axes.reduce(function (acc, v) {
1435 if (v && v in _this._pos) {
1436 acc[v] = _this._pos[v];
1437 }
1438
1439 return acc;
1440 }, {});
1441 } else {
1442 return __assign(__assign({}, this._pos), axes || {});
1443 }
1444 };
1445
1446 __proto.moveTo = function (pos, depaPos) {
1447 if (depaPos === void 0) {
1448 depaPos = this._pos;
1449 }
1450
1451 var delta = map(this._pos, function (v, key) {
1452 return key in pos && key in depaPos ? pos[key] - depaPos[key] : 0;
1453 });
1454 this.set(this.map(pos, function (v, opt) {
1455 return opt ? getCirculatedPos(v, opt.range, opt.circular) : 0;
1456 }));
1457 return {
1458 pos: __assign({}, this._pos),
1459 delta: delta
1460 };
1461 };
1462
1463 __proto.set = function (pos) {
1464 for (var k in pos) {
1465 if (k && k in this._pos) {
1466 this._pos[k] = pos[k];
1467 }
1468 }
1469 };
1470
1471 __proto.every = function (pos, callback) {
1472 var axisOptions = this.axis;
1473 return every(pos, function (value, key) {
1474 return callback(value, axisOptions[key], key);
1475 });
1476 };
1477
1478 __proto.filter = function (pos, callback) {
1479 var axisOptions = this.axis;
1480 return filter(pos, function (value, key) {
1481 return callback(value, axisOptions[key], key);
1482 });
1483 };
1484
1485 __proto.map = function (pos, callback) {
1486 var axisOptions = this.axis;
1487 return map(pos, function (value, key) {
1488 return callback(value, axisOptions[key], key);
1489 });
1490 };
1491
1492 __proto.isOutside = function (axes) {
1493 return !this.every(axes ? this.get(axes) : this._pos, function (v, opt) {
1494 return !isOutside(v, opt.range);
1495 });
1496 };
1497
1498 __proto.getAxisOptions = function (key) {
1499 return this.axis[key];
1500 };
1501
1502 return AxisManager;
1503 }();
1504
1505 var InputObserver =
1506 /*#__PURE__*/
1507 function () {
1508 function InputObserver(_a) {
1509 var options = _a.options,
1510 itm = _a.itm,
1511 em = _a.em,
1512 axm = _a.axm,
1513 am = _a.am;
1514 this.isOutside = false;
1515 this.moveDistance = null;
1516 this.isStopped = false;
1517 this.options = options;
1518 this.itm = itm;
1519 this.em = em;
1520 this.axm = axm;
1521 this.am = am;
1522 } // when move pointer is held in outside
1523
1524
1525 var __proto = InputObserver.prototype;
1526
1527 __proto.atOutside = function (pos) {
1528 var _this = this;
1529
1530 if (this.isOutside) {
1531 return this.axm.map(pos, function (v, opt) {
1532 var tn = opt.range[0] - opt.bounce[0];
1533 var tx = opt.range[1] + opt.bounce[1];
1534 return v > tx ? tx : v < tn ? tn : v;
1535 });
1536 } else {
1537 // when start pointer is held in inside
1538 // get a initialization slope value to prevent smooth animation.
1539 var initSlope_1 = this.am.easing(0.00001) / 0.00001;
1540 return this.axm.map(pos, function (v, opt) {
1541 var min = opt.range[0];
1542 var max = opt.range[1];
1543 var out = opt.bounce;
1544 var circular = opt.circular;
1545
1546 if (circular && (circular[0] || circular[1])) {
1547 return v;
1548 } else if (v < min) {
1549 // left
1550 return min - _this.am.easing((min - v) / (out[0] * initSlope_1)) * out[0];
1551 } else if (v > max) {
1552 // right
1553 return max + _this.am.easing((v - max) / (out[1] * initSlope_1)) * out[1];
1554 }
1555
1556 return v;
1557 });
1558 }
1559 };
1560
1561 __proto.get = function (input) {
1562 return this.axm.get(input.axes);
1563 };
1564
1565 __proto.hold = function (input, event) {
1566 if (this.itm.isInterrupted() || !input.axes.length) {
1567 return;
1568 }
1569
1570 var changeOption = {
1571 input: input,
1572 event: event
1573 };
1574 this.isStopped = false;
1575 this.itm.setInterrupt(true);
1576 this.am.grab(input.axes, changeOption);
1577 !this.moveDistance && this.em.triggerHold(this.axm.get(), changeOption);
1578 this.isOutside = this.axm.isOutside(input.axes);
1579 this.moveDistance = this.axm.get(input.axes);
1580 };
1581
1582 __proto.change = function (input, event, offset) {
1583 if (this.isStopped || !this.itm.isInterrupting() || this.axm.every(offset, function (v) {
1584 return v === 0;
1585 })) {
1586 return;
1587 }
1588
1589 var depaPos = this.moveDistance || this.axm.get(input.axes);
1590 var destPos; // for outside logic
1591
1592 destPos = map(depaPos, function (v, k) {
1593 return v + (offset[k] || 0);
1594 });
1595 this.moveDistance && (this.moveDistance = destPos); // from outside to inside
1596
1597 if (this.isOutside && this.axm.every(depaPos, function (v, opt) {
1598 return !isOutside(v, opt.range);
1599 })) {
1600 this.isOutside = false;
1601 }
1602
1603 depaPos = this.atOutside(depaPos);
1604 destPos = this.atOutside(destPos);
1605 var isCanceled = !this.em.triggerChange(destPos, false, depaPos, {
1606 input: input,
1607 event: event
1608 }, true);
1609
1610 if (isCanceled) {
1611 this.isStopped = true;
1612 this.moveDistance = null;
1613 this.am.finish(false);
1614 }
1615 };
1616
1617 __proto.release = function (input, event, offset, inputDuration) {
1618 if (this.isStopped || !this.itm.isInterrupting() || !this.moveDistance) {
1619 return;
1620 }
1621
1622 var pos = this.axm.get(input.axes);
1623 var depaPos = this.axm.get();
1624 var destPos = this.axm.get(this.axm.map(offset, function (v, opt, k) {
1625 if (opt.circular && (opt.circular[0] || opt.circular[1])) {
1626 return pos[k] + v;
1627 } else {
1628 return getInsidePosition(pos[k] + v, opt.range, opt.circular, opt.bounce);
1629 }
1630 }));
1631 var duration = this.am.getDuration(destPos, pos, inputDuration);
1632
1633 if (duration === 0) {
1634 destPos = __assign({}, depaPos);
1635 } // prepare params
1636
1637
1638 var param = {
1639 depaPos: depaPos,
1640 destPos: destPos,
1641 duration: duration,
1642 delta: this.axm.getDelta(depaPos, destPos),
1643 inputEvent: event,
1644 input: input,
1645 isTrusted: true
1646 };
1647 this.em.triggerRelease(param);
1648 this.moveDistance = null; // to contol
1649
1650 var userWish = this.am.getUserControll(param);
1651 var isEqual = equal(userWish.destPos, depaPos);
1652 var changeOption = {
1653 input: input,
1654 event: event
1655 };
1656
1657 if (isEqual || userWish.duration === 0) {
1658 !isEqual && this.em.triggerChange(userWish.destPos, false, depaPos, changeOption, true);
1659 this.itm.setInterrupt(false);
1660
1661 if (this.axm.isOutside()) {
1662 this.am.restore(changeOption);
1663 } else {
1664 this.em.triggerFinish(true);
1665 }
1666 } else {
1667 this.am.animateTo(userWish.destPos, userWish.duration, changeOption);
1668 }
1669 };
1670
1671 return InputObserver;
1672 }();
1673
1674 /*! Hammer.JS - v2.0.17-rc - 2019-12-16
1675 * http://naver.github.io/egjs
1676 *
1677 * Forked By Naver egjs
1678 * Copyright (c) hammerjs
1679 * Licensed under the MIT license */
1680 function _extends() {
1681 _extends = Object.assign || function (target) {
1682 for (var i = 1; i < arguments.length; i++) {
1683 var source = arguments[i];
1684
1685 for (var key in source) {
1686 if (Object.prototype.hasOwnProperty.call(source, key)) {
1687 target[key] = source[key];
1688 }
1689 }
1690 }
1691
1692 return target;
1693 };
1694
1695 return _extends.apply(this, arguments);
1696 }
1697
1698 function _inheritsLoose(subClass, superClass) {
1699 subClass.prototype = Object.create(superClass.prototype);
1700 subClass.prototype.constructor = subClass;
1701 subClass.__proto__ = superClass;
1702 }
1703
1704 function _assertThisInitialized(self) {
1705 if (self === void 0) {
1706 throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
1707 }
1708
1709 return self;
1710 }
1711
1712 /**
1713 * @private
1714 * extend object.
1715 * means that properties in dest will be overwritten by the ones in src.
1716 * @param {Object} target
1717 * @param {...Object} objects_to_assign
1718 * @returns {Object} target
1719 */
1720 var assign;
1721
1722 if (typeof Object.assign !== 'function') {
1723 assign = function assign(target) {
1724 if (target === undefined || target === null) {
1725 throw new TypeError('Cannot convert undefined or null to object');
1726 }
1727
1728 var output = Object(target);
1729
1730 for (var index = 1; index < arguments.length; index++) {
1731 var source = arguments[index];
1732
1733 if (source !== undefined && source !== null) {
1734 for (var nextKey in source) {
1735 if (source.hasOwnProperty(nextKey)) {
1736 output[nextKey] = source[nextKey];
1737 }
1738 }
1739 }
1740 }
1741
1742 return output;
1743 };
1744 } else {
1745 assign = Object.assign;
1746 }
1747
1748 var assign$1 = assign;
1749
1750 var VENDOR_PREFIXES = ['', 'webkit', 'Moz', 'MS', 'ms', 'o'];
1751 var TEST_ELEMENT = typeof document === "undefined" ? {
1752 style: {}
1753 } : document.createElement('div');
1754 var TYPE_FUNCTION = 'function';
1755 var round = Math.round,
1756 abs = Math.abs;
1757 var now = Date.now;
1758
1759 /**
1760 * @private
1761 * get the prefixed property
1762 * @param {Object} obj
1763 * @param {String} property
1764 * @returns {String|Undefined} prefixed
1765 */
1766
1767 function prefixed(obj, property) {
1768 var prefix;
1769 var prop;
1770 var camelProp = property[0].toUpperCase() + property.slice(1);
1771 var i = 0;
1772
1773 while (i < VENDOR_PREFIXES.length) {
1774 prefix = VENDOR_PREFIXES[i];
1775 prop = prefix ? prefix + camelProp : property;
1776
1777 if (prop in obj) {
1778 return prop;
1779 }
1780
1781 i++;
1782 }
1783
1784 return undefined;
1785 }
1786
1787 /* eslint-disable no-new-func, no-nested-ternary */
1788 var win$1;
1789
1790 if (typeof window === "undefined") {
1791 // window is undefined in node.js
1792 win$1 = {};
1793 } else {
1794 win$1 = window;
1795 }
1796
1797 var PREFIXED_TOUCH_ACTION = prefixed(TEST_ELEMENT.style, 'touchAction');
1798 var NATIVE_TOUCH_ACTION = PREFIXED_TOUCH_ACTION !== undefined;
1799 function getTouchActionProps() {
1800 if (!NATIVE_TOUCH_ACTION) {
1801 return false;
1802 }
1803
1804 var touchMap = {};
1805 var cssSupports = win$1.CSS && win$1.CSS.supports;
1806 ['auto', 'manipulation', 'pan-y', 'pan-x', 'pan-x pan-y', 'none'].forEach(function (val) {
1807 // If css.supports is not supported but there is native touch-action assume it supports
1808 // all values. This is the case for IE 10 and 11.
1809 return touchMap[val] = cssSupports ? win$1.CSS.supports('touch-action', val) : true;
1810 });
1811 return touchMap;
1812 }
1813
1814 var TOUCH_ACTION_COMPUTE = 'compute';
1815 var TOUCH_ACTION_AUTO = 'auto';
1816 var TOUCH_ACTION_MANIPULATION = 'manipulation'; // not implemented
1817
1818 var TOUCH_ACTION_NONE = 'none';
1819 var TOUCH_ACTION_PAN_X = 'pan-x';
1820 var TOUCH_ACTION_PAN_Y = 'pan-y';
1821 var TOUCH_ACTION_MAP = getTouchActionProps();
1822
1823 var MOBILE_REGEX = /mobile|tablet|ip(ad|hone|od)|android/i;
1824 var SUPPORT_TOUCH = 'ontouchstart' in win$1;
1825 var SUPPORT_POINTER_EVENTS = prefixed(win$1, 'PointerEvent') !== undefined;
1826 var SUPPORT_ONLY_TOUCH = SUPPORT_TOUCH && MOBILE_REGEX.test(navigator.userAgent);
1827 var INPUT_TYPE_TOUCH = 'touch';
1828 var INPUT_TYPE_PEN = 'pen';
1829 var INPUT_TYPE_MOUSE = 'mouse';
1830 var INPUT_TYPE_KINECT = 'kinect';
1831 var COMPUTE_INTERVAL = 25;
1832 var INPUT_START = 1;
1833 var INPUT_MOVE = 2;
1834 var INPUT_END = 4;
1835 var INPUT_CANCEL = 8;
1836 var DIRECTION_NONE = 1;
1837 var DIRECTION_LEFT = 2;
1838 var DIRECTION_RIGHT = 4;
1839 var DIRECTION_UP = 8;
1840 var DIRECTION_DOWN = 16;
1841 var DIRECTION_HORIZONTAL = DIRECTION_LEFT | DIRECTION_RIGHT;
1842 var DIRECTION_VERTICAL = DIRECTION_UP | DIRECTION_DOWN;
1843 var DIRECTION_ALL = DIRECTION_HORIZONTAL | DIRECTION_VERTICAL;
1844 var PROPS_XY = ['x', 'y'];
1845 var PROPS_CLIENT_XY = ['clientX', 'clientY'];
1846
1847 /**
1848 * @private
1849 * walk objects and arrays
1850 * @param {Object} obj
1851 * @param {Function} iterator
1852 * @param {Object} context
1853 */
1854 function each(obj, iterator, context) {
1855 var i;
1856
1857 if (!obj) {
1858 return;
1859 }
1860
1861 if (obj.forEach) {
1862 obj.forEach(iterator, context);
1863 } else if (obj.length !== undefined) {
1864 i = 0;
1865
1866 while (i < obj.length) {
1867 iterator.call(context, obj[i], i, obj);
1868 i++;
1869 }
1870 } else {
1871 for (i in obj) {
1872 obj.hasOwnProperty(i) && iterator.call(context, obj[i], i, obj);
1873 }
1874 }
1875 }
1876
1877 /**
1878 * @private
1879 * let a boolean value also be a function that must return a boolean
1880 * this first item in args will be used as the context
1881 * @param {Boolean|Function} val
1882 * @param {Array} [args]
1883 * @returns {Boolean}
1884 */
1885
1886 function boolOrFn(val, args) {
1887 if (typeof val === TYPE_FUNCTION) {
1888 return val.apply(args ? args[0] || undefined : undefined, args);
1889 }
1890
1891 return val;
1892 }
1893
1894 /**
1895 * @private
1896 * small indexOf wrapper
1897 * @param {String} str
1898 * @param {String} find
1899 * @returns {Boolean} found
1900 */
1901 function inStr(str, find) {
1902 return str.indexOf(find) > -1;
1903 }
1904
1905 /**
1906 * @private
1907 * when the touchActions are collected they are not a valid value, so we need to clean things up. *
1908 * @param {String} actions
1909 * @returns {*}
1910 */
1911
1912 function cleanTouchActions(actions) {
1913 // none
1914 if (inStr(actions, TOUCH_ACTION_NONE)) {
1915 return TOUCH_ACTION_NONE;
1916 }
1917
1918 var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X);
1919 var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y); // if both pan-x and pan-y are set (different recognizers
1920 // for different directions, e.g. horizontal pan but vertical swipe?)
1921 // we need none (as otherwise with pan-x pan-y combined none of these
1922 // recognizers will work, since the browser would handle all panning
1923
1924 if (hasPanX && hasPanY) {
1925 return TOUCH_ACTION_NONE;
1926 } // pan-x OR pan-y
1927
1928
1929 if (hasPanX || hasPanY) {
1930 return hasPanX ? TOUCH_ACTION_PAN_X : TOUCH_ACTION_PAN_Y;
1931 } // manipulation
1932
1933
1934 if (inStr(actions, TOUCH_ACTION_MANIPULATION)) {
1935 return TOUCH_ACTION_MANIPULATION;
1936 }
1937
1938 return TOUCH_ACTION_AUTO;
1939 }
1940
1941 /**
1942 * @private
1943 * Touch Action
1944 * sets the touchAction property or uses the js alternative
1945 * @param {Manager} manager
1946 * @param {String} value
1947 * @constructor
1948 */
1949
1950 var TouchAction =
1951 /*#__PURE__*/
1952 function () {
1953 function TouchAction(manager, value) {
1954 this.manager = manager;
1955 this.set(value);
1956 }
1957 /**
1958 * @private
1959 * set the touchAction value on the element or enable the polyfill
1960 * @param {String} value
1961 */
1962
1963
1964 var _proto = TouchAction.prototype;
1965
1966 _proto.set = function set(value) {
1967 // find out the touch-action by the event handlers
1968 if (value === TOUCH_ACTION_COMPUTE) {
1969 value = this.compute();
1970 }
1971
1972 if (NATIVE_TOUCH_ACTION && this.manager.element.style && TOUCH_ACTION_MAP[value]) {
1973 this.manager.element.style[PREFIXED_TOUCH_ACTION] = value;
1974 }
1975
1976 this.actions = value.toLowerCase().trim();
1977 };
1978 /**
1979 * @private
1980 * just re-set the touchAction value
1981 */
1982
1983
1984 _proto.update = function update() {
1985 this.set(this.manager.options.touchAction);
1986 };
1987 /**
1988 * @private
1989 * compute the value for the touchAction property based on the recognizer's settings
1990 * @returns {String} value
1991 */
1992
1993
1994 _proto.compute = function compute() {
1995 var actions = [];
1996 each(this.manager.recognizers, function (recognizer) {
1997 if (boolOrFn(recognizer.options.enable, [recognizer])) {
1998 actions = actions.concat(recognizer.getTouchAction());
1999 }
2000 });
2001 return cleanTouchActions(actions.join(' '));
2002 };
2003 /**
2004 * @private
2005 * this method is called on each input cycle and provides the preventing of the browser behavior
2006 * @param {Object} input
2007 */
2008
2009
2010 _proto.preventDefaults = function preventDefaults(input) {
2011 var srcEvent = input.srcEvent;
2012 var direction = input.offsetDirection; // if the touch action did prevented once this session
2013
2014 if (this.manager.session.prevented) {
2015 srcEvent.preventDefault();
2016 return;
2017 }
2018
2019 var actions = this.actions;
2020 var hasNone = inStr(actions, TOUCH_ACTION_NONE) && !TOUCH_ACTION_MAP[TOUCH_ACTION_NONE];
2021 var hasPanY = inStr(actions, TOUCH_ACTION_PAN_Y) && !TOUCH_ACTION_MAP[TOUCH_ACTION_PAN_Y];
2022 var hasPanX = inStr(actions, TOUCH_ACTION_PAN_X) && !TOUCH_ACTION_MAP[TOUCH_ACTION_PAN_X];
2023
2024 if (hasNone) {
2025 // do not prevent defaults if this is a tap gesture
2026 var isTapPointer = input.pointers.length === 1;
2027 var isTapMovement = input.distance < 2;
2028 var isTapTouchTime = input.deltaTime < 250;
2029
2030 if (isTapPointer && isTapMovement && isTapTouchTime) {
2031 return;
2032 }
2033 }
2034
2035 if (hasPanX && hasPanY) {
2036 // `pan-x pan-y` means browser handles all scrolling/panning, do not prevent
2037 return;
2038 }
2039
2040 if (hasNone || hasPanY && direction & DIRECTION_HORIZONTAL || hasPanX && direction & DIRECTION_VERTICAL) {
2041 return this.preventSrc(srcEvent);
2042 }
2043 };
2044 /**
2045 * @private
2046 * call preventDefault to prevent the browser's default behavior (scrolling in most cases)
2047 * @param {Object} srcEvent
2048 */
2049
2050
2051 _proto.preventSrc = function preventSrc(srcEvent) {
2052 this.manager.session.prevented = true;
2053 srcEvent.preventDefault();
2054 };
2055
2056 return TouchAction;
2057 }();
2058
2059 /**
2060 * @private
2061 * find if a node is in the given parent
2062 * @method hasParent
2063 * @param {HTMLElement} node
2064 * @param {HTMLElement} parent
2065 * @return {Boolean} found
2066 */
2067 function hasParent(node, parent) {
2068 while (node) {
2069 if (node === parent) {
2070 return true;
2071 }
2072
2073 node = node.parentNode;
2074 }
2075
2076 return false;
2077 }
2078
2079 /**
2080 * @private
2081 * get the center of all the pointers
2082 * @param {Array} pointers
2083 * @return {Object} center contains `x` and `y` properties
2084 */
2085
2086 function getCenter(pointers) {
2087 var pointersLength = pointers.length; // no need to loop when only one touch
2088
2089 if (pointersLength === 1) {
2090 return {
2091 x: round(pointers[0].clientX),
2092 y: round(pointers[0].clientY)
2093 };
2094 }
2095
2096 var x = 0;
2097 var y = 0;
2098 var i = 0;
2099
2100 while (i < pointersLength) {
2101 x += pointers[i].clientX;
2102 y += pointers[i].clientY;
2103 i++;
2104 }
2105
2106 return {
2107 x: round(x / pointersLength),
2108 y: round(y / pointersLength)
2109 };
2110 }
2111
2112 /**
2113 * @private
2114 * create a simple clone from the input used for storage of firstInput and firstMultiple
2115 * @param {Object} input
2116 * @returns {Object} clonedInputData
2117 */
2118
2119 function simpleCloneInputData(input) {
2120 // make a simple copy of the pointers because we will get a reference if we don't
2121 // we only need clientXY for the calculations
2122 var pointers = [];
2123 var i = 0;
2124
2125 while (i < input.pointers.length) {
2126 pointers[i] = {
2127 clientX: round(input.pointers[i].clientX),
2128 clientY: round(input.pointers[i].clientY)
2129 };
2130 i++;
2131 }
2132
2133 return {
2134 timeStamp: now(),
2135 pointers: pointers,
2136 center: getCenter(pointers),
2137 deltaX: input.deltaX,
2138 deltaY: input.deltaY
2139 };
2140 }
2141
2142 /**
2143 * @private
2144 * calculate the absolute distance between two points
2145 * @param {Object} p1 {x, y}
2146 * @param {Object} p2 {x, y}
2147 * @param {Array} [props] containing x and y keys
2148 * @return {Number} distance
2149 */
2150
2151 function getDistance(p1, p2, props) {
2152 if (!props) {
2153 props = PROPS_XY;
2154 }
2155
2156 var x = p2[props[0]] - p1[props[0]];
2157 var y = p2[props[1]] - p1[props[1]];
2158 return Math.sqrt(x * x + y * y);
2159 }
2160
2161 /**
2162 * @private
2163 * calculate the angle between two coordinates
2164 * @param {Object} p1
2165 * @param {Object} p2
2166 * @param {Array} [props] containing x and y keys
2167 * @return {Number} angle
2168 */
2169
2170 function getAngle(p1, p2, props) {
2171 if (!props) {
2172 props = PROPS_XY;
2173 }
2174
2175 var x = p2[props[0]] - p1[props[0]];
2176 var y = p2[props[1]] - p1[props[1]];
2177 return Math.atan2(y, x) * 180 / Math.PI;
2178 }
2179
2180 /**
2181 * @private
2182 * get the direction between two points
2183 * @param {Number} x
2184 * @param {Number} y
2185 * @return {Number} direction
2186 */
2187
2188 function getDirection(x, y) {
2189 if (x === y) {
2190 return DIRECTION_NONE;
2191 }
2192
2193 if (abs(x) >= abs(y)) {
2194 return x < 0 ? DIRECTION_LEFT : DIRECTION_RIGHT;
2195 }
2196
2197 return y < 0 ? DIRECTION_UP : DIRECTION_DOWN;
2198 }
2199
2200 function computeDeltaXY(session, input) {
2201 var center = input.center; // let { offsetDelta:offset = {}, prevDelta = {}, prevInput = {} } = session;
2202 // jscs throwing error on defalut destructured values and without defaults tests fail
2203
2204 var offset = session.offsetDelta || {};
2205 var prevDelta = session.prevDelta || {};
2206 var prevInput = session.prevInput || {};
2207
2208 if (input.eventType === INPUT_START || prevInput.eventType === INPUT_END) {
2209 prevDelta = session.prevDelta = {
2210 x: prevInput.deltaX || 0,
2211 y: prevInput.deltaY || 0
2212 };
2213 offset = session.offsetDelta = {
2214 x: center.x,
2215 y: center.y
2216 };
2217 }
2218
2219 input.deltaX = prevDelta.x + (center.x - offset.x);
2220 input.deltaY = prevDelta.y + (center.y - offset.y);
2221 }
2222
2223 /**
2224 * @private
2225 * calculate the velocity between two points. unit is in px per ms.
2226 * @param {Number} deltaTime
2227 * @param {Number} x
2228 * @param {Number} y
2229 * @return {Object} velocity `x` and `y`
2230 */
2231 function getVelocity(deltaTime, x, y) {
2232 return {
2233 x: x / deltaTime || 0,
2234 y: y / deltaTime || 0
2235 };
2236 }
2237
2238 /**
2239 * @private
2240 * calculate the scale factor between two pointersets
2241 * no scale is 1, and goes down to 0 when pinched together, and bigger when pinched out
2242 * @param {Array} start array of pointers
2243 * @param {Array} end array of pointers
2244 * @return {Number} scale
2245 */
2246
2247 function getScale(start, end) {
2248 return getDistance(end[0], end[1], PROPS_CLIENT_XY) / getDistance(start[0], start[1], PROPS_CLIENT_XY);
2249 }
2250
2251 /**
2252 * @private
2253 * calculate the rotation degrees between two pointersets
2254 * @param {Array} start array of pointers
2255 * @param {Array} end array of pointers
2256 * @return {Number} rotation
2257 */
2258
2259 function getRotation(start, end) {
2260 return getAngle(end[1], end[0], PROPS_CLIENT_XY) + getAngle(start[1], start[0], PROPS_CLIENT_XY);
2261 }
2262
2263 /**
2264 * @private
2265 * velocity is calculated every x ms
2266 * @param {Object} session
2267 * @param {Object} input
2268 */
2269
2270 function computeIntervalInputData(session, input) {
2271 var last = session.lastInterval || input;
2272 var deltaTime = input.timeStamp - last.timeStamp;
2273 var velocity;
2274 var velocityX;
2275 var velocityY;
2276 var direction;
2277
2278 if (input.eventType !== INPUT_CANCEL && (deltaTime > COMPUTE_INTERVAL || last.velocity === undefined)) {
2279 var deltaX = input.deltaX - last.deltaX;
2280 var deltaY = input.deltaY - last.deltaY;
2281 var v = getVelocity(deltaTime, deltaX, deltaY);
2282 velocityX = v.x;
2283 velocityY = v.y;
2284 velocity = abs(v.x) > abs(v.y) ? v.x : v.y;
2285 direction = getDirection(deltaX, deltaY);
2286 session.lastInterval = input;
2287 } else {
2288 // use latest velocity info if it doesn't overtake a minimum period
2289 velocity = last.velocity;
2290 velocityX = last.velocityX;
2291 velocityY = last.velocityY;
2292 direction = last.direction;
2293 }
2294
2295 input.velocity = velocity;
2296 input.velocityX = velocityX;
2297 input.velocityY = velocityY;
2298 input.direction = direction;
2299 }
2300
2301 /**
2302 * @private
2303 * extend the data with some usable properties like scale, rotate, velocity etc
2304 * @param {Object} manager
2305 * @param {Object} input
2306 */
2307
2308 function computeInputData(manager, input) {
2309 var session = manager.session;
2310 var pointers = input.pointers;
2311 var pointersLength = pointers.length; // store the first input to calculate the distance and direction
2312
2313 if (!session.firstInput) {
2314 session.firstInput = simpleCloneInputData(input);
2315 } // to compute scale and rotation we need to store the multiple touches
2316
2317
2318 if (pointersLength > 1 && !session.firstMultiple) {
2319 session.firstMultiple = simpleCloneInputData(input);
2320 } else if (pointersLength === 1) {
2321 session.firstMultiple = false;
2322 }
2323
2324 var firstInput = session.firstInput,
2325 firstMultiple = session.firstMultiple;
2326 var offsetCenter = firstMultiple ? firstMultiple.center : firstInput.center;
2327 var center = input.center = getCenter(pointers);
2328 input.timeStamp = now();
2329 input.deltaTime = input.timeStamp - firstInput.timeStamp;
2330 input.angle = getAngle(offsetCenter, center);
2331 input.distance = getDistance(offsetCenter, center);
2332 computeDeltaXY(session, input);
2333 input.offsetDirection = getDirection(input.deltaX, input.deltaY);
2334 var overallVelocity = getVelocity(input.deltaTime, input.deltaX, input.deltaY);
2335 input.overallVelocityX = overallVelocity.x;
2336 input.overallVelocityY = overallVelocity.y;
2337 input.overallVelocity = abs(overallVelocity.x) > abs(overallVelocity.y) ? overallVelocity.x : overallVelocity.y;
2338 input.scale = firstMultiple ? getScale(firstMultiple.pointers, pointers) : 1;
2339 input.rotation = firstMultiple ? getRotation(firstMultiple.pointers, pointers) : 0;
2340 input.maxPointers = !session.prevInput ? input.pointers.length : input.pointers.length > session.prevInput.maxPointers ? input.pointers.length : session.prevInput.maxPointers;
2341 computeIntervalInputData(session, input); // find the correct target
2342
2343 var target = manager.element;
2344 var srcEvent = input.srcEvent;
2345 var srcEventTarget;
2346
2347 if (srcEvent.composedPath) {
2348 srcEventTarget = srcEvent.composedPath()[0];
2349 } else if (srcEvent.path) {
2350 srcEventTarget = srcEvent.path[0];
2351 } else {
2352 srcEventTarget = srcEvent.target;
2353 }
2354
2355 if (hasParent(srcEventTarget, target)) {
2356 target = srcEventTarget;
2357 }
2358
2359 input.target = target;
2360 }
2361
2362 /**
2363 * @private
2364 * handle input events
2365 * @param {Manager} manager
2366 * @param {String} eventType
2367 * @param {Object} input
2368 */
2369
2370 function inputHandler(manager, eventType, input) {
2371 var pointersLen = input.pointers.length;
2372 var changedPointersLen = input.changedPointers.length;
2373 var isFirst = eventType & INPUT_START && pointersLen - changedPointersLen === 0;
2374 var isFinal = eventType & (INPUT_END | INPUT_CANCEL) && pointersLen - changedPointersLen === 0;
2375 input.isFirst = !!isFirst;
2376 input.isFinal = !!isFinal;
2377
2378 if (isFirst) {
2379 manager.session = {};
2380 } // source event is the normalized value of the domEvents
2381 // like 'touchstart, mouseup, pointerdown'
2382
2383
2384 input.eventType = eventType; // compute scale, rotation etc
2385
2386 computeInputData(manager, input); // emit secret event
2387
2388 manager.emit('hammer.input', input);
2389 manager.recognize(input);
2390 manager.session.prevInput = input;
2391 }
2392
2393 /**
2394 * @private
2395 * split string on whitespace
2396 * @param {String} str
2397 * @returns {Array} words
2398 */
2399 function splitStr(str) {
2400 return str.trim().split(/\s+/g);
2401 }
2402
2403 /**
2404 * @private
2405 * addEventListener with multiple events at once
2406 * @param {EventTarget} target
2407 * @param {String} types
2408 * @param {Function} handler
2409 */
2410
2411 function addEventListeners(target, types, handler) {
2412 each(splitStr(types), function (type) {
2413 target.addEventListener(type, handler, false);
2414 });
2415 }
2416
2417 /**
2418 * @private
2419 * removeEventListener with multiple events at once
2420 * @param {EventTarget} target
2421 * @param {String} types
2422 * @param {Function} handler
2423 */
2424
2425 function removeEventListeners(target, types, handler) {
2426 each(splitStr(types), function (type) {
2427 target.removeEventListener(type, handler, false);
2428 });
2429 }
2430
2431 /**
2432 * @private
2433 * get the window object of an element
2434 * @param {HTMLElement} element
2435 * @returns {DocumentView|Window}
2436 */
2437 function getWindowForElement(element) {
2438 var doc = element.ownerDocument || element;
2439 return doc.defaultView || doc.parentWindow || window;
2440 }
2441
2442 /**
2443 * @private
2444 * create new input type manager
2445 * @param {Manager} manager
2446 * @param {Function} callback
2447 * @returns {Input}
2448 * @constructor
2449 */
2450
2451 var Input =
2452 /*#__PURE__*/
2453 function () {
2454 function Input(manager, callback) {
2455 var self = this;
2456 this.manager = manager;
2457 this.callback = callback;
2458 this.element = manager.element;
2459 this.target = manager.options.inputTarget; // smaller wrapper around the handler, for the scope and the enabled state of the manager,
2460 // so when disabled the input events are completely bypassed.
2461
2462 this.domHandler = function (ev) {
2463 if (boolOrFn(manager.options.enable, [manager])) {
2464 self.handler(ev);
2465 }
2466 };
2467
2468 this.init();
2469 }
2470 /**
2471 * @private
2472 * should handle the inputEvent data and trigger the callback
2473 * @virtual
2474 */
2475
2476
2477 var _proto = Input.prototype;
2478
2479 _proto.handler = function handler() {};
2480 /**
2481 * @private
2482 * bind the events
2483 */
2484
2485
2486 _proto.init = function init() {
2487 this.evEl && addEventListeners(this.element, this.evEl, this.domHandler);
2488 this.evTarget && addEventListeners(this.target, this.evTarget, this.domHandler);
2489 this.evWin && addEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler);
2490 };
2491 /**
2492 * @private
2493 * unbind the events
2494 */
2495
2496
2497 _proto.destroy = function destroy() {
2498 this.evEl && removeEventListeners(this.element, this.evEl, this.domHandler);
2499 this.evTarget && removeEventListeners(this.target, this.evTarget, this.domHandler);
2500 this.evWin && removeEventListeners(getWindowForElement(this.element), this.evWin, this.domHandler);
2501 };
2502
2503 return Input;
2504 }();
2505
2506 /**
2507 * @private
2508 * find if a array contains the object using indexOf or a simple polyFill
2509 * @param {Array} src
2510 * @param {String} find
2511 * @param {String} [findByKey]
2512 * @return {Boolean|Number} false when not found, or the index
2513 */
2514 function inArray(src, find, findByKey) {
2515 if (src.indexOf && !findByKey) {
2516 return src.indexOf(find);
2517 } else {
2518 var i = 0;
2519
2520 while (i < src.length) {
2521 if (findByKey && src[i][findByKey] == find || !findByKey && src[i] === find) {
2522 // do not use === here, test fails
2523 return i;
2524 }
2525
2526 i++;
2527 }
2528
2529 return -1;
2530 }
2531 }
2532
2533 var POINTER_INPUT_MAP = {
2534 pointerdown: INPUT_START,
2535 pointermove: INPUT_MOVE,
2536 pointerup: INPUT_END,
2537 pointercancel: INPUT_CANCEL,
2538 pointerout: INPUT_CANCEL
2539 }; // in IE10 the pointer types is defined as an enum
2540
2541 var IE10_POINTER_TYPE_ENUM = {
2542 2: INPUT_TYPE_TOUCH,
2543 3: INPUT_TYPE_PEN,
2544 4: INPUT_TYPE_MOUSE,
2545 5: INPUT_TYPE_KINECT // see https://twitter.com/jacobrossi/status/480596438489890816
2546
2547 };
2548 var POINTER_ELEMENT_EVENTS = 'pointerdown';
2549 var POINTER_WINDOW_EVENTS = 'pointermove pointerup pointercancel'; // IE10 has prefixed support, and case-sensitive
2550
2551 if (win$1.MSPointerEvent && !win$1.PointerEvent) {
2552 POINTER_ELEMENT_EVENTS = 'MSPointerDown';
2553 POINTER_WINDOW_EVENTS = 'MSPointerMove MSPointerUp MSPointerCancel';
2554 }
2555 /**
2556 * @private
2557 * Pointer events input
2558 * @constructor
2559 * @extends Input
2560 */
2561
2562
2563 var PointerEventInput =
2564 /*#__PURE__*/
2565 function (_Input) {
2566 _inheritsLoose(PointerEventInput, _Input);
2567
2568 function PointerEventInput() {
2569 var _this;
2570
2571 var proto = PointerEventInput.prototype;
2572 proto.evEl = POINTER_ELEMENT_EVENTS;
2573 proto.evWin = POINTER_WINDOW_EVENTS;
2574 _this = _Input.apply(this, arguments) || this;
2575 _this.store = _this.manager.session.pointerEvents = [];
2576 return _this;
2577 }
2578 /**
2579 * @private
2580 * handle mouse events
2581 * @param {Object} ev
2582 */
2583
2584
2585 var _proto = PointerEventInput.prototype;
2586
2587 _proto.handler = function handler(ev) {
2588 var store = this.store;
2589 var removePointer = false;
2590 var eventTypeNormalized = ev.type.toLowerCase().replace('ms', '');
2591 var eventType = POINTER_INPUT_MAP[eventTypeNormalized];
2592 var pointerType = IE10_POINTER_TYPE_ENUM[ev.pointerType] || ev.pointerType;
2593 var isTouch = pointerType === INPUT_TYPE_TOUCH; // get index of the event in the store
2594
2595 var storeIndex = inArray(store, ev.pointerId, 'pointerId'); // start and mouse must be down
2596
2597 if (eventType & INPUT_START && (ev.button === 0 || isTouch)) {
2598 if (storeIndex < 0) {
2599 store.push(ev);
2600 storeIndex = store.length - 1;
2601 }
2602 } else if (eventType & (INPUT_END | INPUT_CANCEL)) {
2603 removePointer = true;
2604 } // it not found, so the pointer hasn't been down (so it's probably a hover)
2605
2606
2607 if (storeIndex < 0) {
2608 return;
2609 } // update the event in the store
2610
2611
2612 store[storeIndex] = ev;
2613 this.callback(this.manager, eventType, {
2614 pointers: store,
2615 changedPointers: [ev],
2616 pointerType: pointerType,
2617 srcEvent: ev
2618 });
2619
2620 if (removePointer) {
2621 // remove from the store
2622 store.splice(storeIndex, 1);
2623 }
2624 };
2625
2626 return PointerEventInput;
2627 }(Input);
2628
2629 /**
2630 * @private
2631 * convert array-like objects to real arrays
2632 * @param {Object} obj
2633 * @returns {Array}
2634 */
2635 function toArray$1(obj) {
2636 return Array.prototype.slice.call(obj, 0);
2637 }
2638
2639 /**
2640 * @private
2641 * unique array with objects based on a key (like 'id') or just by the array's value
2642 * @param {Array} src [{id:1},{id:2},{id:1}]
2643 * @param {String} [key]
2644 * @param {Boolean} [sort=False]
2645 * @returns {Array} [{id:1},{id:2}]
2646 */
2647
2648 function uniqueArray(src, key, sort) {
2649 var results = [];
2650 var values = [];
2651 var i = 0;
2652
2653 while (i < src.length) {
2654 var val = key ? src[i][key] : src[i];
2655
2656 if (inArray(values, val) < 0) {
2657 results.push(src[i]);
2658 }
2659
2660 values[i] = val;
2661 i++;
2662 }
2663
2664 if (sort) {
2665 if (!key) {
2666 results = results.sort();
2667 } else {
2668 results = results.sort(function (a, b) {
2669 return a[key] > b[key];
2670 });
2671 }
2672 }
2673
2674 return results;
2675 }
2676
2677 var TOUCH_INPUT_MAP = {
2678 touchstart: INPUT_START,
2679 touchmove: INPUT_MOVE,
2680 touchend: INPUT_END,
2681 touchcancel: INPUT_CANCEL
2682 };
2683 var TOUCH_TARGET_EVENTS = 'touchstart touchmove touchend touchcancel';
2684 /**
2685 * @private
2686 * Multi-user touch events input
2687 * @constructor
2688 * @extends Input
2689 */
2690
2691 var TouchInput =
2692 /*#__PURE__*/
2693 function (_Input) {
2694 _inheritsLoose(TouchInput, _Input);
2695
2696 function TouchInput() {
2697 var _this;
2698
2699 TouchInput.prototype.evTarget = TOUCH_TARGET_EVENTS;
2700 _this = _Input.apply(this, arguments) || this;
2701 _this.targetIds = {}; // this.evTarget = TOUCH_TARGET_EVENTS;
2702
2703 return _this;
2704 }
2705
2706 var _proto = TouchInput.prototype;
2707
2708 _proto.handler = function handler(ev) {
2709 var type = TOUCH_INPUT_MAP[ev.type];
2710 var touches = getTouches.call(this, ev, type);
2711
2712 if (!touches) {
2713 return;
2714 }
2715
2716 this.callback(this.manager, type, {
2717 pointers: touches[0],
2718 changedPointers: touches[1],
2719 pointerType: INPUT_TYPE_TOUCH,
2720 srcEvent: ev
2721 });
2722 };
2723
2724 return TouchInput;
2725 }(Input);
2726
2727 function getTouches(ev, type) {
2728 var allTouches = toArray$1(ev.touches);
2729 var targetIds = this.targetIds; // when there is only one touch, the process can be simplified
2730
2731 if (type & (INPUT_START | INPUT_MOVE) && allTouches.length === 1) {
2732 targetIds[allTouches[0].identifier] = true;
2733 return [allTouches, allTouches];
2734 }
2735
2736 var i;
2737 var targetTouches;
2738 var changedTouches = toArray$1(ev.changedTouches);
2739 var changedTargetTouches = [];
2740 var target = this.target; // get target touches from touches
2741
2742 targetTouches = allTouches.filter(function (touch) {
2743 return hasParent(touch.target, target);
2744 }); // collect touches
2745
2746 if (type === INPUT_START) {
2747 i = 0;
2748
2749 while (i < targetTouches.length) {
2750 targetIds[targetTouches[i].identifier] = true;
2751 i++;
2752 }
2753 } // filter changed touches to only contain touches that exist in the collected target ids
2754
2755
2756 i = 0;
2757
2758 while (i < changedTouches.length) {
2759 if (targetIds[changedTouches[i].identifier]) {
2760 changedTargetTouches.push(changedTouches[i]);
2761 } // cleanup removed touches
2762
2763
2764 if (type & (INPUT_END | INPUT_CANCEL)) {
2765 delete targetIds[changedTouches[i].identifier];
2766 }
2767
2768 i++;
2769 }
2770
2771 if (!changedTargetTouches.length) {
2772 return;
2773 }
2774
2775 return [// merge targetTouches with changedTargetTouches so it contains ALL touches, including 'end' and 'cancel'
2776 uniqueArray(targetTouches.concat(changedTargetTouches), 'identifier', true), changedTargetTouches];
2777 }
2778
2779 var MOUSE_INPUT_MAP = {
2780 mousedown: INPUT_START,
2781 mousemove: INPUT_MOVE,
2782 mouseup: INPUT_END
2783 };
2784 var MOUSE_ELEMENT_EVENTS = 'mousedown';
2785 var MOUSE_WINDOW_EVENTS = 'mousemove mouseup';
2786 /**
2787 * @private
2788 * Mouse events input
2789 * @constructor
2790 * @extends Input
2791 */
2792
2793 var MouseInput =
2794 /*#__PURE__*/
2795 function (_Input) {
2796 _inheritsLoose(MouseInput, _Input);
2797
2798 function MouseInput() {
2799 var _this;
2800
2801 var proto = MouseInput.prototype;
2802 proto.evEl = MOUSE_ELEMENT_EVENTS;
2803 proto.evWin = MOUSE_WINDOW_EVENTS;
2804 _this = _Input.apply(this, arguments) || this;
2805 _this.pressed = false; // mousedown state
2806
2807 return _this;
2808 }
2809 /**
2810 * @private
2811 * handle mouse events
2812 * @param {Object} ev
2813 */
2814
2815
2816 var _proto = MouseInput.prototype;
2817
2818 _proto.handler = function handler(ev) {
2819 var eventType = MOUSE_INPUT_MAP[ev.type]; // on start we want to have the left mouse button down
2820
2821 if (eventType & INPUT_START && ev.button === 0) {
2822 this.pressed = true;
2823 }
2824
2825 if (eventType & INPUT_MOVE && ev.which !== 1) {
2826 eventType = INPUT_END;
2827 } // mouse must be down
2828
2829
2830 if (!this.pressed) {
2831 return;
2832 }
2833
2834 if (eventType & INPUT_END) {
2835 this.pressed = false;
2836 }
2837
2838 this.callback(this.manager, eventType, {
2839 pointers: [ev],
2840 changedPointers: [ev],
2841 pointerType: INPUT_TYPE_MOUSE,
2842 srcEvent: ev
2843 });
2844 };
2845
2846 return MouseInput;
2847 }(Input);
2848
2849 /**
2850 * @private
2851 * Combined touch and mouse input
2852 *
2853 * Touch has a higher priority then mouse, and while touching no mouse events are allowed.
2854 * This because touch devices also emit mouse events while doing a touch.
2855 *
2856 * @constructor
2857 * @extends Input
2858 */
2859
2860 var DEDUP_TIMEOUT = 2500;
2861 var DEDUP_DISTANCE = 25;
2862
2863 function setLastTouch(eventData) {
2864 var _eventData$changedPoi = eventData.changedPointers,
2865 touch = _eventData$changedPoi[0];
2866
2867 if (touch.identifier === this.primaryTouch) {
2868 var lastTouch = {
2869 x: touch.clientX,
2870 y: touch.clientY
2871 };
2872 var lts = this.lastTouches;
2873 this.lastTouches.push(lastTouch);
2874
2875 var removeLastTouch = function removeLastTouch() {
2876 var i = lts.indexOf(lastTouch);
2877
2878 if (i > -1) {
2879 lts.splice(i, 1);
2880 }
2881 };
2882
2883 setTimeout(removeLastTouch, DEDUP_TIMEOUT);
2884 }
2885 }
2886
2887 function recordTouches(eventType, eventData) {
2888 if (eventType & INPUT_START) {
2889 this.primaryTouch = eventData.changedPointers[0].identifier;
2890 setLastTouch.call(this, eventData);
2891 } else if (eventType & (INPUT_END | INPUT_CANCEL)) {
2892 setLastTouch.call(this, eventData);
2893 }
2894 }
2895
2896 function isSyntheticEvent(eventData) {
2897 var x = eventData.srcEvent.clientX;
2898 var y = eventData.srcEvent.clientY;
2899
2900 for (var i = 0; i < this.lastTouches.length; i++) {
2901 var t = this.lastTouches[i];
2902 var dx = Math.abs(x - t.x);
2903 var dy = Math.abs(y - t.y);
2904
2905 if (dx <= DEDUP_DISTANCE && dy <= DEDUP_DISTANCE) {
2906 return true;
2907 }
2908 }
2909
2910 return false;
2911 }
2912
2913 var TouchMouseInput =
2914 /*#__PURE__*/
2915 function () {
2916 var TouchMouseInput =
2917 /*#__PURE__*/
2918 function (_Input) {
2919 _inheritsLoose(TouchMouseInput, _Input);
2920
2921 function TouchMouseInput(_manager, callback) {
2922 var _this;
2923
2924 _this = _Input.call(this, _manager, callback) || this;
2925
2926 _this.handler = function (manager, inputEvent, inputData) {
2927 var isTouch = inputData.pointerType === INPUT_TYPE_TOUCH;
2928 var isMouse = inputData.pointerType === INPUT_TYPE_MOUSE;
2929
2930 if (isMouse && inputData.sourceCapabilities && inputData.sourceCapabilities.firesTouchEvents) {
2931 return;
2932 } // when we're in a touch event, record touches to de-dupe synthetic mouse event
2933
2934
2935 if (isTouch) {
2936 recordTouches.call(_assertThisInitialized(_assertThisInitialized(_this)), inputEvent, inputData);
2937 } else if (isMouse && isSyntheticEvent.call(_assertThisInitialized(_assertThisInitialized(_this)), inputData)) {
2938 return;
2939 }
2940
2941 _this.callback(manager, inputEvent, inputData);
2942 };
2943
2944 _this.touch = new TouchInput(_this.manager, _this.handler);
2945 _this.mouse = new MouseInput(_this.manager, _this.handler);
2946 _this.primaryTouch = null;
2947 _this.lastTouches = [];
2948 return _this;
2949 }
2950 /**
2951 * @private
2952 * handle mouse and touch events
2953 * @param {Hammer} manager
2954 * @param {String} inputEvent
2955 * @param {Object} inputData
2956 */
2957
2958
2959 var _proto = TouchMouseInput.prototype;
2960
2961 /**
2962 * @private
2963 * remove the event listeners
2964 */
2965 _proto.destroy = function destroy() {
2966 this.touch.destroy();
2967 this.mouse.destroy();
2968 };
2969
2970 return TouchMouseInput;
2971 }(Input);
2972
2973 return TouchMouseInput;
2974 }();
2975
2976 /**
2977 * @private
2978 * create new input type manager
2979 * called by the Manager constructor
2980 * @param {Hammer} manager
2981 * @returns {Input}
2982 */
2983
2984 function createInputInstance(manager) {
2985 var Type; // let inputClass = manager.options.inputClass;
2986
2987 var inputClass = manager.options.inputClass;
2988
2989 if (inputClass) {
2990 Type = inputClass;
2991 } else if (SUPPORT_POINTER_EVENTS) {
2992 Type = PointerEventInput;
2993 } else if (SUPPORT_ONLY_TOUCH) {
2994 Type = TouchInput;
2995 } else if (!SUPPORT_TOUCH) {
2996 Type = MouseInput;
2997 } else {
2998 Type = TouchMouseInput;
2999 }
3000
3001 return new Type(manager, inputHandler);
3002 }
3003
3004 /**
3005 * @private
3006 * if the argument is an array, we want to execute the fn on each entry
3007 * if it aint an array we don't want to do a thing.
3008 * this is used by all the methods that accept a single and array argument.
3009 * @param {*|Array} arg
3010 * @param {String} fn
3011 * @param {Object} [context]
3012 * @returns {Boolean}
3013 */
3014
3015 function invokeArrayArg(arg, fn, context) {
3016 if (Array.isArray(arg)) {
3017 each(arg, context[fn], context);
3018 return true;
3019 }
3020
3021 return false;
3022 }
3023
3024 var STATE_POSSIBLE = 1;
3025 var STATE_BEGAN = 2;
3026 var STATE_CHANGED = 4;
3027 var STATE_ENDED = 8;
3028 var STATE_RECOGNIZED = STATE_ENDED;
3029 var STATE_CANCELLED = 16;
3030 var STATE_FAILED = 32;
3031
3032 /**
3033 * @private
3034 * get a unique id
3035 * @returns {number} uniqueId
3036 */
3037 var _uniqueId = 1;
3038 function uniqueId() {
3039 return _uniqueId++;
3040 }
3041
3042 /**
3043 * @private
3044 * get a recognizer by name if it is bound to a manager
3045 * @param {Recognizer|String} otherRecognizer
3046 * @param {Recognizer} recognizer
3047 * @returns {Recognizer}
3048 */
3049 function getRecognizerByNameIfManager(otherRecognizer, recognizer) {
3050 var manager = recognizer.manager;
3051
3052 if (manager) {
3053 return manager.get(otherRecognizer);
3054 }
3055
3056 return otherRecognizer;
3057 }
3058
3059 /**
3060 * @private
3061 * get a usable string, used as event postfix
3062 * @param {constant} state
3063 * @returns {String} state
3064 */
3065
3066 function stateStr(state) {
3067 if (state & STATE_CANCELLED) {
3068 return 'cancel';
3069 } else if (state & STATE_ENDED) {
3070 return 'end';
3071 } else if (state & STATE_CHANGED) {
3072 return 'move';
3073 } else if (state & STATE_BEGAN) {
3074 return 'start';
3075 }
3076
3077 return '';
3078 }
3079
3080 /**
3081 * @private
3082 * Recognizer flow explained; *
3083 * All recognizers have the initial state of POSSIBLE when a input session starts.
3084 * The definition of a input session is from the first input until the last input, with all it's movement in it. *
3085 * Example session for mouse-input: mousedown -> mousemove -> mouseup
3086 *
3087 * On each recognizing cycle (see Manager.recognize) the .recognize() method is executed
3088 * which determines with state it should be.
3089 *
3090 * If the recognizer has the state FAILED, CANCELLED or RECOGNIZED (equals ENDED), it is reset to
3091 * POSSIBLE to give it another change on the next cycle.
3092 *
3093 * Possible
3094 * |
3095 * +-----+---------------+
3096 * | |
3097 * +-----+-----+ |
3098 * | | |
3099 * Failed Cancelled |
3100 * +-------+------+
3101 * | |
3102 * Recognized Began
3103 * |
3104 * Changed
3105 * |
3106 * Ended/Recognized
3107 */
3108
3109 /**
3110 * @private
3111 * Recognizer
3112 * Every recognizer needs to extend from this class.
3113 * @constructor
3114 * @param {Object} options
3115 */
3116
3117 var Recognizer =
3118 /*#__PURE__*/
3119 function () {
3120 function Recognizer(options) {
3121 if (options === void 0) {
3122 options = {};
3123 }
3124
3125 this.options = _extends({
3126 enable: true
3127 }, options);
3128 this.id = uniqueId();
3129 this.manager = null; // default is enable true
3130
3131 this.state = STATE_POSSIBLE;
3132 this.simultaneous = {};
3133 this.requireFail = [];
3134 }
3135 /**
3136 * @private
3137 * set options
3138 * @param {Object} options
3139 * @return {Recognizer}
3140 */
3141
3142
3143 var _proto = Recognizer.prototype;
3144
3145 _proto.set = function set(options) {
3146 assign$1(this.options, options); // also update the touchAction, in case something changed about the directions/enabled state
3147
3148 this.manager && this.manager.touchAction.update();
3149 return this;
3150 };
3151 /**
3152 * @private
3153 * recognize simultaneous with an other recognizer.
3154 * @param {Recognizer} otherRecognizer
3155 * @returns {Recognizer} this
3156 */
3157
3158
3159 _proto.recognizeWith = function recognizeWith(otherRecognizer) {
3160 if (invokeArrayArg(otherRecognizer, 'recognizeWith', this)) {
3161 return this;
3162 }
3163
3164 var simultaneous = this.simultaneous;
3165 otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
3166
3167 if (!simultaneous[otherRecognizer.id]) {
3168 simultaneous[otherRecognizer.id] = otherRecognizer;
3169 otherRecognizer.recognizeWith(this);
3170 }
3171
3172 return this;
3173 };
3174 /**
3175 * @private
3176 * drop the simultaneous link. it doesnt remove the link on the other recognizer.
3177 * @param {Recognizer} otherRecognizer
3178 * @returns {Recognizer} this
3179 */
3180
3181
3182 _proto.dropRecognizeWith = function dropRecognizeWith(otherRecognizer) {
3183 if (invokeArrayArg(otherRecognizer, 'dropRecognizeWith', this)) {
3184 return this;
3185 }
3186
3187 otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
3188 delete this.simultaneous[otherRecognizer.id];
3189 return this;
3190 };
3191 /**
3192 * @private
3193 * recognizer can only run when an other is failing
3194 * @param {Recognizer} otherRecognizer
3195 * @returns {Recognizer} this
3196 */
3197
3198
3199 _proto.requireFailure = function requireFailure(otherRecognizer) {
3200 if (invokeArrayArg(otherRecognizer, 'requireFailure', this)) {
3201 return this;
3202 }
3203
3204 var requireFail = this.requireFail;
3205 otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
3206
3207 if (inArray(requireFail, otherRecognizer) === -1) {
3208 requireFail.push(otherRecognizer);
3209 otherRecognizer.requireFailure(this);
3210 }
3211
3212 return this;
3213 };
3214 /**
3215 * @private
3216 * drop the requireFailure link. it does not remove the link on the other recognizer.
3217 * @param {Recognizer} otherRecognizer
3218 * @returns {Recognizer} this
3219 */
3220
3221
3222 _proto.dropRequireFailure = function dropRequireFailure(otherRecognizer) {
3223 if (invokeArrayArg(otherRecognizer, 'dropRequireFailure', this)) {
3224 return this;
3225 }
3226
3227 otherRecognizer = getRecognizerByNameIfManager(otherRecognizer, this);
3228 var index = inArray(this.requireFail, otherRecognizer);
3229
3230 if (index > -1) {
3231 this.requireFail.splice(index, 1);
3232 }
3233
3234 return this;
3235 };
3236 /**
3237 * @private
3238 * has require failures boolean
3239 * @returns {boolean}
3240 */
3241
3242
3243 _proto.hasRequireFailures = function hasRequireFailures() {
3244 return this.requireFail.length > 0;
3245 };
3246 /**
3247 * @private
3248 * if the recognizer can recognize simultaneous with an other recognizer
3249 * @param {Recognizer} otherRecognizer
3250 * @returns {Boolean}
3251 */
3252
3253
3254 _proto.canRecognizeWith = function canRecognizeWith(otherRecognizer) {
3255 return !!this.simultaneous[otherRecognizer.id];
3256 };
3257 /**
3258 * @private
3259 * You should use `tryEmit` instead of `emit` directly to check
3260 * that all the needed recognizers has failed before emitting.
3261 * @param {Object} input
3262 */
3263
3264
3265 _proto.emit = function emit(input) {
3266 var self = this;
3267 var state = this.state;
3268
3269 function emit(event) {
3270 self.manager.emit(event, input);
3271 } // 'panstart' and 'panmove'
3272
3273
3274 if (state < STATE_ENDED) {
3275 emit(self.options.event + stateStr(state));
3276 }
3277
3278 emit(self.options.event); // simple 'eventName' events
3279
3280 if (input.additionalEvent) {
3281 // additional event(panleft, panright, pinchin, pinchout...)
3282 emit(input.additionalEvent);
3283 } // panend and pancancel
3284
3285
3286 if (state >= STATE_ENDED) {
3287 emit(self.options.event + stateStr(state));
3288 }
3289 };
3290 /**
3291 * @private
3292 * Check that all the require failure recognizers has failed,
3293 * if true, it emits a gesture event,
3294 * otherwise, setup the state to FAILED.
3295 * @param {Object} input
3296 */
3297
3298
3299 _proto.tryEmit = function tryEmit(input) {
3300 if (this.canEmit()) {
3301 return this.emit(input);
3302 } // it's failing anyway
3303
3304
3305 this.state = STATE_FAILED;
3306 };
3307 /**
3308 * @private
3309 * can we emit?
3310 * @returns {boolean}
3311 */
3312
3313
3314 _proto.canEmit = function canEmit() {
3315 var i = 0;
3316
3317 while (i < this.requireFail.length) {
3318 if (!(this.requireFail[i].state & (STATE_FAILED | STATE_POSSIBLE))) {
3319 return false;
3320 }
3321
3322 i++;
3323 }
3324
3325 return true;
3326 };
3327 /**
3328 * @private
3329 * update the recognizer
3330 * @param {Object} inputData
3331 */
3332
3333
3334 _proto.recognize = function recognize(inputData) {
3335 // make a new copy of the inputData
3336 // so we can change the inputData without messing up the other recognizers
3337 var inputDataClone = assign$1({}, inputData); // is is enabled and allow recognizing?
3338
3339 if (!boolOrFn(this.options.enable, [this, inputDataClone])) {
3340 this.reset();
3341 this.state = STATE_FAILED;
3342 return;
3343 } // reset when we've reached the end
3344
3345
3346 if (this.state & (STATE_RECOGNIZED | STATE_CANCELLED | STATE_FAILED)) {
3347 this.state = STATE_POSSIBLE;
3348 }
3349
3350 this.state = this.process(inputDataClone); // the recognizer has recognized a gesture
3351 // so trigger an event
3352
3353 if (this.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED | STATE_CANCELLED)) {
3354 this.tryEmit(inputDataClone);
3355 }
3356 };
3357 /**
3358 * @private
3359 * return the state of the recognizer
3360 * the actual recognizing happens in this method
3361 * @virtual
3362 * @param {Object} inputData
3363 * @returns {constant} STATE
3364 */
3365
3366 /* jshint ignore:start */
3367
3368
3369 _proto.process = function process(inputData) {};
3370 /* jshint ignore:end */
3371
3372 /**
3373 * @private
3374 * return the preferred touch-action
3375 * @virtual
3376 * @returns {Array}
3377 */
3378
3379
3380 _proto.getTouchAction = function getTouchAction() {};
3381 /**
3382 * @private
3383 * called when the gesture isn't allowed to recognize
3384 * like when another is being recognized or it is disabled
3385 * @virtual
3386 */
3387
3388
3389 _proto.reset = function reset() {};
3390
3391 return Recognizer;
3392 }();
3393
3394 /**
3395 * @private
3396 * A tap is recognized when the pointer is doing a small tap/click. Multiple taps are recognized if they occur
3397 * between the given interval and position. The delay option can be used to recognize multi-taps without firing
3398 * a single tap.
3399 *
3400 * The eventData from the emitted event contains the property `tapCount`, which contains the amount of
3401 * multi-taps being recognized.
3402 * @constructor
3403 * @extends Recognizer
3404 */
3405
3406 var TapRecognizer =
3407 /*#__PURE__*/
3408 function (_Recognizer) {
3409 _inheritsLoose(TapRecognizer, _Recognizer);
3410
3411 function TapRecognizer(options) {
3412 var _this;
3413
3414 if (options === void 0) {
3415 options = {};
3416 }
3417
3418 _this = _Recognizer.call(this, _extends({
3419 event: 'tap',
3420 pointers: 1,
3421 taps: 1,
3422 interval: 300,
3423 // max time between the multi-tap taps
3424 time: 250,
3425 // max time of the pointer to be down (like finger on the screen)
3426 threshold: 9,
3427 // a minimal movement is ok, but keep it low
3428 posThreshold: 10
3429 }, options)) || this; // previous time and center,
3430 // used for tap counting
3431
3432 _this.pTime = false;
3433 _this.pCenter = false;
3434 _this._timer = null;
3435 _this._input = null;
3436 _this.count = 0;
3437 return _this;
3438 }
3439
3440 var _proto = TapRecognizer.prototype;
3441
3442 _proto.getTouchAction = function getTouchAction() {
3443 return [TOUCH_ACTION_MANIPULATION];
3444 };
3445
3446 _proto.process = function process(input) {
3447 var _this2 = this;
3448
3449 var options = this.options;
3450 var validPointers = input.pointers.length === options.pointers;
3451 var validMovement = input.distance < options.threshold;
3452 var validTouchTime = input.deltaTime < options.time;
3453 this.reset();
3454
3455 if (input.eventType & INPUT_START && this.count === 0) {
3456 return this.failTimeout();
3457 } // we only allow little movement
3458 // and we've reached an end event, so a tap is possible
3459
3460
3461 if (validMovement && validTouchTime && validPointers) {
3462 if (input.eventType !== INPUT_END) {
3463 return this.failTimeout();
3464 }
3465
3466 var validInterval = this.pTime ? input.timeStamp - this.pTime < options.interval : true;
3467 var validMultiTap = !this.pCenter || getDistance(this.pCenter, input.center) < options.posThreshold;
3468 this.pTime = input.timeStamp;
3469 this.pCenter = input.center;
3470
3471 if (!validMultiTap || !validInterval) {
3472 this.count = 1;
3473 } else {
3474 this.count += 1;
3475 }
3476
3477 this._input = input; // if tap count matches we have recognized it,
3478 // else it has began recognizing...
3479
3480 var tapCount = this.count % options.taps;
3481
3482 if (tapCount === 0) {
3483 // no failing requirements, immediately trigger the tap event
3484 // or wait as long as the multitap interval to trigger
3485 if (!this.hasRequireFailures()) {
3486 return STATE_RECOGNIZED;
3487 } else {
3488 this._timer = setTimeout(function () {
3489 _this2.state = STATE_RECOGNIZED;
3490
3491 _this2.tryEmit();
3492 }, options.interval);
3493 return STATE_BEGAN;
3494 }
3495 }
3496 }
3497
3498 return STATE_FAILED;
3499 };
3500
3501 _proto.failTimeout = function failTimeout() {
3502 var _this3 = this;
3503
3504 this._timer = setTimeout(function () {
3505 _this3.state = STATE_FAILED;
3506 }, this.options.interval);
3507 return STATE_FAILED;
3508 };
3509
3510 _proto.reset = function reset() {
3511 clearTimeout(this._timer);
3512 };
3513
3514 _proto.emit = function emit() {
3515 if (this.state === STATE_RECOGNIZED) {
3516 this._input.tapCount = this.count;
3517 this.manager.emit(this.options.event, this._input);
3518 }
3519 };
3520
3521 return TapRecognizer;
3522 }(Recognizer);
3523
3524 /**
3525 * @private
3526 * This recognizer is just used as a base for the simple attribute recognizers.
3527 * @constructor
3528 * @extends Recognizer
3529 */
3530
3531 var AttrRecognizer =
3532 /*#__PURE__*/
3533 function (_Recognizer) {
3534 _inheritsLoose(AttrRecognizer, _Recognizer);
3535
3536 function AttrRecognizer(options) {
3537 if (options === void 0) {
3538 options = {};
3539 }
3540
3541 return _Recognizer.call(this, _extends({
3542 pointers: 1
3543 }, options)) || this;
3544 }
3545 /**
3546 * @private
3547 * Used to check if it the recognizer receives valid input, like input.distance > 10.
3548 * @memberof AttrRecognizer
3549 * @param {Object} input
3550 * @returns {Boolean} recognized
3551 */
3552
3553
3554 var _proto = AttrRecognizer.prototype;
3555
3556 _proto.attrTest = function attrTest(input) {
3557 var optionPointers = this.options.pointers;
3558 return optionPointers === 0 || input.pointers.length === optionPointers;
3559 };
3560 /**
3561 * @private
3562 * Process the input and return the state for the recognizer
3563 * @memberof AttrRecognizer
3564 * @param {Object} input
3565 * @returns {*} State
3566 */
3567
3568
3569 _proto.process = function process(input) {
3570 var state = this.state;
3571 var eventType = input.eventType;
3572 var isRecognized = state & (STATE_BEGAN | STATE_CHANGED);
3573 var isValid = this.attrTest(input); // on cancel input and we've recognized before, return STATE_CANCELLED
3574
3575 if (isRecognized && (eventType & INPUT_CANCEL || !isValid)) {
3576 return state | STATE_CANCELLED;
3577 } else if (isRecognized || isValid) {
3578 if (eventType & INPUT_END) {
3579 return state | STATE_ENDED;
3580 } else if (!(state & STATE_BEGAN)) {
3581 return STATE_BEGAN;
3582 }
3583
3584 return state | STATE_CHANGED;
3585 }
3586
3587 return STATE_FAILED;
3588 };
3589
3590 return AttrRecognizer;
3591 }(Recognizer);
3592
3593 /**
3594 * @private
3595 * direction cons to string
3596 * @param {constant} direction
3597 * @returns {String}
3598 */
3599
3600 function directionStr(direction) {
3601 if (direction === DIRECTION_DOWN) {
3602 return 'down';
3603 } else if (direction === DIRECTION_UP) {
3604 return 'up';
3605 } else if (direction === DIRECTION_LEFT) {
3606 return 'left';
3607 } else if (direction === DIRECTION_RIGHT) {
3608 return 'right';
3609 }
3610
3611 return '';
3612 }
3613
3614 /**
3615 * @private
3616 * Pan
3617 * Recognized when the pointer is down and moved in the allowed direction.
3618 * @constructor
3619 * @extends AttrRecognizer
3620 */
3621
3622 var PanRecognizer =
3623 /*#__PURE__*/
3624 function (_AttrRecognizer) {
3625 _inheritsLoose(PanRecognizer, _AttrRecognizer);
3626
3627 function PanRecognizer(options) {
3628 var _this;
3629
3630 if (options === void 0) {
3631 options = {};
3632 }
3633
3634 _this = _AttrRecognizer.call(this, _extends({
3635 event: 'pan',
3636 threshold: 10,
3637 pointers: 1,
3638 direction: DIRECTION_ALL
3639 }, options)) || this;
3640 _this.pX = null;
3641 _this.pY = null;
3642 return _this;
3643 }
3644
3645 var _proto = PanRecognizer.prototype;
3646
3647 _proto.getTouchAction = function getTouchAction() {
3648 var direction = this.options.direction;
3649 var actions = [];
3650
3651 if (direction & DIRECTION_HORIZONTAL) {
3652 actions.push(TOUCH_ACTION_PAN_Y);
3653 }
3654
3655 if (direction & DIRECTION_VERTICAL) {
3656 actions.push(TOUCH_ACTION_PAN_X);
3657 }
3658
3659 return actions;
3660 };
3661
3662 _proto.directionTest = function directionTest(input) {
3663 var options = this.options;
3664 var hasMoved = true;
3665 var distance = input.distance;
3666 var direction = input.direction;
3667 var x = input.deltaX;
3668 var y = input.deltaY; // lock to axis?
3669
3670 if (!(direction & options.direction)) {
3671 if (options.direction & DIRECTION_HORIZONTAL) {
3672 direction = x === 0 ? DIRECTION_NONE : x < 0 ? DIRECTION_LEFT : DIRECTION_RIGHT;
3673 hasMoved = x !== this.pX;
3674 distance = Math.abs(input.deltaX);
3675 } else {
3676 direction = y === 0 ? DIRECTION_NONE : y < 0 ? DIRECTION_UP : DIRECTION_DOWN;
3677 hasMoved = y !== this.pY;
3678 distance = Math.abs(input.deltaY);
3679 }
3680 }
3681
3682 input.direction = direction;
3683 return hasMoved && distance > options.threshold && direction & options.direction;
3684 };
3685
3686 _proto.attrTest = function attrTest(input) {
3687 return AttrRecognizer.prototype.attrTest.call(this, input) && ( // replace with a super call
3688 this.state & STATE_BEGAN || !(this.state & STATE_BEGAN) && this.directionTest(input));
3689 };
3690
3691 _proto.emit = function emit(input) {
3692 this.pX = input.deltaX;
3693 this.pY = input.deltaY;
3694 var direction = directionStr(input.direction);
3695
3696 if (direction) {
3697 input.additionalEvent = this.options.event + direction;
3698 }
3699
3700 _AttrRecognizer.prototype.emit.call(this, input);
3701 };
3702
3703 return PanRecognizer;
3704 }(AttrRecognizer);
3705
3706 /**
3707 * @private
3708 * Swipe
3709 * Recognized when the pointer is moving fast (velocity), with enough distance in the allowed direction.
3710 * @constructor
3711 * @extends AttrRecognizer
3712 */
3713
3714 var SwipeRecognizer =
3715 /*#__PURE__*/
3716 function (_AttrRecognizer) {
3717 _inheritsLoose(SwipeRecognizer, _AttrRecognizer);
3718
3719 function SwipeRecognizer(options) {
3720 if (options === void 0) {
3721 options = {};
3722 }
3723
3724 return _AttrRecognizer.call(this, _extends({
3725 event: 'swipe',
3726 threshold: 10,
3727 velocity: 0.3,
3728 direction: DIRECTION_HORIZONTAL | DIRECTION_VERTICAL,
3729 pointers: 1
3730 }, options)) || this;
3731 }
3732
3733 var _proto = SwipeRecognizer.prototype;
3734
3735 _proto.getTouchAction = function getTouchAction() {
3736 return PanRecognizer.prototype.getTouchAction.call(this);
3737 };
3738
3739 _proto.attrTest = function attrTest(input) {
3740 var direction = this.options.direction;
3741 var velocity;
3742
3743 if (direction & (DIRECTION_HORIZONTAL | DIRECTION_VERTICAL)) {
3744 velocity = input.overallVelocity;
3745 } else if (direction & DIRECTION_HORIZONTAL) {
3746 velocity = input.overallVelocityX;
3747 } else if (direction & DIRECTION_VERTICAL) {
3748 velocity = input.overallVelocityY;
3749 }
3750
3751 return _AttrRecognizer.prototype.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;
3752 };
3753
3754 _proto.emit = function emit(input) {
3755 var direction = directionStr(input.offsetDirection);
3756
3757 if (direction) {
3758 this.manager.emit(this.options.event + direction, input);
3759 }
3760
3761 this.manager.emit(this.options.event, input);
3762 };
3763
3764 return SwipeRecognizer;
3765 }(AttrRecognizer);
3766
3767 /**
3768 * @private
3769 * Pinch
3770 * Recognized when two or more pointers are moving toward (zoom-in) or away from each other (zoom-out).
3771 * @constructor
3772 * @extends AttrRecognizer
3773 */
3774
3775 var PinchRecognizer =
3776 /*#__PURE__*/
3777 function (_AttrRecognizer) {
3778 _inheritsLoose(PinchRecognizer, _AttrRecognizer);
3779
3780 function PinchRecognizer(options) {
3781 if (options === void 0) {
3782 options = {};
3783 }
3784
3785 return _AttrRecognizer.call(this, _extends({
3786 event: 'pinch',
3787 threshold: 0,
3788 pointers: 2
3789 }, options)) || this;
3790 }
3791
3792 var _proto = PinchRecognizer.prototype;
3793
3794 _proto.getTouchAction = function getTouchAction() {
3795 return [TOUCH_ACTION_NONE];
3796 };
3797
3798 _proto.attrTest = function attrTest(input) {
3799 return _AttrRecognizer.prototype.attrTest.call(this, input) && (Math.abs(input.scale - 1) > this.options.threshold || this.state & STATE_BEGAN);
3800 };
3801
3802 _proto.emit = function emit(input) {
3803 if (input.scale !== 1) {
3804 var inOut = input.scale < 1 ? 'in' : 'out';
3805 input.additionalEvent = this.options.event + inOut;
3806 }
3807
3808 _AttrRecognizer.prototype.emit.call(this, input);
3809 };
3810
3811 return PinchRecognizer;
3812 }(AttrRecognizer);
3813
3814 /**
3815 * @private
3816 * Rotate
3817 * Recognized when two or more pointer are moving in a circular motion.
3818 * @constructor
3819 * @extends AttrRecognizer
3820 */
3821
3822 var RotateRecognizer =
3823 /*#__PURE__*/
3824 function (_AttrRecognizer) {
3825 _inheritsLoose(RotateRecognizer, _AttrRecognizer);
3826
3827 function RotateRecognizer(options) {
3828 if (options === void 0) {
3829 options = {};
3830 }
3831
3832 return _AttrRecognizer.call(this, _extends({
3833 event: 'rotate',
3834 threshold: 0,
3835 pointers: 2
3836 }, options)) || this;
3837 }
3838
3839 var _proto = RotateRecognizer.prototype;
3840
3841 _proto.getTouchAction = function getTouchAction() {
3842 return [TOUCH_ACTION_NONE];
3843 };
3844
3845 _proto.attrTest = function attrTest(input) {
3846 return _AttrRecognizer.prototype.attrTest.call(this, input) && (Math.abs(input.rotation) > this.options.threshold || this.state & STATE_BEGAN);
3847 };
3848
3849 return RotateRecognizer;
3850 }(AttrRecognizer);
3851
3852 /**
3853 * @private
3854 * Press
3855 * Recognized when the pointer is down for x ms without any movement.
3856 * @constructor
3857 * @extends Recognizer
3858 */
3859
3860 var PressRecognizer =
3861 /*#__PURE__*/
3862 function (_Recognizer) {
3863 _inheritsLoose(PressRecognizer, _Recognizer);
3864
3865 function PressRecognizer(options) {
3866 var _this;
3867
3868 if (options === void 0) {
3869 options = {};
3870 }
3871
3872 _this = _Recognizer.call(this, _extends({
3873 event: 'press',
3874 pointers: 1,
3875 time: 251,
3876 // minimal time of the pointer to be pressed
3877 threshold: 9
3878 }, options)) || this;
3879 _this._timer = null;
3880 _this._input = null;
3881 return _this;
3882 }
3883
3884 var _proto = PressRecognizer.prototype;
3885
3886 _proto.getTouchAction = function getTouchAction() {
3887 return [TOUCH_ACTION_AUTO];
3888 };
3889
3890 _proto.process = function process(input) {
3891 var _this2 = this;
3892
3893 var options = this.options;
3894 var validPointers = input.pointers.length === options.pointers;
3895 var validMovement = input.distance < options.threshold;
3896 var validTime = input.deltaTime > options.time;
3897 this._input = input; // we only allow little movement
3898 // and we've reached an end event, so a tap is possible
3899
3900 if (!validMovement || !validPointers || input.eventType & (INPUT_END | INPUT_CANCEL) && !validTime) {
3901 this.reset();
3902 } else if (input.eventType & INPUT_START) {
3903 this.reset();
3904 this._timer = setTimeout(function () {
3905 _this2.state = STATE_RECOGNIZED;
3906
3907 _this2.tryEmit();
3908 }, options.time);
3909 } else if (input.eventType & INPUT_END) {
3910 return STATE_RECOGNIZED;
3911 }
3912
3913 return STATE_FAILED;
3914 };
3915
3916 _proto.reset = function reset() {
3917 clearTimeout(this._timer);
3918 };
3919
3920 _proto.emit = function emit(input) {
3921 if (this.state !== STATE_RECOGNIZED) {
3922 return;
3923 }
3924
3925 if (input && input.eventType & INPUT_END) {
3926 this.manager.emit(this.options.event + "up", input);
3927 } else {
3928 this._input.timeStamp = now();
3929 this.manager.emit(this.options.event, this._input);
3930 }
3931 };
3932
3933 return PressRecognizer;
3934 }(Recognizer);
3935
3936 var defaults = {
3937 /**
3938 * @private
3939 * set if DOM events are being triggered.
3940 * But this is slower and unused by simple implementations, so disabled by default.
3941 * @type {Boolean}
3942 * @default false
3943 */
3944 domEvents: false,
3945
3946 /**
3947 * @private
3948 * The value for the touchAction property/fallback.
3949 * When set to `compute` it will magically set the correct value based on the added recognizers.
3950 * @type {String}
3951 * @default compute
3952 */
3953 touchAction: TOUCH_ACTION_COMPUTE,
3954
3955 /**
3956 * @private
3957 * @type {Boolean}
3958 * @default true
3959 */
3960 enable: true,
3961
3962 /**
3963 * @private
3964 * EXPERIMENTAL FEATURE -- can be removed/changed
3965 * Change the parent input target element.
3966 * If Null, then it is being set the to main element.
3967 * @type {Null|EventTarget}
3968 * @default null
3969 */
3970 inputTarget: null,
3971
3972 /**
3973 * @private
3974 * force an input class
3975 * @type {Null|Function}
3976 * @default null
3977 */
3978 inputClass: null,
3979
3980 /**
3981 * @private
3982 * Some CSS properties can be used to improve the working of Hammer.
3983 * Add them to this method and they will be set when creating a new Manager.
3984 * @namespace
3985 */
3986 cssProps: {
3987 /**
3988 * @private
3989 * Disables text selection to improve the dragging gesture. Mainly for desktop browsers.
3990 * @type {String}
3991 * @default 'none'
3992 */
3993 userSelect: "none",
3994
3995 /**
3996 * @private
3997 * Disable the Windows Phone grippers when pressing an element.
3998 * @type {String}
3999 * @default 'none'
4000 */
4001 touchSelect: "none",
4002
4003 /**
4004 * @private
4005 * Disables the default callout shown when you touch and hold a touch target.
4006 * On iOS, when you touch and hold a touch target such as a link, Safari displays
4007 * a callout containing information about the link. This property allows you to disable that callout.
4008 * @type {String}
4009 * @default 'none'
4010 */
4011 touchCallout: "none",
4012
4013 /**
4014 * @private
4015 * Specifies whether zooming is enabled. Used by IE10>
4016 * @type {String}
4017 * @default 'none'
4018 */
4019 contentZooming: "none",
4020
4021 /**
4022 * @private
4023 * Specifies that an entire element should be draggable instead of its contents. Mainly for desktop browsers.
4024 * @type {String}
4025 * @default 'none'
4026 */
4027 userDrag: "none",
4028
4029 /**
4030 * @private
4031 * Overrides the highlight color shown when the user taps a link or a JavaScript
4032 * clickable element in iOS. This property obeys the alpha value, if specified.
4033 * @type {String}
4034 * @default 'rgba(0,0,0,0)'
4035 */
4036 tapHighlightColor: "rgba(0,0,0,0)"
4037 }
4038 };
4039 /**
4040 * @private
4041 * Default recognizer setup when calling `Hammer()`
4042 * When creating a new Manager these will be skipped.
4043 * This is separated with other defaults because of tree-shaking.
4044 * @type {Array}
4045 */
4046
4047 var preset = [[RotateRecognizer, {
4048 enable: false
4049 }], [PinchRecognizer, {
4050 enable: false
4051 }, ['rotate']], [SwipeRecognizer, {
4052 direction: DIRECTION_HORIZONTAL
4053 }], [PanRecognizer, {
4054 direction: DIRECTION_HORIZONTAL
4055 }, ['swipe']], [TapRecognizer], [TapRecognizer, {
4056 event: 'doubletap',
4057 taps: 2
4058 }, ['tap']], [PressRecognizer]];
4059
4060 var STOP = 1;
4061 var FORCED_STOP = 2;
4062 /**
4063 * @private
4064 * add/remove the css properties as defined in manager.options.cssProps
4065 * @param {Manager} manager
4066 * @param {Boolean} add
4067 */
4068
4069 function toggleCssProps(manager, add) {
4070 var element = manager.element;
4071
4072 if (!element.style) {
4073 return;
4074 }
4075
4076 var prop;
4077 each(manager.options.cssProps, function (value, name) {
4078 prop = prefixed(element.style, name);
4079
4080 if (add) {
4081 manager.oldCssProps[prop] = element.style[prop];
4082 element.style[prop] = value;
4083 } else {
4084 element.style[prop] = manager.oldCssProps[prop] || "";
4085 }
4086 });
4087
4088 if (!add) {
4089 manager.oldCssProps = {};
4090 }
4091 }
4092 /**
4093 * @private
4094 * trigger dom event
4095 * @param {String} event
4096 * @param {Object} data
4097 */
4098
4099
4100 function triggerDomEvent(event, data) {
4101 var gestureEvent = document.createEvent("Event");
4102 gestureEvent.initEvent(event, true, true);
4103 gestureEvent.gesture = data;
4104 data.target.dispatchEvent(gestureEvent);
4105 }
4106 /**
4107 * @private
4108 * Manager
4109 * @param {HTMLElement} element
4110 * @param {Object} [options]
4111 * @constructor
4112 */
4113
4114
4115 var Manager =
4116 /*#__PURE__*/
4117 function () {
4118 function Manager(element, options) {
4119 var _this = this;
4120
4121 this.options = assign$1({}, defaults, options || {});
4122 this.options.inputTarget = this.options.inputTarget || element;
4123 this.handlers = {};
4124 this.session = {};
4125 this.recognizers = [];
4126 this.oldCssProps = {};
4127 this.element = element;
4128 this.input = createInputInstance(this);
4129 this.touchAction = new TouchAction(this, this.options.touchAction);
4130 toggleCssProps(this, true);
4131 each(this.options.recognizers, function (item) {
4132 var recognizer = _this.add(new item[0](item[1]));
4133
4134 item[2] && recognizer.recognizeWith(item[2]);
4135 item[3] && recognizer.requireFailure(item[3]);
4136 }, this);
4137 }
4138 /**
4139 * @private
4140 * set options
4141 * @param {Object} options
4142 * @returns {Manager}
4143 */
4144
4145
4146 var _proto = Manager.prototype;
4147
4148 _proto.set = function set(options) {
4149 assign$1(this.options, options); // Options that need a little more setup
4150
4151 if (options.touchAction) {
4152 this.touchAction.update();
4153 }
4154
4155 if (options.inputTarget) {
4156 // Clean up existing event listeners and reinitialize
4157 this.input.destroy();
4158 this.input.target = options.inputTarget;
4159 this.input.init();
4160 }
4161
4162 return this;
4163 };
4164 /**
4165 * @private
4166 * stop recognizing for this session.
4167 * This session will be discarded, when a new [input]start event is fired.
4168 * When forced, the recognizer cycle is stopped immediately.
4169 * @param {Boolean} [force]
4170 */
4171
4172
4173 _proto.stop = function stop(force) {
4174 this.session.stopped = force ? FORCED_STOP : STOP;
4175 };
4176 /**
4177 * @private
4178 * run the recognizers!
4179 * called by the inputHandler function on every movement of the pointers (touches)
4180 * it walks through all the recognizers and tries to detect the gesture that is being made
4181 * @param {Object} inputData
4182 */
4183
4184
4185 _proto.recognize = function recognize(inputData) {
4186 var session = this.session;
4187
4188 if (session.stopped) {
4189 return;
4190 } // run the touch-action polyfill
4191
4192
4193 this.touchAction.preventDefaults(inputData);
4194 var recognizer;
4195 var recognizers = this.recognizers; // this holds the recognizer that is being recognized.
4196 // so the recognizer's state needs to be BEGAN, CHANGED, ENDED or RECOGNIZED
4197 // if no recognizer is detecting a thing, it is set to `null`
4198
4199 var curRecognizer = session.curRecognizer; // reset when the last recognizer is recognized
4200 // or when we're in a new session
4201
4202 if (!curRecognizer || curRecognizer && curRecognizer.state & STATE_RECOGNIZED) {
4203 session.curRecognizer = null;
4204 curRecognizer = null;
4205 }
4206
4207 var i = 0;
4208
4209 while (i < recognizers.length) {
4210 recognizer = recognizers[i]; // find out if we are allowed try to recognize the input for this one.
4211 // 1. allow if the session is NOT forced stopped (see the .stop() method)
4212 // 2. allow if we still haven't recognized a gesture in this session, or the this recognizer is the one
4213 // that is being recognized.
4214 // 3. allow if the recognizer is allowed to run simultaneous with the current recognized recognizer.
4215 // this can be setup with the `recognizeWith()` method on the recognizer.
4216
4217 if (session.stopped !== FORCED_STOP && ( // 1
4218 !curRecognizer || recognizer === curRecognizer || // 2
4219 recognizer.canRecognizeWith(curRecognizer))) {
4220 // 3
4221 recognizer.recognize(inputData);
4222 } else {
4223 recognizer.reset();
4224 } // if the recognizer has been recognizing the input as a valid gesture, we want to store this one as the
4225 // current active recognizer. but only if we don't already have an active recognizer
4226
4227
4228 if (!curRecognizer && recognizer.state & (STATE_BEGAN | STATE_CHANGED | STATE_ENDED)) {
4229 session.curRecognizer = recognizer;
4230 curRecognizer = recognizer;
4231 }
4232
4233 i++;
4234 }
4235 };
4236 /**
4237 * @private
4238 * get a recognizer by its event name.
4239 * @param {Recognizer|String} recognizer
4240 * @returns {Recognizer|Null}
4241 */
4242
4243
4244 _proto.get = function get(recognizer) {
4245 if (recognizer instanceof Recognizer) {
4246 return recognizer;
4247 }
4248
4249 var recognizers = this.recognizers;
4250
4251 for (var i = 0; i < recognizers.length; i++) {
4252 if (recognizers[i].options.event === recognizer) {
4253 return recognizers[i];
4254 }
4255 }
4256
4257 return null;
4258 };
4259 /**
4260 * @private add a recognizer to the manager
4261 * existing recognizers with the same event name will be removed
4262 * @param {Recognizer} recognizer
4263 * @returns {Recognizer|Manager}
4264 */
4265
4266
4267 _proto.add = function add(recognizer) {
4268 if (invokeArrayArg(recognizer, "add", this)) {
4269 return this;
4270 } // remove existing
4271
4272
4273 var existing = this.get(recognizer.options.event);
4274
4275 if (existing) {
4276 this.remove(existing);
4277 }
4278
4279 this.recognizers.push(recognizer);
4280 recognizer.manager = this;
4281 this.touchAction.update();
4282 return recognizer;
4283 };
4284 /**
4285 * @private
4286 * remove a recognizer by name or instance
4287 * @param {Recognizer|String} recognizer
4288 * @returns {Manager}
4289 */
4290
4291
4292 _proto.remove = function remove(recognizer) {
4293 if (invokeArrayArg(recognizer, "remove", this)) {
4294 return this;
4295 }
4296
4297 var targetRecognizer = this.get(recognizer); // let's make sure this recognizer exists
4298
4299 if (recognizer) {
4300 var recognizers = this.recognizers;
4301 var index = inArray(recognizers, targetRecognizer);
4302
4303 if (index !== -1) {
4304 recognizers.splice(index, 1);
4305 this.touchAction.update();
4306 }
4307 }
4308
4309 return this;
4310 };
4311 /**
4312 * @private
4313 * bind event
4314 * @param {String} events
4315 * @param {Function} handler
4316 * @returns {EventEmitter} this
4317 */
4318
4319
4320 _proto.on = function on(events, handler) {
4321 if (events === undefined || handler === undefined) {
4322 return this;
4323 }
4324
4325 var handlers = this.handlers;
4326 each(splitStr(events), function (event) {
4327 handlers[event] = handlers[event] || [];
4328 handlers[event].push(handler);
4329 });
4330 return this;
4331 };
4332 /**
4333 * @private unbind event, leave emit blank to remove all handlers
4334 * @param {String} events
4335 * @param {Function} [handler]
4336 * @returns {EventEmitter} this
4337 */
4338
4339
4340 _proto.off = function off(events, handler) {
4341 if (events === undefined) {
4342 return this;
4343 }
4344
4345 var handlers = this.handlers;
4346 each(splitStr(events), function (event) {
4347 if (!handler) {
4348 delete handlers[event];
4349 } else {
4350 handlers[event] && handlers[event].splice(inArray(handlers[event], handler), 1);
4351 }
4352 });
4353 return this;
4354 };
4355 /**
4356 * @private emit event to the listeners
4357 * @param {String} event
4358 * @param {Object} data
4359 */
4360
4361
4362 _proto.emit = function emit(event, data) {
4363 // we also want to trigger dom events
4364 if (this.options.domEvents) {
4365 triggerDomEvent(event, data);
4366 } // no handlers, so skip it all
4367
4368
4369 var handlers = this.handlers[event] && this.handlers[event].slice();
4370
4371 if (!handlers || !handlers.length) {
4372 return;
4373 }
4374
4375 data.type = event;
4376
4377 data.preventDefault = function () {
4378 data.srcEvent.preventDefault();
4379 };
4380
4381 var i = 0;
4382
4383 while (i < handlers.length) {
4384 handlers[i](data);
4385 i++;
4386 }
4387 };
4388 /**
4389 * @private
4390 * destroy the manager and unbinds all events
4391 * it doesn't unbind dom events, that is the user own responsibility
4392 */
4393
4394
4395 _proto.destroy = function destroy() {
4396 this.element && toggleCssProps(this, false);
4397 this.handlers = {};
4398 this.session = {};
4399 this.input.destroy();
4400 this.element = null;
4401 };
4402
4403 return Manager;
4404 }();
4405
4406 var SINGLE_TOUCH_INPUT_MAP = {
4407 touchstart: INPUT_START,
4408 touchmove: INPUT_MOVE,
4409 touchend: INPUT_END,
4410 touchcancel: INPUT_CANCEL
4411 };
4412 var SINGLE_TOUCH_TARGET_EVENTS = 'touchstart';
4413 var SINGLE_TOUCH_WINDOW_EVENTS = 'touchstart touchmove touchend touchcancel';
4414 /**
4415 * @private
4416 * Touch events input
4417 * @constructor
4418 * @extends Input
4419 */
4420
4421 var SingleTouchInput =
4422 /*#__PURE__*/
4423 function (_Input) {
4424 _inheritsLoose(SingleTouchInput, _Input);
4425
4426 function SingleTouchInput() {
4427 var _this;
4428
4429 var proto = SingleTouchInput.prototype;
4430 proto.evTarget = SINGLE_TOUCH_TARGET_EVENTS;
4431 proto.evWin = SINGLE_TOUCH_WINDOW_EVENTS;
4432 _this = _Input.apply(this, arguments) || this;
4433 _this.started = false;
4434 return _this;
4435 }
4436
4437 var _proto = SingleTouchInput.prototype;
4438
4439 _proto.handler = function handler(ev) {
4440 var type = SINGLE_TOUCH_INPUT_MAP[ev.type]; // should we handle the touch events?
4441
4442 if (type === INPUT_START) {
4443 this.started = true;
4444 }
4445
4446 if (!this.started) {
4447 return;
4448 }
4449
4450 var touches = normalizeSingleTouches.call(this, ev, type); // when done, reset the started state
4451
4452 if (type & (INPUT_END | INPUT_CANCEL) && touches[0].length - touches[1].length === 0) {
4453 this.started = false;
4454 }
4455
4456 this.callback(this.manager, type, {
4457 pointers: touches[0],
4458 changedPointers: touches[1],
4459 pointerType: INPUT_TYPE_TOUCH,
4460 srcEvent: ev
4461 });
4462 };
4463
4464 return SingleTouchInput;
4465 }(Input);
4466
4467 function normalizeSingleTouches(ev, type) {
4468 var all = toArray$1(ev.touches);
4469 var changed = toArray$1(ev.changedTouches);
4470
4471 if (type & (INPUT_END | INPUT_CANCEL)) {
4472 all = uniqueArray(all.concat(changed), 'identifier', true);
4473 }
4474
4475 return [all, changed];
4476 }
4477
4478 /**
4479 * @private
4480 * wrap a method with a deprecation warning and stack trace
4481 * @param {Function} method
4482 * @param {String} name
4483 * @param {String} message
4484 * @returns {Function} A new function wrapping the supplied method.
4485 */
4486 function deprecate(method, name, message) {
4487 var deprecationMessage = "DEPRECATED METHOD: " + name + "\n" + message + " AT \n";
4488 return function () {
4489 var e = new Error('get-stack-trace');
4490 var stack = e && e.stack ? e.stack.replace(/^[^\(]+?[\n$]/gm, '').replace(/^\s+at\s+/gm, '').replace(/^Object.<anonymous>\s*\(/gm, '{anonymous}()@') : 'Unknown Stack Trace';
4491 var log = window.console && (window.console.warn || window.console.log);
4492
4493 if (log) {
4494 log.call(window.console, deprecationMessage, stack);
4495 }
4496
4497 return method.apply(this, arguments);
4498 };
4499 }
4500
4501 /**
4502 * @private
4503 * extend object.
4504 * means that properties in dest will be overwritten by the ones in src.
4505 * @param {Object} dest
4506 * @param {Object} src
4507 * @param {Boolean} [merge=false]
4508 * @returns {Object} dest
4509 */
4510
4511 var extend = deprecate(function (dest, src, merge) {
4512 var keys = Object.keys(src);
4513 var i = 0;
4514
4515 while (i < keys.length) {
4516 if (!merge || merge && dest[keys[i]] === undefined) {
4517 dest[keys[i]] = src[keys[i]];
4518 }
4519
4520 i++;
4521 }
4522
4523 return dest;
4524 }, 'extend', 'Use `assign`.');
4525
4526 /**
4527 * @private
4528 * merge the values from src in the dest.
4529 * means that properties that exist in dest will not be overwritten by src
4530 * @param {Object} dest
4531 * @param {Object} src
4532 * @returns {Object} dest
4533 */
4534
4535 var merge = deprecate(function (dest, src) {
4536 return extend(dest, src, true);
4537 }, 'merge', 'Use `assign`.');
4538
4539 /**
4540 * @private
4541 * simple class inheritance
4542 * @param {Function} child
4543 * @param {Function} base
4544 * @param {Object} [properties]
4545 */
4546
4547 function inherit(child, base, properties) {
4548 var baseP = base.prototype;
4549 var childP;
4550 childP = child.prototype = Object.create(baseP);
4551 childP.constructor = child;
4552 childP._super = baseP;
4553
4554 if (properties) {
4555 assign$1(childP, properties);
4556 }
4557 }
4558
4559 /**
4560 * @private
4561 * simple function bind
4562 * @param {Function} fn
4563 * @param {Object} context
4564 * @returns {Function}
4565 */
4566 function bindFn(fn, context) {
4567 return function boundFn() {
4568 return fn.apply(context, arguments);
4569 };
4570 }
4571
4572 /**
4573 * @private
4574 * Simple way to create a manager with a default set of recognizers.
4575 * @param {HTMLElement} element
4576 * @param {Object} [options]
4577 * @constructor
4578 */
4579
4580 var Hammer =
4581 /*#__PURE__*/
4582 function () {
4583 var Hammer =
4584 /**
4585 * @private
4586 * @const {string}
4587 */
4588 function Hammer(element, options) {
4589 if (options === void 0) {
4590 options = {};
4591 }
4592
4593 return new Manager(element, _extends({
4594 recognizers: preset.concat()
4595 }, options));
4596 };
4597
4598 Hammer.VERSION = "2.0.17-rc";
4599 Hammer.DIRECTION_ALL = DIRECTION_ALL;
4600 Hammer.DIRECTION_DOWN = DIRECTION_DOWN;
4601 Hammer.DIRECTION_LEFT = DIRECTION_LEFT;
4602 Hammer.DIRECTION_RIGHT = DIRECTION_RIGHT;
4603 Hammer.DIRECTION_UP = DIRECTION_UP;
4604 Hammer.DIRECTION_HORIZONTAL = DIRECTION_HORIZONTAL;
4605 Hammer.DIRECTION_VERTICAL = DIRECTION_VERTICAL;
4606 Hammer.DIRECTION_NONE = DIRECTION_NONE;
4607 Hammer.DIRECTION_DOWN = DIRECTION_DOWN;
4608 Hammer.INPUT_START = INPUT_START;
4609 Hammer.INPUT_MOVE = INPUT_MOVE;
4610 Hammer.INPUT_END = INPUT_END;
4611 Hammer.INPUT_CANCEL = INPUT_CANCEL;
4612 Hammer.STATE_POSSIBLE = STATE_POSSIBLE;
4613 Hammer.STATE_BEGAN = STATE_BEGAN;
4614 Hammer.STATE_CHANGED = STATE_CHANGED;
4615 Hammer.STATE_ENDED = STATE_ENDED;
4616 Hammer.STATE_RECOGNIZED = STATE_RECOGNIZED;
4617 Hammer.STATE_CANCELLED = STATE_CANCELLED;
4618 Hammer.STATE_FAILED = STATE_FAILED;
4619 Hammer.Manager = Manager;
4620 Hammer.Input = Input;
4621 Hammer.TouchAction = TouchAction;
4622 Hammer.TouchInput = TouchInput;
4623 Hammer.MouseInput = MouseInput;
4624 Hammer.PointerEventInput = PointerEventInput;
4625 Hammer.TouchMouseInput = TouchMouseInput;
4626 Hammer.SingleTouchInput = SingleTouchInput;
4627 Hammer.Recognizer = Recognizer;
4628 Hammer.AttrRecognizer = AttrRecognizer;
4629 Hammer.Tap = TapRecognizer;
4630 Hammer.Pan = PanRecognizer;
4631 Hammer.Swipe = SwipeRecognizer;
4632 Hammer.Pinch = PinchRecognizer;
4633 Hammer.Rotate = RotateRecognizer;
4634 Hammer.Press = PressRecognizer;
4635 Hammer.on = addEventListeners;
4636 Hammer.off = removeEventListeners;
4637 Hammer.each = each;
4638 Hammer.merge = merge;
4639 Hammer.extend = extend;
4640 Hammer.bindFn = bindFn;
4641 Hammer.assign = assign$1;
4642 Hammer.inherit = inherit;
4643 Hammer.bindFn = bindFn;
4644 Hammer.prefixed = prefixed;
4645 Hammer.toArray = toArray$1;
4646 Hammer.inArray = inArray;
4647 Hammer.uniqueArray = uniqueArray;
4648 Hammer.splitStr = splitStr;
4649 Hammer.boolOrFn = boolOrFn;
4650 Hammer.hasParent = hasParent;
4651 Hammer.addEventListeners = addEventListeners;
4652 Hammer.removeEventListeners = removeEventListeners;
4653 Hammer.defaults = assign$1({}, defaults, {
4654 preset: preset
4655 });
4656 return Hammer;
4657 }();
4658
4659 /*
4660 Copyright (c) 2015 NAVER Corp.
4661 name: @egjs/agent
4662 license: MIT
4663 author: NAVER Corp.
4664 repository: git+https://github.com/naver/agent.git
4665 version: 2.2.1
4666 */
4667 function some(arr, callback) {
4668 var length = arr.length;
4669
4670 for (var i = 0; i < length; ++i) {
4671 if (callback(arr[i], i)) {
4672 return true;
4673 }
4674 }
4675
4676 return false;
4677 }
4678 function find(arr, callback) {
4679 var length = arr.length;
4680
4681 for (var i = 0; i < length; ++i) {
4682 if (callback(arr[i], i)) {
4683 return arr[i];
4684 }
4685 }
4686
4687 return null;
4688 }
4689 function getUserAgent(agent) {
4690 var userAgent = agent;
4691
4692 if (typeof userAgent === "undefined") {
4693 if (typeof navigator === "undefined" || !navigator) {
4694 return "";
4695 }
4696
4697 userAgent = navigator.userAgent || "";
4698 }
4699
4700 return userAgent.toLowerCase();
4701 }
4702 function execRegExp(pattern, text) {
4703 try {
4704 return new RegExp(pattern, "g").exec(text);
4705 } catch (e) {
4706 return null;
4707 }
4708 }
4709 function hasUserAgentData() {
4710 if (typeof navigator === "undefined" || !navigator || !navigator.userAgentData) {
4711 return false;
4712 }
4713
4714 var userAgentData = navigator.userAgentData;
4715 var brands = userAgentData.brands || userAgentData.uaList;
4716 return !!(brands && brands.length);
4717 }
4718 function findVersion(versionTest, userAgent) {
4719 var result = execRegExp("(" + versionTest + ")((?:\\/|\\s|:)([0-9|\\.|_]+))?", userAgent);
4720 return result ? result[3] : "";
4721 }
4722 function convertVersion(text) {
4723 return text.replace(/_/g, ".");
4724 }
4725 function findPreset(presets, userAgent) {
4726 var userPreset = null;
4727 var version = "-1";
4728 some(presets, function (preset) {
4729 var result = execRegExp("(" + preset.test + ")((?:\\/|\\s|:)([0-9|\\.|_]+))?", userAgent);
4730
4731 if (!result || preset.brand) {
4732 return false;
4733 }
4734
4735 userPreset = preset;
4736 version = result[3] || "-1";
4737
4738 if (preset.versionAlias) {
4739 version = preset.versionAlias;
4740 } else if (preset.versionTest) {
4741 version = findVersion(preset.versionTest.toLowerCase(), userAgent) || version;
4742 }
4743
4744 version = convertVersion(version);
4745 return true;
4746 });
4747 return {
4748 preset: userPreset,
4749 version: version
4750 };
4751 }
4752 function findBrand(brands, preset) {
4753 return find(brands, function (_a) {
4754 var brand = _a.brand;
4755 return execRegExp("" + preset.test, brand.toLowerCase());
4756 });
4757 }
4758
4759 var BROWSER_PRESETS = [{
4760 test: "phantomjs",
4761 id: "phantomjs"
4762 }, {
4763 test: "whale",
4764 id: "whale"
4765 }, {
4766 test: "edgios|edge|edg",
4767 id: "edge"
4768 }, {
4769 test: "msie|trident|windows phone",
4770 id: "ie",
4771 versionTest: "iemobile|msie|rv"
4772 }, {
4773 test: "miuibrowser",
4774 id: "miui browser"
4775 }, {
4776 test: "samsungbrowser",
4777 id: "samsung internet"
4778 }, {
4779 test: "samsung",
4780 id: "samsung internet",
4781 versionTest: "version"
4782 }, {
4783 test: "chrome|crios",
4784 id: "chrome"
4785 }, {
4786 test: "firefox|fxios",
4787 id: "firefox"
4788 }, {
4789 test: "android",
4790 id: "android browser",
4791 versionTest: "version"
4792 }, {
4793 test: "safari|iphone|ipad|ipod",
4794 id: "safari",
4795 versionTest: "version"
4796 }]; // chromium's engine(blink) is based on applewebkit 537.36.
4797
4798 var CHROMIUM_PRESETS = [{
4799 test: "(?=.*applewebkit/(53[0-7]|5[0-2]|[0-4]))(?=.*\\schrome)",
4800 id: "chrome"
4801 }, {
4802 test: "chromium",
4803 id: "chrome"
4804 }, {
4805 test: "whale",
4806 id: "chrome",
4807 brand: true
4808 }];
4809 var WEBKIT_PRESETS = [{
4810 test: "applewebkit",
4811 id: "webkit"
4812 }];
4813 var WEBVIEW_PRESETS = [{
4814 test: "(?=(iphone|ipad))(?!(.*version))",
4815 id: "webview"
4816 }, {
4817 test: "(?=(android|iphone|ipad))(?=.*(naver|daum|; wv))",
4818 id: "webview"
4819 }, {
4820 // test webview
4821 test: "webview",
4822 id: "webview"
4823 }];
4824 var OS_PRESETS = [{
4825 test: "windows phone",
4826 id: "windows phone"
4827 }, {
4828 test: "windows 2000",
4829 id: "window",
4830 versionAlias: "5.0"
4831 }, {
4832 test: "windows nt",
4833 id: "window"
4834 }, {
4835 test: "iphone|ipad|ipod",
4836 id: "ios",
4837 versionTest: "iphone os|cpu os"
4838 }, {
4839 test: "mac os x",
4840 id: "mac"
4841 }, {
4842 test: "android",
4843 id: "android"
4844 }, {
4845 test: "tizen",
4846 id: "tizen"
4847 }, {
4848 test: "webos|web0s",
4849 id: "webos"
4850 }];
4851
4852 function parseUserAgentData(osData) {
4853 var userAgentData = navigator.userAgentData;
4854 var brands = (userAgentData.uaList || userAgentData.brands).slice();
4855 var isMobile = userAgentData.mobile || false;
4856 var firstBrand = brands[0];
4857 var browser = {
4858 name: firstBrand.brand,
4859 version: firstBrand.version,
4860 majorVersion: -1,
4861 webkit: false,
4862 webview: some(WEBVIEW_PRESETS, function (preset) {
4863 return findBrand(brands, preset);
4864 }),
4865 chromium: some(CHROMIUM_PRESETS, function (preset) {
4866 return findBrand(brands, preset);
4867 })
4868 };
4869 var os = {
4870 name: "unknown",
4871 version: "-1",
4872 majorVersion: -1
4873 };
4874 browser.webkit = !browser.chromium && some(WEBKIT_PRESETS, function (preset) {
4875 return findBrand(brands, preset);
4876 });
4877
4878 if (osData) {
4879 var platform_1 = osData.platform.toLowerCase();
4880 var result = find(OS_PRESETS, function (preset) {
4881 return new RegExp("" + preset.test, "g").exec(platform_1);
4882 });
4883 os.name = result ? result.id : platform_1;
4884 os.version = osData.platformVersion;
4885 }
4886
4887 some(BROWSER_PRESETS, function (preset) {
4888 var result = findBrand(brands, preset);
4889
4890 if (!result) {
4891 return false;
4892 }
4893
4894 browser.name = preset.id;
4895 browser.version = osData ? osData.uaFullVersion : result.version;
4896 return true;
4897 });
4898
4899 if (navigator.platform === "Linux armv8l") {
4900 os.name = "android";
4901 } else if (browser.webkit) {
4902 os.name = isMobile ? "ios" : "mac";
4903 }
4904
4905 if (os.name === "ios" && browser.webview) {
4906 browser.version = "-1";
4907 }
4908
4909 os.version = convertVersion(os.version);
4910 browser.version = convertVersion(browser.version);
4911 os.majorVersion = parseInt(os.version, 10);
4912 browser.majorVersion = parseInt(browser.version, 10);
4913 return {
4914 browser: browser,
4915 os: os,
4916 isMobile: isMobile,
4917 isHints: true
4918 };
4919 }
4920
4921 function parseUserAgent(userAgent) {
4922 var nextAgent = getUserAgent(userAgent);
4923 var isMobile = !!/mobi/g.exec(nextAgent);
4924 var browser = {
4925 name: "unknown",
4926 version: "-1",
4927 majorVersion: -1,
4928 webview: !!findPreset(WEBVIEW_PRESETS, nextAgent).preset,
4929 chromium: !!findPreset(CHROMIUM_PRESETS, nextAgent).preset,
4930 webkit: false
4931 };
4932 var os = {
4933 name: "unknown",
4934 version: "-1",
4935 majorVersion: -1
4936 };
4937
4938 var _a = findPreset(BROWSER_PRESETS, nextAgent),
4939 browserPreset = _a.preset,
4940 browserVersion = _a.version;
4941
4942 var _b = findPreset(OS_PRESETS, nextAgent),
4943 osPreset = _b.preset,
4944 osVersion = _b.version;
4945
4946 browser.webkit = !browser.chromium && !!findPreset(WEBKIT_PRESETS, nextAgent).preset;
4947
4948 if (osPreset) {
4949 os.name = osPreset.id;
4950 os.version = osVersion;
4951 os.majorVersion = parseInt(osVersion, 10);
4952 }
4953
4954 if (browserPreset) {
4955 browser.name = browserPreset.id;
4956 browser.version = browserVersion;
4957
4958 if (browser.webview && os.name === "ios" && browser.name !== "safari") {
4959 browser.webview = false;
4960 }
4961 }
4962
4963 browser.majorVersion = parseInt(browser.version, 10);
4964 return {
4965 browser: browser,
4966 os: os,
4967 isMobile: isMobile,
4968 isHints: false
4969 };
4970 }
4971 /**
4972 * Extracts browser and operating system information from the user agent string.
4973 * @ko 유저 에이전트 문자열에서 브라우저와 운영체제 정보를 추출한다.
4974 * @function eg.agent#agent
4975 * @param - user agent string to parse <ko>파싱할 유저에이전트 문자열</ko>
4976 * @return - agent Info <ko> 에이전트 정보 </ko>
4977 * @example
4978 import agent from "@egjs/agent";
4979 // eg.agent();
4980 const { os, browser, isMobile } = agent();
4981 */
4982
4983 function agent(userAgent) {
4984 if (typeof userAgent === "undefined" && hasUserAgentData()) {
4985 return parseUserAgentData();
4986 } else {
4987 return parseUserAgent(userAgent);
4988 }
4989 }
4990
4991 // export const DIRECTION_NONE = 1;
4992 var IOS_EDGE_THRESHOLD = 30;
4993 var IS_IOS_SAFARI = "ontouchstart" in win && agent().browser.name === "safari";
4994 var TRANSFORM = function () {
4995 if (typeof document === "undefined") {
4996 return "";
4997 }
4998
4999 var bodyStyle = (document.head || document.getElementsByTagName("head")[0]).style;
5000 var target = ["transform", "webkitTransform", "msTransform", "mozTransform"];
5001
5002 for (var i = 0, len = target.length; i < len; i++) {
5003 if (target[i] in bodyStyle) {
5004 return target[i];
5005 }
5006 }
5007
5008 return "";
5009 }();
5010
5011 /**
5012 * @typedef {Object} AxisOption The Axis information. The key of the axis specifies the name to use as the logical virtual coordinate system.
5013 * @ko 축 정보. 축의 키는 논리적인 가상 좌표계로 사용할 이름을 지정한다.
5014 * @property {Number[]} [range] The coordinate of range <ko>좌표 범위</ko>
5015 * @property {Number} [range.0=0] The coordinate of the minimum <ko>최소 좌표</ko>
5016 * @property {Number} [range.1=0] The coordinate of the maximum <ko>최대 좌표</ko>
5017 * @property {Number[]} [bounce] The size of bouncing area. The coordinates can exceed the coordinate area as much as the bouncing area based on user action. If the coordinates does not exceed the bouncing area when an element is dragged, the coordinates where bouncing effects are applied are retuned back into the coordinate area<ko>바운스 영역의 크기. 사용자의 동작에 따라 좌표가 좌표 영역을 넘어 바운스 영역의 크기만큼 더 이동할 수 있다. 사용자가 끌어다 놓는 동작을 했을 때 좌표가 바운스 영역에 있으면, 바운스 효과가 적용된 좌표가 다시 좌표 영역 안으로 들어온다</ko>
5018 * @property {Number} [bounce.0=0] The size of coordinate of the minimum area <ko>최소 좌표 바운스 영역의 크기</ko>
5019 * @property {Number} [bounce.1=0] The size of coordinate of the maximum area <ko>최대 좌표 바운스 영역의 크기</ko>
5020 * @property {Boolean[]} [circular] Indicates whether a circular element is available. If it is set to "true" and an element is dragged outside the coordinate area, the element will appear on the other side.<ko>순환 여부. 'true'로 설정한 방향의 좌표 영역 밖으로 엘리먼트가 이동하면 반대 방향에서 엘리먼트가 나타난다</ko>
5021 * @property {Boolean} [circular.0=false] Indicates whether to circulate to the coordinate of the minimum <ko>최소 좌표 방향의 순환 여부</ko>
5022 * @property {Boolean} [circular.1=false] Indicates whether to circulate to the coordinate of the maximum <ko>최대 좌표 방향의 순환 여부</ko>
5023 **/
5024
5025 /**
5026 * @typedef {Object} AxesOption The option object of the eg.Axes module
5027 * @ko eg.Axes 모듈의 옵션 객체
5028 * @property {Function} [easing=easing.easeOutCubic] The easing function to apply to an animation <ko>애니메이션에 적용할 easing 함수</ko>
5029 * @property {Number} [maximumDuration=Infinity] Maximum duration of the animation <ko>가속도에 의해 애니메이션이 동작할 때의 최대 좌표 이동 시간</ko>
5030 * @property {Number} [minimumDuration=0] Minimum duration of the animation <ko>가속도에 의해 애니메이션이 동작할 때의 최소 좌표 이동 시간</ko>
5031 * @property {Number} [deceleration=0.0006] Deceleration of the animation where acceleration is manually enabled by user. A higher value indicates shorter running time. <ko>사용자의 동작으로 가속도가 적용된 애니메이션의 감속도. 값이 높을수록 애니메이션 실행 시간이 짧아진다</ko>
5032 * @property {Boolean} [interruptable=true] Indicates whether an animation is interruptible.<br>- true: It can be paused or stopped by user action or the API.<br>- false: It cannot be paused or stopped by user action or the API while it is running.<ko>진행 중인 애니메이션 중지 가능 여부.<br>- true: 사용자의 동작이나 API로 애니메이션을 중지할 수 있다.<br>- false: 애니메이션이 진행 중일 때는 사용자의 동작이나 API가 적용되지 않는다</ko>
5033 * @property {Number} [round = null] Rounding unit. For example, 0.1 rounds to 0.1 decimal point(6.1234 => 6.1), 5 rounds to 5 (93 => 95) <br>[Details](https://github.com/naver/egjs-axes/wiki/round-option)<ko>반올림 단위. 예를 들어 0.1 은 소숫점 0.1 까지 반올림(6.1234 => 6.1), 5 는 5 단위로 반올림(93 => 95).<br>[상세내용](https://github.com/naver/egjs-axes/wiki/round-option)</ko>
5034 **/
5035
5036 /**
5037 * @class eg.Axes
5038 * @classdesc A module used to change the information of user action entered by various input devices such as touch screen or mouse into the logical virtual coordinates. You can easily create a UI that responds to user actions.
5039 * @ko 터치 입력 장치나 마우스와 같은 다양한 입력 장치를 통해 전달 받은 사용자의 동작을 논리적인 가상 좌표로 변경하는 모듈이다. 사용자 동작에 반응하는 UI를 손쉽게 만들수 있다.
5040 * @extends eg.Component
5041 *
5042 * @param {Object.<string, AxisOption>} axis Axis information managed by eg.Axes. The key of the axis specifies the name to use as the logical virtual coordinate system. <ko>eg.Axes가 관리하는 축 정보. 축의 키는 논리적인 가상 좌표계로 사용할 이름을 지정한다.</ko>
5043 * @param {AxesOption} [options] The option object of the eg.Axes module<ko>eg.Axes 모듈의 옵션 객체</ko>
5044 * @param {Object.<string, number>} [startPos] The coordinates to be moved when creating an instance. not triggering change event.<ko>인스턴스 생성시 이동할 좌표, change 이벤트는 발생하지 않음.</ko>
5045 *
5046 * @support {"ie": "10+", "ch" : "latest", "ff" : "latest", "sf" : "latest", "edge" : "latest", "ios" : "7+", "an" : "2.3+ (except 3.x)"}
5047 * @example
5048 *
5049 * // 1. Initialize eg.Axes
5050 * const axes = new eg.Axes({
5051 * something1: {
5052 * range: [0, 150],
5053 * bounce: 50
5054 * },
5055 * something2: {
5056 * range: [0, 200],
5057 * bounce: 100
5058 * },
5059 * somethingN: {
5060 * range: [1, 10],
5061 * }
5062 * }, {
5063 * deceleration : 0.0024
5064 * });
5065 *
5066 * // 2. attach event handler
5067 * axes.on({
5068 * "hold" : function(evt) {
5069 * },
5070 * "release" : function(evt) {
5071 * },
5072 * "animationStart" : function(evt) {
5073 * },
5074 * "animationEnd" : function(evt) {
5075 * },
5076 * "change" : function(evt) {
5077 * }
5078 * });
5079 *
5080 * // 3. Initialize inputTypes
5081 * const panInputArea = new eg.Axes.PanInput("#area", {
5082 * scale: [0.5, 1]
5083 * });
5084 * const panInputHmove = new eg.Axes.PanInput("#hmove");
5085 * const panInputVmove = new eg.Axes.PanInput("#vmove");
5086 * const pinchInputArea = new eg.Axes.PinchInput("#area", {
5087 * scale: 1.5
5088 * });
5089 *
5090 * // 4. Connect eg.Axes and InputTypes
5091 * // [PanInput] When the mouse or touchscreen is down and moved.
5092 * // Connect the 'something2' axis to the mouse or touchscreen x position and
5093 * // connect the 'somethingN' axis to the mouse or touchscreen y position.
5094 * axes.connect(["something2", "somethingN"], panInputArea); // or axes.connect("something2 somethingN", panInputArea);
5095 *
5096 * // Connect only one 'something1' axis to the mouse or touchscreen x position.
5097 * axes.connect(["something1"], panInputHmove); // or axes.connect("something1", panInputHmove);
5098 *
5099 * // Connect only one 'something2' axis to the mouse or touchscreen y position.
5100 * axes.connect(["", "something2"], panInputVmove); // or axes.connect(" something2", panInputVmove);
5101 *
5102 * // [PinchInput] Connect 'something2' axis when two pointers are moving toward (zoom-in) or away from each other (zoom-out).
5103 * axes.connect("something2", pinchInputArea);
5104 */
5105
5106 var Axes =
5107 /*#__PURE__*/
5108 function (_super) {
5109 __extends(Axes, _super);
5110
5111 function Axes(axis, options, startPos) {
5112 if (axis === void 0) {
5113 axis = {};
5114 }
5115
5116 if (options === void 0) {
5117 options = {};
5118 }
5119
5120 var _this = _super.call(this) || this;
5121
5122 _this.axis = axis;
5123 _this._inputs = [];
5124 _this.options = __assign({
5125 easing: function easeOutCubic(x) {
5126 return 1 - Math.pow(1 - x, 3);
5127 },
5128 interruptable: true,
5129 maximumDuration: Infinity,
5130 minimumDuration: 0,
5131 deceleration: 0.0006,
5132 round: null
5133 }, options);
5134 _this.itm = new InterruptManager(_this.options);
5135 _this.axm = new AxisManager(_this.axis, _this.options);
5136 _this.em = new EventManager(_this);
5137 _this.am = new AnimationManager(_this);
5138 _this.io = new InputObserver(_this);
5139
5140 _this.em.setAnimationManager(_this.am);
5141
5142 startPos && _this.em.triggerChange(startPos);
5143 return _this;
5144 }
5145 /**
5146 * Connect the axis of eg.Axes to the inputType.
5147 * @ko eg.Axes의 축과 inputType을 연결한다
5148 * @method eg.Axes#connect
5149 * @param {(String[]|String)} axes The name of the axis to associate with inputType <ko>inputType과 연결할 축의 이름</ko>
5150 * @param {Object} inputType The inputType instance to associate with the axis of eg.Axes <ko>eg.Axes의 축과 연결할 inputType 인스턴스<ko>
5151 * @return {eg.Axes} An instance of a module itself <ko>모듈 자신의 인스턴스</ko>
5152 * @example
5153 * const axes = new eg.Axes({
5154 * "x": {
5155 * range: [0, 100]
5156 * },
5157 * "xOther": {
5158 * range: [-100, 100]
5159 * }
5160 * });
5161 *
5162 * axes.connect("x", new eg.Axes.PanInput("#area1"))
5163 * .connect("x xOther", new eg.Axes.PanInput("#area2"))
5164 * .connect(" xOther", new eg.Axes.PanInput("#area3"))
5165 * .connect(["x"], new eg.Axes.PanInput("#area4"))
5166 * .connect(["xOther", "x"], new eg.Axes.PanInput("#area5"))
5167 * .connect(["", "xOther"], new eg.Axes.PanInput("#area6"));
5168 */
5169
5170
5171 var __proto = Axes.prototype;
5172
5173 __proto.connect = function (axes, inputType) {
5174 var mapped;
5175
5176 if (typeof axes === "string") {
5177 mapped = axes.split(" ");
5178 } else {
5179 mapped = axes.concat();
5180 } // check same instance
5181
5182
5183 if (~this._inputs.indexOf(inputType)) {
5184 this.disconnect(inputType);
5185 } // check same element in hammer type for share
5186
5187
5188 if ("hammer" in inputType) {
5189 var targets = this._inputs.filter(function (v) {
5190 return v.hammer && v.element === inputType.element;
5191 });
5192
5193 if (targets.length) {
5194 inputType.hammer = targets[0].hammer;
5195 }
5196 }
5197
5198 inputType.mapAxes(mapped);
5199 inputType.connect(this.io);
5200
5201 this._inputs.push(inputType);
5202
5203 return this;
5204 };
5205 /**
5206 * Disconnect the axis of eg.Axes from the inputType.
5207 * @ko eg.Axes의 축과 inputType의 연결을 끊는다.
5208 * @method eg.Axes#disconnect
5209 * @param {Object} [inputType] An inputType instance associated with the axis of eg.Axes <ko>eg.Axes의 축과 연결한 inputType 인스턴스<ko>
5210 * @return {eg.Axes} An instance of a module itself <ko>모듈 자신의 인스턴스</ko>
5211 * @example
5212 * const axes = new eg.Axes({
5213 * "x": {
5214 * range: [0, 100]
5215 * },
5216 * "xOther": {
5217 * range: [-100, 100]
5218 * }
5219 * });
5220 *
5221 * const input1 = new eg.Axes.PanInput("#area1");
5222 * const input2 = new eg.Axes.PanInput("#area2");
5223 * const input3 = new eg.Axes.PanInput("#area3");
5224 *
5225 * axes.connect("x", input1);
5226 * .connect("x xOther", input2)
5227 * .connect(["xOther", "x"], input3);
5228 *
5229 * axes.disconnect(input1); // disconnects input1
5230 * axes.disconnect(); // disconnects all of them
5231 */
5232
5233
5234 __proto.disconnect = function (inputType) {
5235 if (inputType) {
5236 var index = this._inputs.indexOf(inputType);
5237
5238 if (index >= 0) {
5239 this._inputs[index].disconnect();
5240
5241 this._inputs.splice(index, 1);
5242 }
5243 } else {
5244 this._inputs.forEach(function (v) {
5245 return v.disconnect();
5246 });
5247
5248 this._inputs = [];
5249 }
5250
5251 return this;
5252 };
5253 /**
5254 * Returns the current position of the coordinates.
5255 * @ko 좌표의 현재 위치를 반환한다
5256 * @method eg.Axes#get
5257 * @param {Object} [axes] The names of the axis <ko>축 이름들</ko>
5258 * @return {Object.<string, number>} Axis coordinate information <ko>축 좌표 정보</ko>
5259 * @example
5260 * const axes = new eg.Axes({
5261 * "x": {
5262 * range: [0, 100]
5263 * },
5264 * "xOther": {
5265 * range: [-100, 100]
5266 * },
5267 * "zoom": {
5268 * range: [50, 30]
5269 * }
5270 * });
5271 *
5272 * axes.get(); // {"x": 0, "xOther": -100, "zoom": 50}
5273 * axes.get(["x", "zoom"]); // {"x": 0, "zoom": 50}
5274 */
5275
5276
5277 __proto.get = function (axes) {
5278 return this.axm.get(axes);
5279 };
5280 /**
5281 * Moves an axis to specific coordinates.
5282 * @ko 좌표를 이동한다.
5283 * @method eg.Axes#setTo
5284 * @param {Object.<string, number>} pos The coordinate to move to <ko>이동할 좌표</ko>
5285 * @param {Number} [duration=0] Duration of the animation (unit: ms) <ko>애니메이션 진행 시간(단위: ms)</ko>
5286 * @return {eg.Axes} An instance of a module itself <ko>모듈 자신의 인스턴스</ko>
5287 * @example
5288 * const axes = new eg.Axes({
5289 * "x": {
5290 * range: [0, 100]
5291 * },
5292 * "xOther": {
5293 * range: [-100, 100]
5294 * },
5295 * "zoom": {
5296 * range: [50, 30]
5297 * }
5298 * });
5299 *
5300 * axes.setTo({"x": 30, "zoom": 60});
5301 * axes.get(); // {"x": 30, "xOther": -100, "zoom": 60}
5302 *
5303 * axes.setTo({"x": 100, "xOther": 60}, 1000); // animatation
5304 *
5305 * // after 1000 ms
5306 * axes.get(); // {"x": 100, "xOther": 60, "zoom": 60}
5307 */
5308
5309
5310 __proto.setTo = function (pos, duration) {
5311 if (duration === void 0) {
5312 duration = 0;
5313 }
5314
5315 this.am.setTo(pos, duration);
5316 return this;
5317 };
5318 /**
5319 * Moves an axis from the current coordinates to specific coordinates.
5320 * @ko 현재 좌표를 기준으로 좌표를 이동한다.
5321 * @method eg.Axes#setBy
5322 * @param {Object.<string, number>} pos The coordinate to move to <ko>이동할 좌표</ko>
5323 * @param {Number} [duration=0] Duration of the animation (unit: ms) <ko>애니메이션 진행 시간(단위: ms)</ko>
5324 * @return {eg.Axes} An instance of a module itself <ko>모듈 자신의 인스턴스</ko>
5325 * @example
5326 * const axes = new eg.Axes({
5327 * "x": {
5328 * range: [0, 100]
5329 * },
5330 * "xOther": {
5331 * range: [-100, 100]
5332 * },
5333 * "zoom": {
5334 * range: [50, 30]
5335 * }
5336 * });
5337 *
5338 * axes.setBy({"x": 30, "zoom": 10});
5339 * axes.get(); // {"x": 30, "xOther": -100, "zoom": 60}
5340 *
5341 * axes.setBy({"x": 70, "xOther": 60}, 1000); // animatation
5342 *
5343 * // after 1000 ms
5344 * axes.get(); // {"x": 100, "xOther": -40, "zoom": 60}
5345 */
5346
5347
5348 __proto.setBy = function (pos, duration) {
5349 if (duration === void 0) {
5350 duration = 0;
5351 }
5352
5353 this.am.setBy(pos, duration);
5354 return this;
5355 };
5356 /**
5357 * Returns whether there is a coordinate in the bounce area of ​​the target axis.
5358 * @ko 대상 축 중 bounce영역에 좌표가 존재하는지를 반환한다
5359 * @method eg.Axes#isBounceArea
5360 * @param {Object} [axes] The names of the axis <ko>축 이름들</ko>
5361 * @return {Boolen} Whether the bounce area exists. <ko>bounce 영역 존재 여부</ko>
5362 * @example
5363 * const axes = new eg.Axes({
5364 * "x": {
5365 * range: [0, 100]
5366 * },
5367 * "xOther": {
5368 * range: [-100, 100]
5369 * },
5370 * "zoom": {
5371 * range: [50, 30]
5372 * }
5373 * });
5374 *
5375 * axes.isBounceArea(["x"]);
5376 * axes.isBounceArea(["x", "zoom"]);
5377 * axes.isBounceArea();
5378 */
5379
5380
5381 __proto.isBounceArea = function (axes) {
5382 return this.axm.isOutside(axes);
5383 };
5384 /**
5385 * Destroys properties, and events used in a module and disconnect all connections to inputTypes.
5386 * @ko 모듈에 사용한 속성, 이벤트를 해제한다. 모든 inputType과의 연결을 끊는다.
5387 * @method eg.Axes#destroy
5388 */
5389
5390
5391 __proto.destroy = function () {
5392 this.disconnect();
5393 this.em.destroy();
5394 };
5395 /**
5396 * Version info string
5397 * @ko 버전정보 문자열
5398 * @name VERSION
5399 * @static
5400 * @type {String}
5401 * @example
5402 * eg.Axes.VERSION; // ex) 3.3.3
5403 * @memberof eg.Axes
5404 */
5405
5406
5407 Axes.VERSION = "2.8.0";
5408 /**
5409 * @name eg.Axes.TRANSFORM
5410 * @desc Returns the transform attribute with CSS vendor prefixes.
5411 * @ko CSS vendor prefixes를 붙인 transform 속성을 반환한다.
5412 *
5413 * @constant
5414 * @type {String}
5415 * @example
5416 * eg.Axes.TRANSFORM; // "transform" or "webkitTransform"
5417 */
5418
5419 Axes.TRANSFORM = TRANSFORM;
5420 /**
5421 * @name eg.Axes.DIRECTION_NONE
5422 * @constant
5423 * @type {Number}
5424 */
5425
5426 Axes.DIRECTION_NONE = DIRECTION_NONE;
5427 /**
5428 * @name eg.Axes.DIRECTION_LEFT
5429 * @constant
5430 * @type {Number}
5431 */
5432
5433 Axes.DIRECTION_LEFT = DIRECTION_LEFT;
5434 /**
5435 * @name eg.Axes.DIRECTION_RIGHT
5436 * @constant
5437 * @type {Number}
5438 */
5439
5440 Axes.DIRECTION_RIGHT = DIRECTION_RIGHT;
5441 /**
5442 * @name eg.Axes.DIRECTION_UP
5443 * @constant
5444 * @type {Number}
5445 */
5446
5447 Axes.DIRECTION_UP = DIRECTION_UP;
5448 /**
5449 * @name eg.Axes.DIRECTION_DOWN
5450 * @constant
5451 * @type {Number}
5452 */
5453
5454 Axes.DIRECTION_DOWN = DIRECTION_DOWN;
5455 /**
5456 * @name eg.Axes.DIRECTION_HORIZONTAL
5457 * @constant
5458 * @type {Number}
5459 */
5460
5461 Axes.DIRECTION_HORIZONTAL = DIRECTION_HORIZONTAL;
5462 /**
5463 * @name eg.Axes.DIRECTION_VERTICAL
5464 * @constant
5465 * @type {Number}
5466 */
5467
5468 Axes.DIRECTION_VERTICAL = DIRECTION_VERTICAL;
5469 /**
5470 * @name eg.Axes.DIRECTION_ALL
5471 * @constant
5472 * @type {Number}
5473 */
5474
5475 Axes.DIRECTION_ALL = DIRECTION_ALL;
5476 return Axes;
5477 }(Component);
5478
5479 var SUPPORT_POINTER_EVENTS$1 = "PointerEvent" in win || "MSPointerEvent" in win;
5480 var SUPPORT_TOUCH$1 = ("ontouchstart" in win);
5481 var UNIQUEKEY = "_EGJS_AXES_INPUTTYPE_";
5482 function toAxis(source, offset) {
5483 return offset.reduce(function (acc, v, i) {
5484 if (source[i]) {
5485 acc[source[i]] = v;
5486 }
5487
5488 return acc;
5489 }, {});
5490 }
5491 function createHammer(element, options) {
5492 try {
5493 // create Hammer
5494 return new Manager(element, __assign({}, options));
5495 } catch (e) {
5496 return null;
5497 }
5498 }
5499 function convertInputType(inputType) {
5500 if (inputType === void 0) {
5501 inputType = [];
5502 }
5503
5504 var hasTouch = false;
5505 var hasMouse = false;
5506 var hasPointer = false;
5507 inputType.forEach(function (v) {
5508 switch (v) {
5509 case "mouse":
5510 hasMouse = true;
5511 break;
5512
5513 case "touch":
5514 hasTouch = SUPPORT_TOUCH$1;
5515 break;
5516
5517 case "pointer":
5518 hasPointer = SUPPORT_POINTER_EVENTS$1;
5519 // no default
5520 }
5521 });
5522
5523 if (hasPointer) {
5524 return PointerEventInput;
5525 } else if (hasTouch && hasMouse) {
5526 return TouchMouseInput;
5527 } else if (hasTouch) {
5528 return TouchInput;
5529 } else if (hasMouse) {
5530 return MouseInput;
5531 }
5532
5533 return null;
5534 }
5535
5536 function getDirectionByAngle(angle, thresholdAngle) {
5537 if (thresholdAngle < 0 || thresholdAngle > 90) {
5538 return DIRECTION_NONE;
5539 }
5540
5541 var toAngle = Math.abs(angle);
5542 return toAngle > thresholdAngle && toAngle < 180 - thresholdAngle ? DIRECTION_VERTICAL : DIRECTION_HORIZONTAL;
5543 }
5544 function getNextOffset(speeds, deceleration) {
5545 var normalSpeed = Math.sqrt(speeds[0] * speeds[0] + speeds[1] * speeds[1]);
5546 var duration = Math.abs(normalSpeed / -deceleration);
5547 return [speeds[0] / 2 * duration, speeds[1] / 2 * duration];
5548 }
5549 function useDirection(checkType, direction, userDirection) {
5550 if (userDirection) {
5551 return !!(direction === DIRECTION_ALL || direction & checkType && userDirection & checkType);
5552 } else {
5553 return !!(direction & checkType);
5554 }
5555 }
5556 /**
5557 * @typedef {Object} PanInputOption The option object of the eg.Axes.PanInput module.
5558 * @ko eg.Axes.PanInput 모듈의 옵션 객체
5559 * @property {String[]} [inputType=["touch","mouse", "pointer"]] Types of input devices.<br>- touch: Touch screen<br>- mouse: Mouse <ko>입력 장치 종류.<br>- touch: 터치 입력 장치<br>- mouse: 마우스</ko>
5560 * @property {Number[]} [scale] Coordinate scale that a user can move<ko>사용자의 동작으로 이동하는 좌표의 배율</ko>
5561 * @property {Number} [scale.0=1] horizontal axis scale <ko>수평축 배율</ko>
5562 * @property {Number} [scale.1=1] vertical axis scale <ko>수직축 배율</ko>
5563 * @property {Number} [thresholdAngle=45] The threshold value that determines whether user action is horizontal or vertical (0~90) <ko>사용자의 동작이 가로 방향인지 세로 방향인지 판단하는 기준 각도(0~90)</ko>
5564 * @property {Number} [threshold=0] Minimal pan distance required before recognizing <ko>사용자의 Pan 동작을 인식하기 위해산 최소한의 거리</ko>
5565 * @property {Number} [iOSEdgeSwipeThreshold=30] Area (px) that can go to the next page when swiping the right edge in iOS safari <ko>iOS Safari에서 오른쪽 엣지를 스와이프 하는 경우 다음 페이지로 넘어갈 수 있는 영역(px)</ko>
5566 * @property {Object} [hammerManagerOptions={cssProps: {userSelect: "none",touchSelect: "none",touchCallout: "none",userDrag: "none"}] Options of Hammer.Manager <ko>Hammer.Manager의 옵션</ko>
5567 **/
5568
5569 /**
5570 * @class eg.Axes.PanInput
5571 * @classdesc A module that passes the amount of change to eg.Axes when the mouse or touchscreen is down and moved. use less than two axes.
5572 * @ko 마우스나 터치 스크린을 누르고 움직일때의 변화량을 eg.Axes에 전달하는 모듈. 두개 이하의 축을 사용한다.
5573 *
5574 * @example
5575 * const pan = new eg.Axes.PanInput("#area", {
5576 * inputType: ["touch"],
5577 * scale: [1, 1.3],
5578 * });
5579 *
5580 * // Connect the 'something2' axis to the mouse or touchscreen x position when the mouse or touchscreen is down and moved.
5581 * // Connect the 'somethingN' axis to the mouse or touchscreen y position when the mouse or touchscreen is down and moved.
5582 * axes.connect(["something2", "somethingN"], pan); // or axes.connect("something2 somethingN", pan);
5583 *
5584 * // Connect only one 'something1' axis to the mouse or touchscreen x position when the mouse or touchscreen is down and moved.
5585 * axes.connect(["something1"], pan); // or axes.connect("something1", pan);
5586 *
5587 * // Connect only one 'something2' axis to the mouse or touchscreen y position when the mouse or touchscreen is down and moved.
5588 * axes.connect(["", "something2"], pan); // or axes.connect(" something2", pan);
5589 *
5590 * @param {HTMLElement|String|jQuery} element An element to use the eg.Axes.PanInput module <ko>eg.Axes.PanInput 모듈을 사용할 엘리먼트</ko>
5591 * @param {PanInputOption} [options] The option object of the eg.Axes.PanInput module<ko>eg.Axes.PanInput 모듈의 옵션 객체</ko>
5592 */
5593
5594 var PanInput =
5595 /*#__PURE__*/
5596 function () {
5597 function PanInput(el, options) {
5598 this.axes = [];
5599 this.hammer = null;
5600 this.element = null;
5601 this.panRecognizer = null;
5602 this.isRightEdge = false;
5603 this.rightEdgeTimer = 0;
5604 this.panFlag = false;
5605 /**
5606 * Hammer helps you add support for touch gestures to your page
5607 *
5608 * @external Hammer
5609 * @see {@link http://hammerjs.github.io|Hammer.JS}
5610 * @see {@link http://hammerjs.github.io/jsdoc/Hammer.html|Hammer.JS API documents}
5611 * @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.Axes module removes all default CSS properties provided by Hammer.JS
5612 */
5613
5614 if (typeof Manager === "undefined") {
5615 throw new Error("The Hammerjs must be loaded before eg.Axes.PanInput.\nhttp://hammerjs.github.io/");
5616 }
5617
5618 this.element = $(el);
5619 this.options = __assign({
5620 inputType: ["touch", "mouse", "pointer"],
5621 scale: [1, 1],
5622 thresholdAngle: 45,
5623 threshold: 0,
5624 iOSEdgeSwipeThreshold: IOS_EDGE_THRESHOLD,
5625 releaseOnScroll: false,
5626 hammerManagerOptions: {
5627 // css properties were removed due to usablility issue
5628 // http://hammerjs.github.io/jsdoc/Hammer.defaults.cssProps.html
5629 cssProps: {
5630 userSelect: "none",
5631 touchSelect: "none",
5632 touchCallout: "none",
5633 userDrag: "none"
5634 }
5635 }
5636 }, options);
5637 this.onHammerInput = this.onHammerInput.bind(this);
5638 this.onPanmove = this.onPanmove.bind(this);
5639 this.onPanend = this.onPanend.bind(this);
5640 }
5641
5642 var __proto = PanInput.prototype;
5643
5644 __proto.mapAxes = function (axes) {
5645 var useHorizontal = !!axes[0];
5646 var useVertical = !!axes[1];
5647
5648 if (useHorizontal && useVertical) {
5649 this._direction = DIRECTION_ALL;
5650 } else if (useHorizontal) {
5651 this._direction = DIRECTION_HORIZONTAL;
5652 } else if (useVertical) {
5653 this._direction = DIRECTION_VERTICAL;
5654 } else {
5655 this._direction = DIRECTION_NONE;
5656 }
5657
5658 this.axes = axes;
5659 };
5660
5661 __proto.connect = function (observer) {
5662 var hammerOption = {
5663 direction: this._direction,
5664 threshold: this.options.threshold
5665 };
5666
5667 if (this.hammer) {
5668 // for sharing hammer instance.
5669 // hammer remove previous PanRecognizer.
5670 this.removeRecognizer();
5671 this.dettachEvent();
5672 } else {
5673 var keyValue = this.element[UNIQUEKEY];
5674
5675 if (!keyValue) {
5676 keyValue = String(Math.round(Math.random() * new Date().getTime()));
5677 }
5678
5679 var inputClass = convertInputType(this.options.inputType);
5680
5681 if (!inputClass) {
5682 throw new Error("Wrong inputType parameter!");
5683 }
5684
5685 this.hammer = createHammer(this.element, __assign({
5686 inputClass: inputClass
5687 }, this.options.hammerManagerOptions));
5688 this.element[UNIQUEKEY] = keyValue;
5689 }
5690
5691 this.panRecognizer = new PanRecognizer(hammerOption);
5692 this.hammer.add(this.panRecognizer);
5693 this.attachEvent(observer);
5694 return this;
5695 };
5696
5697 __proto.disconnect = function () {
5698 this.removeRecognizer();
5699
5700 if (this.hammer) {
5701 this.dettachEvent();
5702 }
5703
5704 this._direction = DIRECTION_NONE;
5705 return this;
5706 };
5707 /**
5708 * Destroys elements, properties, and events used in a module.
5709 * @ko 모듈에 사용한 엘리먼트와 속성, 이벤트를 해제한다.
5710 * @method eg.Axes.PanInput#destroy
5711 */
5712
5713
5714 __proto.destroy = function () {
5715 this.disconnect();
5716
5717 if (this.hammer && this.hammer.recognizers.length === 0) {
5718 this.hammer.destroy();
5719 }
5720
5721 delete this.element[UNIQUEKEY];
5722 this.element = null;
5723 this.hammer = null;
5724 };
5725 /**
5726 * Enables input devices
5727 * @ko 입력 장치를 사용할 수 있게 한다
5728 * @method eg.Axes.PanInput#enable
5729 * @return {eg.Axes.PanInput} An instance of a module itself <ko>모듈 자신의 인스턴스</ko>
5730 */
5731
5732
5733 __proto.enable = function () {
5734 this.hammer && (this.hammer.get("pan").options.enable = true);
5735 return this;
5736 };
5737 /**
5738 * Disables input devices
5739 * @ko 입력 장치를 사용할 수 없게 한다.
5740 * @method eg.Axes.PanInput#disable
5741 * @return {eg.Axes.PanInput} An instance of a module itself <ko>모듈 자신의 인스턴스</ko>
5742 */
5743
5744
5745 __proto.disable = function () {
5746 this.hammer && (this.hammer.get("pan").options.enable = false);
5747 return this;
5748 };
5749 /**
5750 * Returns whether to use an input device
5751 * @ko 입력 장치를 사용 여부를 반환한다.
5752 * @method eg.Axes.PanInput#isEnable
5753 * @return {Boolean} Whether to use an input device <ko>입력장치 사용여부</ko>
5754 */
5755
5756
5757 __proto.isEnable = function () {
5758 return !!(this.hammer && this.hammer.get("pan").options.enable);
5759 };
5760
5761 __proto.removeRecognizer = function () {
5762 if (this.hammer && this.panRecognizer) {
5763 this.hammer.remove(this.panRecognizer);
5764 this.panRecognizer = null;
5765 }
5766 };
5767
5768 __proto.onHammerInput = function (event) {
5769 if (this.isEnable()) {
5770 if (event.isFirst) {
5771 this.panFlag = false;
5772
5773 if (event.srcEvent.cancelable !== false) {
5774 var edgeThreshold = this.options.iOSEdgeSwipeThreshold;
5775 this.observer.hold(this, event);
5776 this.isRightEdge = IS_IOS_SAFARI && event.center.x > window.innerWidth - edgeThreshold;
5777 this.panFlag = true;
5778 }
5779 } else if (event.isFinal) {
5780 this.onPanend(event);
5781 }
5782 }
5783 };
5784
5785 __proto.onPanmove = function (event) {
5786 var _this = this;
5787
5788 if (!this.panFlag) {
5789 return;
5790 }
5791
5792 var _a = this.options,
5793 iOSEdgeSwipeThreshold = _a.iOSEdgeSwipeThreshold,
5794 releaseOnScroll = _a.releaseOnScroll;
5795 var userDirection = getDirectionByAngle(event.angle, this.options.thresholdAngle); // not support offset properties in Hammerjs - start
5796
5797 var prevInput = this.hammer.session.prevInput;
5798
5799 if (releaseOnScroll && !event.srcEvent.cancelable) {
5800 this.onPanend(__assign(__assign({}, event), {
5801 velocityX: 0,
5802 velocityY: 0,
5803 offsetX: 0,
5804 offsetY: 0
5805 }));
5806 return;
5807 }
5808
5809 if (prevInput && IS_IOS_SAFARI) {
5810 var swipeLeftToRight = event.center.x < 0;
5811
5812 if (swipeLeftToRight) {
5813 // iOS swipe left => right
5814 this.onPanend(__assign(__assign({}, prevInput), {
5815 velocityX: 0,
5816 velocityY: 0,
5817 offsetX: 0,
5818 offsetY: 0
5819 }));
5820 return;
5821 } else if (this.isRightEdge) {
5822 clearTimeout(this.rightEdgeTimer); // - is right to left
5823
5824 var swipeRightToLeft = event.deltaX < -iOSEdgeSwipeThreshold;
5825
5826 if (swipeRightToLeft) {
5827 this.isRightEdge = false;
5828 } else {
5829 // iOS swipe right => left
5830 this.rightEdgeTimer = window.setTimeout(function () {
5831 _this.onPanend(__assign(__assign({}, prevInput), {
5832 velocityX: 0,
5833 velocityY: 0,
5834 offsetX: 0,
5835 offsetY: 0
5836 }));
5837 }, 100);
5838 }
5839 }
5840 }
5841 /* eslint-disable no-param-reassign */
5842
5843
5844 if (prevInput) {
5845 event.offsetX = event.deltaX - prevInput.deltaX;
5846 event.offsetY = event.deltaY - prevInput.deltaY;
5847 } else {
5848 event.offsetX = 0;
5849 event.offsetY = 0;
5850 }
5851
5852 var offset = this.getOffset([event.offsetX, event.offsetY], [useDirection(DIRECTION_HORIZONTAL, this._direction, userDirection), useDirection(DIRECTION_VERTICAL, this._direction, userDirection)]);
5853 var prevent = offset.some(function (v) {
5854 return v !== 0;
5855 });
5856
5857 if (prevent) {
5858 var srcEvent = event.srcEvent;
5859
5860 if (srcEvent.cancelable !== false) {
5861 srcEvent.preventDefault();
5862 }
5863
5864 srcEvent.stopPropagation();
5865 }
5866
5867 event.preventSystemEvent = prevent;
5868 prevent && this.observer.change(this, event, toAxis(this.axes, offset));
5869 };
5870
5871 __proto.onPanend = function (event) {
5872 if (!this.panFlag) {
5873 return;
5874 }
5875
5876 clearTimeout(this.rightEdgeTimer);
5877 this.panFlag = false;
5878 var offset = this.getOffset([Math.abs(event.velocityX) * (event.deltaX < 0 ? -1 : 1), Math.abs(event.velocityY) * (event.deltaY < 0 ? -1 : 1)], [useDirection(DIRECTION_HORIZONTAL, this._direction), useDirection(DIRECTION_VERTICAL, this._direction)]);
5879 offset = getNextOffset(offset, this.observer.options.deceleration);
5880 this.observer.release(this, event, toAxis(this.axes, offset));
5881 };
5882
5883 __proto.attachEvent = function (observer) {
5884 this.observer = observer;
5885 this.hammer.on("hammer.input", this.onHammerInput).on("panstart panmove", this.onPanmove);
5886 };
5887
5888 __proto.dettachEvent = function () {
5889 this.hammer.off("hammer.input", this.onHammerInput).off("panstart panmove", this.onPanmove);
5890 this.observer = null;
5891 };
5892
5893 __proto.getOffset = function (properties, direction) {
5894 var offset = [0, 0];
5895 var scale = this.options.scale;
5896
5897 if (direction[0]) {
5898 offset[0] = properties[0] * scale[0];
5899 }
5900
5901 if (direction[1]) {
5902 offset[1] = properties[1] * scale[1];
5903 }
5904
5905 return offset;
5906 };
5907
5908 return PanInput;
5909 }();
5910
5911 /**
5912 * @class eg.Axes.RotatePanInput
5913 * @classdesc A module that passes the angle moved by touch to Axes and uses one axis of rotation.<br>[Details](https://github.com/naver/egjs-axes/wiki/RotatePanInput)
5914 * @ko 터치에 의해 움직인 각도를 Axes 에 전달하며 1개의 회전축만 사용한다.<br>[상세내용](https://github.com/naver/egjs-axes/wiki/RotatePanInput-%7C-%ED%95%9C%EA%B5%AD%EC%96%B4)
5915 *
5916 * @example
5917 * const input = new eg.Axes.RotatePanInput("#area");
5918 *
5919 * var axes = new eg.Axes({
5920 * // property name('angle') could be anything you want (eg. x, y, z...)
5921 * angle: {
5922 * range: [-180, 180] // from -180deg to 180deg
5923 * }
5924 * });
5925 *
5926 * axes.connect("angle", input)
5927 *
5928 * @param {HTMLElement|String|jQuery} element An element to use the eg.Axes.RotatePanInput module <ko>eg.Axes.RotatePanInput 모듈을 사용할 엘리먼트</ko>
5929 * @param {PanInputOption} [options] The option object of the eg.Axes.PanInput module<ko>eg.Axes.PanInput 모듈의 옵션 객체</ko>
5930 * @extends eg.Axes.PanInput
5931 */
5932
5933 var RotatePanInput =
5934 /*#__PURE__*/
5935 function (_super) {
5936 __extends(RotatePanInput, _super);
5937
5938 function RotatePanInput(el, options) {
5939 var _this = _super.call(this, el, options) || this;
5940
5941 _this.prevQuadrant = null;
5942 _this.lastDiff = 0;
5943 return _this;
5944 }
5945
5946 var __proto = RotatePanInput.prototype;
5947
5948 __proto.mapAxes = function (axes) {
5949 this._direction = Axes.DIRECTION_ALL;
5950 this.axes = axes;
5951 };
5952
5953 __proto.onHammerInput = function (event) {
5954 if (this.isEnable()) {
5955 if (event.isFirst) {
5956 this.observer.hold(this, event);
5957 this.onPanstart(event);
5958 } else if (event.isFinal) {
5959 this.onPanend(event);
5960 }
5961 }
5962 };
5963
5964 __proto.onPanstart = function (event) {
5965 var rect = this.element.getBoundingClientRect();
5966 /**
5967 * Responsive
5968 */
5969 // TODO: how to do if element is ellipse not circle.
5970
5971 this.coefficientForDistanceToAngle = 360 / (rect.width * Math.PI); // from 2*pi*r * x / 360
5972 // TODO: provide a way to set origin like https://developer.mozilla.org/en-US/docs/Web/CSS/transform-origin
5973
5974 this.rotateOrigin = [rect.left + (rect.width - 1) / 2, rect.top + (rect.height - 1) / 2]; // init angle.
5975
5976 this.prevAngle = null;
5977 this.triggerChange(event);
5978 };
5979
5980 __proto.onPanmove = function (event) {
5981 this.triggerChange(event);
5982 };
5983
5984 __proto.onPanend = function (event) {
5985 this.triggerChange(event);
5986 this.triggerAnimation(event);
5987 };
5988
5989 __proto.triggerChange = function (event) {
5990 var angle = this.getAngle(event.center.x, event.center.y);
5991 var quadrant = this.getQuadrant(event.center.x, event.center.y);
5992 var diff = this.getDifference(this.prevAngle, angle, this.prevQuadrant, quadrant);
5993 this.prevAngle = angle;
5994 this.prevQuadrant = quadrant;
5995
5996 if (diff === 0) {
5997 return;
5998 }
5999
6000 this.lastDiff = diff;
6001 this.observer.change(this, event, toAxis(this.axes, [-diff])); // minus for clockwise
6002 };
6003
6004 __proto.triggerAnimation = function (event) {
6005 var vx = event.velocityX;
6006 var vy = event.velocityY;
6007 var velocity = Math.sqrt(vx * vx + vy * vy) * (this.lastDiff > 0 ? -1 : 1); // clockwise
6008
6009 var duration = Math.abs(velocity / -this.observer.options.deceleration);
6010 var distance = velocity / 2 * duration;
6011 this.observer.release(this, event, toAxis(this.axes, [distance * this.coefficientForDistanceToAngle]));
6012 };
6013
6014 __proto.getDifference = function (prevAngle, angle, prevQuadrant, quadrant) {
6015 var diff;
6016
6017 if (prevAngle === null) {
6018 diff = 0;
6019 } else if (prevQuadrant === 1 && quadrant === 4) {
6020 diff = -prevAngle - (360 - angle);
6021 } else if (prevQuadrant === 4 && quadrant === 1) {
6022 diff = 360 - prevAngle + angle;
6023 } else {
6024 diff = angle - prevAngle;
6025 }
6026
6027 return diff;
6028 };
6029
6030 __proto.getPosFromOrigin = function (posX, posY) {
6031 return {
6032 x: posX - this.rotateOrigin[0],
6033 y: this.rotateOrigin[1] - posY
6034 };
6035 };
6036
6037 __proto.getAngle = function (posX, posY) {
6038 var _a = this.getPosFromOrigin(posX, posY),
6039 x = _a.x,
6040 y = _a.y;
6041
6042 var angle = Math.atan2(y, x) * 180 / Math.PI; // console.log(angle, x, y);
6043
6044 return angle < 0 ? 360 + angle : angle;
6045 };
6046 /**
6047 * Quadrant
6048 * y(+)
6049 * |
6050 * 2 | 1
6051 * --------------->x(+)
6052 * 3 | 4
6053 * |
6054 */
6055
6056
6057 __proto.getQuadrant = function (posX, posY) {
6058 var _a = this.getPosFromOrigin(posX, posY),
6059 x = _a.x,
6060 y = _a.y;
6061
6062 var q = 0;
6063
6064 if (x >= 0 && y >= 0) {
6065 q = 1;
6066 } else if (x < 0 && y >= 0) {
6067 q = 2;
6068 } else if (x < 0 && y < 0) {
6069 q = 3;
6070 } else if (x >= 0 && y < 0) {
6071 q = 4;
6072 }
6073
6074 return q;
6075 };
6076
6077 return RotatePanInput;
6078 }(PanInput);
6079
6080 /**
6081 * @typedef {Object} PinchInputOption The option object of the eg.Axes.PinchInput module
6082 * @ko eg.Axes.PinchInput 모듈의 옵션 객체
6083 * @property {Number} [scale=1] Coordinate scale that a user can move<ko>사용자의 동작으로 이동하는 좌표의 배율</ko>
6084 * @property {Number} [threshold=0] Minimal scale before recognizing <ko>사용자의 Pinch 동작을 인식하기 위해산 최소한의 배율</ko>
6085 * @property {Object} [hammerManagerOptions={cssProps: {userSelect: "none",touchSelect: "none",touchCallout: "none",userDrag: "none"}] Options of Hammer.Manager <ko>Hammer.Manager의 옵션</ko>
6086 **/
6087
6088 /**
6089 * @class eg.Axes.PinchInput
6090 * @classdesc A module that passes the amount of change to eg.Axes when two pointers are moving toward (zoom-in) or away from each other (zoom-out). use one axis.
6091 * @ko 2개의 pointer를 이용하여 zoom-in하거나 zoom-out 하는 동작의 변화량을 eg.Axes에 전달하는 모듈. 한 개 의 축을 사용한다.
6092 * @example
6093 * const pinch = new eg.Axes.PinchInput("#area", {
6094 * scale: 1
6095 * });
6096 *
6097 * // Connect 'something' axis when two pointers are moving toward (zoom-in) or away from each other (zoom-out).
6098 * axes.connect("something", pinch);
6099 *
6100 * @param {HTMLElement|String|jQuery} element An element to use the eg.Axes.PinchInput module <ko>eg.Axes.PinchInput 모듈을 사용할 엘리먼트</ko>
6101 * @param {PinchInputOption} [options] The option object of the eg.Axes.PinchInput module<ko>eg.Axes.PinchInput 모듈의 옵션 객체</ko>
6102 */
6103
6104 var PinchInput =
6105 /*#__PURE__*/
6106 function () {
6107 function PinchInput(el, options) {
6108 this.axes = [];
6109 this.hammer = null;
6110 this.element = null;
6111 this._base = null;
6112 this._prev = null;
6113 this.pinchRecognizer = null;
6114 /**
6115 * Hammer helps you add support for touch gestures to your page
6116 *
6117 * @external Hammer
6118 * @see {@link http://hammerjs.github.io|Hammer.JS}
6119 * @see {@link http://hammerjs.github.io/jsdoc/Hammer.html|Hammer.JS API documents}
6120 * @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.Axes module removes all default CSS properties provided by Hammer.JS
6121 */
6122
6123 if (typeof Manager === "undefined") {
6124 throw new Error("The Hammerjs must be loaded before eg.Axes.PinchInput.\nhttp://hammerjs.github.io/");
6125 }
6126
6127 this.element = $(el);
6128 this.options = __assign({
6129 scale: 1,
6130 threshold: 0,
6131 inputType: ["touch", "pointer"],
6132 hammerManagerOptions: {
6133 // css properties were removed due to usablility issue
6134 // http://hammerjs.github.io/jsdoc/Hammer.defaults.cssProps.html
6135 cssProps: {
6136 userSelect: "none",
6137 touchSelect: "none",
6138 touchCallout: "none",
6139 userDrag: "none"
6140 }
6141 }
6142 }, options);
6143 this.onPinchStart = this.onPinchStart.bind(this);
6144 this.onPinchMove = this.onPinchMove.bind(this);
6145 this.onPinchEnd = this.onPinchEnd.bind(this);
6146 }
6147
6148 var __proto = PinchInput.prototype;
6149
6150 __proto.mapAxes = function (axes) {
6151 this.axes = axes;
6152 };
6153
6154 __proto.connect = function (observer) {
6155 var hammerOption = {
6156 threshold: this.options.threshold
6157 };
6158
6159 if (this.hammer) {
6160 // for sharing hammer instance.
6161 // hammer remove previous PinchRecognizer.
6162 this.removeRecognizer();
6163 this.dettachEvent();
6164 } else {
6165 var keyValue = this.element[UNIQUEKEY];
6166
6167 if (!keyValue) {
6168 keyValue = String(Math.round(Math.random() * new Date().getTime()));
6169 }
6170
6171 var inputClass = convertInputType(this.options.inputType);
6172
6173 if (!inputClass) {
6174 throw new Error("Wrong inputType parameter!");
6175 }
6176
6177 this.hammer = createHammer(this.element, __assign({
6178 inputClass: inputClass
6179 }, this.options.hammerManagerOptions));
6180 this.element[UNIQUEKEY] = keyValue;
6181 }
6182
6183 this.pinchRecognizer = new PinchRecognizer(hammerOption);
6184 this.hammer.add(this.pinchRecognizer);
6185 this.attachEvent(observer);
6186 return this;
6187 };
6188
6189 __proto.disconnect = function () {
6190 this.removeRecognizer();
6191
6192 if (this.hammer) {
6193 this.hammer.remove(this.pinchRecognizer);
6194 this.pinchRecognizer = null;
6195 this.dettachEvent();
6196 }
6197
6198 return this;
6199 };
6200 /**
6201 * Destroys elements, properties, and events used in a module.
6202 * @ko 모듈에 사용한 엘리먼트와 속성, 이벤트를 해제한다.
6203 * @method eg.Axes.PinchInput#destroy
6204 */
6205
6206
6207 __proto.destroy = function () {
6208 this.disconnect();
6209
6210 if (this.hammer && this.hammer.recognizers.length === 0) {
6211 this.hammer.destroy();
6212 }
6213
6214 delete this.element[UNIQUEKEY];
6215 this.element = null;
6216 this.hammer = null;
6217 };
6218
6219 __proto.removeRecognizer = function () {
6220 if (this.hammer && this.pinchRecognizer) {
6221 this.hammer.remove(this.pinchRecognizer);
6222 this.pinchRecognizer = null;
6223 }
6224 };
6225
6226 __proto.onPinchStart = function (event) {
6227 this._base = this.observer.get(this)[this.axes[0]];
6228 var offset = this.getOffset(event.scale);
6229 this.observer.hold(this, event);
6230 this.observer.change(this, event, toAxis(this.axes, [offset]));
6231 this._prev = event.scale;
6232 };
6233
6234 __proto.onPinchMove = function (event) {
6235 var offset = this.getOffset(event.scale, this._prev);
6236 this.observer.change(this, event, toAxis(this.axes, [offset]));
6237 this._prev = event.scale;
6238 };
6239
6240 __proto.onPinchEnd = function (event) {
6241 var offset = this.getOffset(event.scale, this._prev);
6242 this.observer.change(this, event, toAxis(this.axes, [offset]));
6243 this.observer.release(this, event, toAxis(this.axes, [0]), 0);
6244 this._base = null;
6245 this._prev = null;
6246 };
6247
6248 __proto.getOffset = function (pinchScale, prev) {
6249 if (prev === void 0) {
6250 prev = 1;
6251 }
6252
6253 return this._base * (pinchScale - prev) * this.options.scale;
6254 };
6255
6256 __proto.attachEvent = function (observer) {
6257 this.observer = observer;
6258 this.hammer.on("pinchstart", this.onPinchStart).on("pinchmove", this.onPinchMove).on("pinchend", this.onPinchEnd);
6259 };
6260
6261 __proto.dettachEvent = function () {
6262 this.hammer.off("pinchstart", this.onPinchStart).off("pinchmove", this.onPinchMove).off("pinchend", this.onPinchEnd);
6263 this.observer = null;
6264 this._prev = null;
6265 };
6266 /**
6267 * Enables input devices
6268 * @ko 입력 장치를 사용할 수 있게 한다
6269 * @method eg.Axes.PinchInput#enable
6270 * @return {eg.Axes.PinchInput} An instance of a module itself <ko>모듈 자신의 인스턴스</ko>
6271 */
6272
6273
6274 __proto.enable = function () {
6275 this.hammer && (this.hammer.get("pinch").options.enable = true);
6276 return this;
6277 };
6278 /**
6279 * Disables input devices
6280 * @ko 입력 장치를 사용할 수 없게 한다.
6281 * @method eg.Axes.PinchInput#disable
6282 * @return {eg.Axes.PinchInput} An instance of a module itself <ko>모듈 자신의 인스턴스</ko>
6283 */
6284
6285
6286 __proto.disable = function () {
6287 this.hammer && (this.hammer.get("pinch").options.enable = false);
6288 return this;
6289 };
6290 /**
6291 * Returns whether to use an input device
6292 * @ko 입력 장치를 사용 여부를 반환한다.
6293 * @method eg.Axes.PinchInput#isEnable
6294 * @return {Boolean} Whether to use an input device <ko>입력장치 사용여부</ko>
6295 */
6296
6297
6298 __proto.isEnable = function () {
6299 return !!(this.hammer && this.hammer.get("pinch").options.enable);
6300 };
6301
6302 return PinchInput;
6303 }();
6304
6305 /**
6306 * @typedef {Object} WheelInputOption The option object of the eg.Axes.WheelInput module
6307 * @ko eg.Axes.WheelInput 모듈의 옵션 객체
6308 * @property {Number} [scale=1] Coordinate scale that a user can move<ko>사용자의 동작으로 이동하는 좌표의 배율</ko>
6309 **/
6310
6311 /**
6312 * @class eg.Axes.WheelInput
6313 * @classdesc A module that passes the amount of change to eg.Axes when the mouse wheel is moved. use one axis.
6314 * @ko 마우스 휠이 움직일때의 변화량을 eg.Axes에 전달하는 모듈. 한 개 의 축을 사용한다.
6315 *
6316 * @example
6317 * const wheel = new eg.Axes.WheelInput("#area", {
6318 * scale: 1
6319 * });
6320 *
6321 * // Connect 'something' axis when the mousewheel is moved.
6322 * axes.connect("something", wheel);
6323 *
6324 * @param {HTMLElement|String|jQuery} element An element to use the eg.Axes.WheelInput module <ko>eg.Axes.WheelInput 모듈을 사용할 엘리먼트</ko>
6325 * @param {WheelInputOption} [options] The option object of the eg.Axes.WheelInput module<ko>eg.Axes.WheelInput 모듈의 옵션 객체</ko>
6326 */
6327
6328 var WheelInput =
6329 /*#__PURE__*/
6330 function () {
6331 function WheelInput(el, options) {
6332 this.axes = [];
6333 this.element = null;
6334 this._isEnabled = false;
6335 this._isHolded = false;
6336 this._timer = null;
6337 this.element = $(el);
6338 this.options = __assign({
6339 scale: 1,
6340 useNormalized: true
6341 }, options);
6342 this.onWheel = this.onWheel.bind(this);
6343 }
6344
6345 var __proto = WheelInput.prototype;
6346
6347 __proto.mapAxes = function (axes) {
6348 this.axes = axes;
6349 };
6350
6351 __proto.connect = function (observer) {
6352 this.dettachEvent();
6353 this.attachEvent(observer);
6354 return this;
6355 };
6356
6357 __proto.disconnect = function () {
6358 this.dettachEvent();
6359 return this;
6360 };
6361 /**
6362 * Destroys elements, properties, and events used in a module.
6363 * @ko 모듈에 사용한 엘리먼트와 속성, 이벤트를 해제한다.
6364 * @method eg.Axes.WheelInput#destroy
6365 */
6366
6367
6368 __proto.destroy = function () {
6369 this.disconnect();
6370 this.element = null;
6371 };
6372
6373 __proto.onWheel = function (event) {
6374 var _this = this;
6375
6376 if (!this._isEnabled) {
6377 return;
6378 }
6379
6380 event.preventDefault();
6381
6382 if (event.deltaY === 0) {
6383 return;
6384 }
6385
6386 if (!this._isHolded) {
6387 this.observer.hold(this, event);
6388 this._isHolded = true;
6389 }
6390
6391 var offset = (event.deltaY > 0 ? -1 : 1) * this.options.scale * (this.options.useNormalized ? 1 : Math.abs(event.deltaY));
6392 this.observer.change(this, event, toAxis(this.axes, [offset]));
6393 clearTimeout(this._timer);
6394 this._timer = setTimeout(function () {
6395 if (_this._isHolded) {
6396 _this._isHolded = false;
6397
6398 _this.observer.release(_this, event, toAxis(_this.axes, [0]));
6399 }
6400 }, 50);
6401 };
6402
6403 __proto.attachEvent = function (observer) {
6404 this.observer = observer;
6405 this.element.addEventListener("wheel", this.onWheel);
6406 this._isEnabled = true;
6407 };
6408
6409 __proto.dettachEvent = function () {
6410 this.element.removeEventListener("wheel", this.onWheel);
6411 this._isEnabled = false;
6412 this.observer = null;
6413
6414 if (this._timer) {
6415 clearTimeout(this._timer);
6416 this._timer = null;
6417 }
6418 };
6419 /**
6420 * Enables input devices
6421 * @ko 입력 장치를 사용할 수 있게 한다
6422 * @method eg.Axes.WheelInput#enable
6423 * @return {eg.Axes.WheelInput} An instance of a module itself <ko>모듈 자신의 인스턴스</ko>
6424 */
6425
6426
6427 __proto.enable = function () {
6428 this._isEnabled = true;
6429 return this;
6430 };
6431 /**
6432 * Disables input devices
6433 * @ko 입력 장치를 사용할 수 없게 한다.
6434 * @method eg.Axes.WheelInput#disable
6435 * @return {eg.Axes.WheelInput} An instance of a module itself <ko>모듈 자신의 인스턴스</ko>
6436 */
6437
6438
6439 __proto.disable = function () {
6440 this._isEnabled = false;
6441 return this;
6442 };
6443 /**
6444 * Returns whether to use an input device
6445 * @ko 입력 장치를 사용 여부를 반환한다.
6446 * @method eg.Axes.WheelInput#isEnable
6447 * @return {Boolean} Whether to use an input device <ko>입력장치 사용여부</ko>
6448 */
6449
6450
6451 __proto.isEnable = function () {
6452 return this._isEnabled;
6453 };
6454
6455 return WheelInput;
6456 }();
6457
6458 var KEY_LEFT_ARROW = 37;
6459 var KEY_A = 65;
6460 var KEY_UP_ARROW = 38;
6461 var KEY_W = 87;
6462 var KEY_RIGHT_ARROW = 39;
6463 var KEY_D = 68;
6464 var KEY_DOWN_ARROW = 40;
6465 var KEY_S = 83;
6466 var DIRECTION_REVERSE = -1;
6467 var DIRECTION_FORWARD = 1;
6468 var DIRECTION_HORIZONTAL$1 = -1;
6469 var DIRECTION_VERTICAL$1 = 1;
6470 var DELAY = 80;
6471 /**
6472 * @typedef {Object} MoveKeyInputOption The option object of the eg.Axes.MoveKeyInput module
6473 * @ko eg.Axes.MoveKeyInput 모듈의 옵션 객체
6474 * @property {Array<Number>} [scale] Coordinate scale that a user can move<ko>사용자의 동작으로 이동하는 좌표의 배율</ko>
6475 * @property {Number} [scale[0]=1] Coordinate scale for the first axis<ko>첫번째 축의 배율</ko>
6476 * @property {Number} [scale[1]=1] Coordinate scale for the decond axis<ko>두번째 축의 배율</ko>
6477 **/
6478
6479 /**
6480 * @class eg.Axes.MoveKeyInput
6481 * @classdesc A module that passes the amount of change to eg.Axes when the move key stroke is occured. use two axis.
6482 * @ko 이동키 입력이 발생했을 때의 변화량을 eg.Axes에 전달하는 모듈. 두 개 의 축을 사용한다.
6483 *
6484 * @example
6485 * const moveKey = new eg.Axes.MoveKeyInput("#area", {
6486 * scale: [1, 1]
6487 * });
6488 *
6489 * // Connect 'x', 'y' axes when the moveKey is pressed.
6490 * axes.connect(["x", "y"], moveKey);
6491 *
6492 * @param {HTMLElement|String|jQuery} element An element to use the eg.Axes.MoveKeyInput module <ko>eg.Axes.MoveKeyInput 모듈을 사용할 엘리먼트</ko>
6493 * @param {MoveKeyInputOption} [options] The option object of the eg.Axes.MoveKeyInput module<ko>eg.Axes.MoveKeyInput 모듈의 옵션 객체</ko>
6494 */
6495
6496 var MoveKeyInput =
6497 /*#__PURE__*/
6498 function () {
6499 function MoveKeyInput(el, options) {
6500 this.axes = [];
6501 this.element = null;
6502 this._isEnabled = false;
6503 this._isHolded = false;
6504 this._timer = null;
6505 this.element = $(el);
6506 this.options = __assign({
6507 scale: [1, 1]
6508 }, options);
6509 this.onKeydown = this.onKeydown.bind(this);
6510 this.onKeyup = this.onKeyup.bind(this);
6511 }
6512
6513 var __proto = MoveKeyInput.prototype;
6514
6515 __proto.mapAxes = function (axes) {
6516 this.axes = axes;
6517 };
6518
6519 __proto.connect = function (observer) {
6520 this.dettachEvent(); // add tabindex="0" to the container for making it focusable
6521
6522 if (this.element.getAttribute("tabindex") !== "0") {
6523 this.element.setAttribute("tabindex", "0");
6524 }
6525
6526 this.attachEvent(observer);
6527 return this;
6528 };
6529
6530 __proto.disconnect = function () {
6531 this.dettachEvent();
6532 return this;
6533 };
6534 /**
6535 * Destroys elements, properties, and events used in a module.
6536 * @ko 모듈에 사용한 엘리먼트와 속성, 이벤트를 해제한다.
6537 * @method eg.Axes.MoveKeyInput#destroy
6538 */
6539
6540
6541 __proto.destroy = function () {
6542 this.disconnect();
6543 this.element = null;
6544 };
6545
6546 __proto.onKeydown = function (e) {
6547 if (!this._isEnabled) {
6548 return;
6549 }
6550
6551 var isMoveKey = true;
6552 var direction = DIRECTION_FORWARD;
6553 var move = DIRECTION_HORIZONTAL$1;
6554
6555 switch (e.keyCode) {
6556 case KEY_LEFT_ARROW:
6557 case KEY_A:
6558 direction = DIRECTION_REVERSE;
6559 break;
6560
6561 case KEY_RIGHT_ARROW:
6562 case KEY_D:
6563 break;
6564
6565 case KEY_DOWN_ARROW:
6566 case KEY_S:
6567 direction = DIRECTION_REVERSE;
6568 move = DIRECTION_VERTICAL$1;
6569 break;
6570
6571 case KEY_UP_ARROW:
6572 case KEY_W:
6573 move = DIRECTION_VERTICAL$1;
6574 break;
6575
6576 default:
6577 isMoveKey = false;
6578 }
6579
6580 if (move === DIRECTION_HORIZONTAL$1 && !this.axes[0] || move === DIRECTION_VERTICAL$1 && !this.axes[1]) {
6581 isMoveKey = false;
6582 }
6583
6584 if (!isMoveKey) {
6585 return;
6586 }
6587
6588 var offsets = move === DIRECTION_HORIZONTAL$1 ? [+this.options.scale[0] * direction, 0] : [0, +this.options.scale[1] * direction];
6589
6590 if (!this._isHolded) {
6591 this.observer.hold(this, event);
6592 this._isHolded = true;
6593 }
6594
6595 clearTimeout(this._timer);
6596 this.observer.change(this, event, toAxis(this.axes, offsets));
6597 };
6598
6599 __proto.onKeyup = function (e) {
6600 var _this = this;
6601
6602 if (!this._isHolded) {
6603 return;
6604 }
6605
6606 clearTimeout(this._timer);
6607 this._timer = setTimeout(function () {
6608 _this.observer.release(_this, e, toAxis(_this.axes, [0, 0]));
6609
6610 _this._isHolded = false;
6611 }, DELAY);
6612 };
6613
6614 __proto.attachEvent = function (observer) {
6615 this.observer = observer;
6616 this.element.addEventListener("keydown", this.onKeydown, false);
6617 this.element.addEventListener("keypress", this.onKeydown, false);
6618 this.element.addEventListener("keyup", this.onKeyup, false);
6619 this._isEnabled = true;
6620 };
6621
6622 __proto.dettachEvent = function () {
6623 this.element.removeEventListener("keydown", this.onKeydown, false);
6624 this.element.removeEventListener("keypress", this.onKeydown, false);
6625 this.element.removeEventListener("keyup", this.onKeyup, false);
6626 this._isEnabled = false;
6627 this.observer = null;
6628 };
6629 /**
6630 * Enables input devices
6631 * @ko 입력 장치를 사용할 수 있게 한다
6632 * @method eg.Axes.MoveKeyInput#enable
6633 * @return {eg.Axes.MoveKeyInput} An instance of a module itself <ko>모듈 자신의 인스턴스</ko>
6634 */
6635
6636
6637 __proto.enable = function () {
6638 this._isEnabled = true;
6639 return this;
6640 };
6641 /**
6642 * Disables input devices
6643 * @ko 입력 장치를 사용할 수 없게 한다.
6644 * @method eg.Axes.MoveKeyInput#disable
6645 * @return {eg.Axes.MoveKeyInput} An instance of a module itself <ko>모듈 자신의 인스턴스</ko>
6646 */
6647
6648
6649 __proto.disable = function () {
6650 this._isEnabled = false;
6651 return this;
6652 };
6653 /**
6654 * Returns whether to use an input device
6655 * @ko 입력 장치를 사용 여부를 반환한다.
6656 * @method eg.Axes.MoveKeyInput#isEnable
6657 * @return {Boolean} Whether to use an input device <ko>입력장치 사용여부</ko>
6658 */
6659
6660
6661 __proto.isEnable = function () {
6662 return this._isEnabled;
6663 };
6664
6665 return MoveKeyInput;
6666 }();
6667
6668 Axes.PanInput = PanInput;
6669 Axes.RotatePanInput = RotatePanInput;
6670 Axes.PinchInput = PinchInput;
6671 Axes.WheelInput = WheelInput;
6672 Axes.MoveKeyInput = MoveKeyInput;
6673
6674 return Axes;
6675
6676})));
6677//# sourceMappingURL=axes.pkgd.js.map