| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224 |
3x
3x
3x
3x
3x
3x
3x
3x
3x
3x
3x
3x
3x
3x
3x
3x
24x
24x
24x
24x
24x
24x
24x
24x
24x
3x
22x
3x
24x
24x
24x
24x
24x
3x
45x
45x
3x
23x
23x
3x
2x
2x
3x
1x
1x
3x
4x
3x
188x
188x
188x
188x
188x
2x
2x
88x
6x
6x
6x
86x
86x
6x
188x
2x
188x
7x
181x
181x
181x
13x
13x
181x
181x
9x
9x
4x
5x
5x
5x
5x
3x
24x
24x
24x
24x
24x
24x
24x
3x
69x
69x
69x
69x
69x
69x
69x
3x
| /*
* Copyright (c) 2015 NAVER Corp.
* egjs projects are licensed under the MIT license
*/
import { ElementType } from "../types";
import { $ } from "../utils";
import { toAxis, InputType, InputTypeObserver } from "./InputType";
export const KEY_LEFT_ARROW = 37;
export const KEY_A = 65;
export const KEY_UP_ARROW = 38;
export const KEY_W = 87;
export const KEY_RIGHT_ARROW = 39;
export const KEY_D = 68;
export const KEY_DOWN_ARROW = 40;
export const KEY_S = 83;
/* eslint-disable */
const DIRECTION_REVERSE = -1;
const DIRECTION_FORWARD = 1;
const DIRECTION_HORIZONTAL = -1;
const DIRECTION_VERTICAL = 1;
const DELAY = 80;
/* eslint-enable */
export interface MoveKeyInputOption {
scale?: number[];
}
/**
* @typedef {Object} MoveKeyInputOption The option object of the eg.Axes.MoveKeyInput module
* @ko eg.Axes.MoveKeyInput 모듈의 옵션 객체
* @param {Array<Number>} [scale] Coordinate scale that a user can move<ko>사용자의 동작으로 이동하는 좌표의 배율</ko>
* @param {Number} [scale[0]=1] Coordinate scale for the first axis<ko>첫번째 축의 배율</ko>
* @param {Number} [scale[1]=1] Coordinate scale for the decond axis<ko>두번째 축의 배율</ko>
**/
/**
* A module that passes the amount of change to eg.Axes when the move key stroke is occured. use two axis.
* @ko 이동키 입력이 발생했을 때의 변화량을 eg.Axes에 전달하는 모듈. 두 개 의 축을 사용한다.
*
* @example
* ```js
* const moveKey = new eg.Axes.MoveKeyInput("#area", {
* scale: [1, 1]
* });
*
* // Connect 'x', 'y' axes when the moveKey is pressed.
* axes.connect(["x", "y"], moveKey);
* ```
* @param {HTMLElement|String|jQuery} element An element to use the eg.Axes.MoveKeyInput module <ko>eg.Axes.MoveKeyInput 모듈을 사용할 엘리먼트</ko>
* @param {MoveKeyInputOption} [options] The option object of the eg.Axes.MoveKeyInput module<ko>eg.Axes.MoveKeyInput 모듈의 옵션 객체</ko>
*/
export class MoveKeyInput implements InputType {
public options: MoveKeyInputOption;
public axes: string[] = [];
public element: HTMLElement = null;
private _observer: InputTypeObserver;
private _enabled = false;
private _holding = false;
private _timer: NodeJS.Timeout = null;
/**
*
*/
public constructor(el: ElementType, options?: MoveKeyInputOption) {
this.element = $(el);
this.options = {
...{
scale: [1, 1],
},
...options,
};
this._onKeydown = this._onKeydown.bind(this);
this._onKeyup = this._onKeyup.bind(this);
}
public mapAxes(axes: string[]) {
this.axes = axes;
}
public connect(observer: InputTypeObserver): InputType {
this._detachEvent();
// add tabindex="0" to the container for making it focusable
Eif (this.element.getAttribute("tabindex") !== "0") {
this.element.setAttribute("tabindex", "0");
}
this._attachEvent(observer);
return this;
}
public disconnect() {
this._detachEvent();
return this;
}
/**
* Destroys elements, properties, and events used in a module.
* @ko 모듈에 사용한 엘리먼트와 속성, 이벤트를 해제한다.
*/
public destroy() {
this.disconnect();
this.element = null;
}
/**
* Enables input devices
* @ko 입력 장치를 사용할 수 있게 한다
* @return {MoveKeyInput} An instance of a module itself <ko>모듈 자신의 인스턴스</ko>
*/
public enable() {
this._enabled = true;
return this;
}
/**
* Disables input devices
* @ko 입력 장치를 사용할 수 없게 한다.
* @return {MoveKeyInput} An instance of a module itself <ko>모듈 자신의 인스턴스</ko>
*/
public disable() {
this._enabled = false;
return this;
}
/**
* Returns whether to use an input device
* @ko 입력 장치를 사용 여부를 반환한다.
* @return {Boolean} Whether to use an input device <ko>입력장치 사용여부</ko>
*/
public isEnabled() {
return this._enabled;
}
private _onKeydown(event: KeyboardEvent) {
Iif (!this._enabled) {
return;
}
let isMoveKey = true;
let direction = DIRECTION_FORWARD;
let move = DIRECTION_HORIZONTAL;
switch (event.keyCode) {
case KEY_LEFT_ARROW:
case KEY_A:
direction = DIRECTION_REVERSE;
break;
case KEY_RIGHT_ARROW:
case KEY_D:
break;
case KEY_DOWN_ARROW:
case KEY_S:
direction = DIRECTION_REVERSE;
move = DIRECTION_VERTICAL;
break;
case KEY_UP_ARROW:
case KEY_W:
move = DIRECTION_VERTICAL;
break;
default:
isMoveKey = false;
}
if (
(move === DIRECTION_HORIZONTAL && !this.axes[0]) ||
(move === DIRECTION_VERTICAL && !this.axes[1])
) {
isMoveKey = false;
}
if (!isMoveKey) {
return;
}
event.preventDefault();
const offsets =
move === DIRECTION_HORIZONTAL
? [+this.options.scale[0] * direction, 0]
: [0, +this.options.scale[1] * direction];
if (!this._holding) {
this._observer.hold(this, event);
this._holding = true;
}
clearTimeout(this._timer);
this._observer.change(this, event, toAxis(this.axes, offsets));
}
private _onKeyup(event: KeyboardEvent) {
if (!this._holding) {
return;
}
clearTimeout(this._timer);
this._timer = setTimeout(() => {
this._observer.release(this, event, [0, 0]);
this._holding = false;
}, DELAY);
}
private _attachEvent(observer: InputTypeObserver) {
const element = this.element;
Iif (!element) {
throw new Error("Element to connect input does not exist.");
}
this._observer = observer;
element.addEventListener("keydown", this._onKeydown, false);
element.addEventListener("keypress", this._onKeydown, false);
element.addEventListener("keyup", this._onKeyup, false);
this._enabled = true;
}
private _detachEvent() {
const element = this.element;
Eif (element) {
element.removeEventListener("keydown", this._onKeydown, false);
element.removeEventListener("keypress", this._onKeydown, false);
element.removeEventListener("keyup", this._onKeyup, false);
}
this._enabled = false;
this._observer = null;
}
}
|