@wwawing/virtual-pad 3.8.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/lib/VirtualPad.d.ts +51 -0
- package/lib/VirtualPad.js +188 -0
- package/lib/autoRotate.d.ts +2 -0
- package/lib/autoRotate.js +23 -0
- package/lib/index.d.ts +4 -0
- package/lib/index.js +4 -0
- package/lib/makeInject.d.ts +1 -0
- package/lib/makeInject.js +3 -0
- package/package.json +20 -0
- package/src/VirtualPad.ts +326 -0
- package/src/autoRotate.ts +37 -0
- package/src/index.ts +13 -0
- package/src/makeInject.ts +17 -0
- package/tsconfig.json +14 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 1996-2015 NAO
|
|
4
|
+
Copyright (c) 2015-2022 WWA Wing Team
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in
|
|
14
|
+
all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
22
|
+
THE SOFTWARE.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export declare enum VirtualPadButtonCode {
|
|
2
|
+
BUTTON_ENTER = 0,
|
|
3
|
+
BUTTON_ESC = 1,
|
|
4
|
+
BUTTON_SIDEBAR = 2,
|
|
5
|
+
BUTTON_ESTIMATE = 3,
|
|
6
|
+
BUTTON_FAST = 4,
|
|
7
|
+
BUTTON_SLOW = 5,
|
|
8
|
+
BUTTON_LEFT = 6,
|
|
9
|
+
BUTTON_UP = 7,
|
|
10
|
+
BUTTON_RIGHT = 8,
|
|
11
|
+
BUTTON_DOWN = 9
|
|
12
|
+
}
|
|
13
|
+
export declare enum VirtualPadState {
|
|
14
|
+
NONE = 0,
|
|
15
|
+
TOUCH = 1,
|
|
16
|
+
TOUCHING = 2,
|
|
17
|
+
LEAVE = 3
|
|
18
|
+
}
|
|
19
|
+
export declare type VirtualPadButtons = {
|
|
20
|
+
[VirtualPadButtonCode.BUTTON_ENTER]: HTMLButtonElement;
|
|
21
|
+
[VirtualPadButtonCode.BUTTON_ESC]: HTMLButtonElement;
|
|
22
|
+
[VirtualPadButtonCode.BUTTON_SIDEBAR]?: HTMLButtonElement;
|
|
23
|
+
[VirtualPadButtonCode.BUTTON_ESTIMATE]: HTMLButtonElement;
|
|
24
|
+
[VirtualPadButtonCode.BUTTON_FAST]: HTMLButtonElement;
|
|
25
|
+
[VirtualPadButtonCode.BUTTON_SLOW]: HTMLButtonElement;
|
|
26
|
+
[VirtualPadButtonCode.BUTTON_LEFT]: HTMLButtonElement;
|
|
27
|
+
[VirtualPadButtonCode.BUTTON_UP]: HTMLButtonElement;
|
|
28
|
+
[VirtualPadButtonCode.BUTTON_RIGHT]: HTMLButtonElement;
|
|
29
|
+
[VirtualPadButtonCode.BUTTON_DOWN]: HTMLButtonElement;
|
|
30
|
+
};
|
|
31
|
+
declare type VirtualPadEventFunction = (buttonCode: VirtualPadButtonCode) => void;
|
|
32
|
+
export default class VirtualPadStore {
|
|
33
|
+
private _enabled;
|
|
34
|
+
private _onTouchStart;
|
|
35
|
+
private _onTouchEnd;
|
|
36
|
+
private _availableButtons;
|
|
37
|
+
private _isTouchingButtons;
|
|
38
|
+
private _moveButtonsElement;
|
|
39
|
+
constructor(buttons: VirtualPadButtons | {}, moveButtons?: HTMLElement, onTouchStart?: VirtualPadEventFunction, onTouchEnd?: VirtualPadEventFunction);
|
|
40
|
+
private _detectMovingMoveButton;
|
|
41
|
+
checkTouchButton(buttonType: VirtualPadButtonCode): boolean;
|
|
42
|
+
checkTouchingButton(buttonType: VirtualPadButtonCode): boolean;
|
|
43
|
+
getButtonState(buttonType: VirtualPadButtonCode): VirtualPadState;
|
|
44
|
+
setTouchInfo(buttonType: VirtualPadButtonCode): void;
|
|
45
|
+
clearTouchInfo(buttonType: VirtualPadButtonCode): void;
|
|
46
|
+
allMoveClear(): void;
|
|
47
|
+
allClear(): void;
|
|
48
|
+
static isMoveButton(buttonType: VirtualPadButtonCode): boolean;
|
|
49
|
+
update(): void;
|
|
50
|
+
}
|
|
51
|
+
export {};
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
export var VirtualPadButtonCode;
|
|
2
|
+
(function (VirtualPadButtonCode) {
|
|
3
|
+
VirtualPadButtonCode[VirtualPadButtonCode["BUTTON_ENTER"] = 0] = "BUTTON_ENTER";
|
|
4
|
+
VirtualPadButtonCode[VirtualPadButtonCode["BUTTON_ESC"] = 1] = "BUTTON_ESC";
|
|
5
|
+
VirtualPadButtonCode[VirtualPadButtonCode["BUTTON_SIDEBAR"] = 2] = "BUTTON_SIDEBAR";
|
|
6
|
+
VirtualPadButtonCode[VirtualPadButtonCode["BUTTON_ESTIMATE"] = 3] = "BUTTON_ESTIMATE";
|
|
7
|
+
VirtualPadButtonCode[VirtualPadButtonCode["BUTTON_FAST"] = 4] = "BUTTON_FAST";
|
|
8
|
+
VirtualPadButtonCode[VirtualPadButtonCode["BUTTON_SLOW"] = 5] = "BUTTON_SLOW";
|
|
9
|
+
VirtualPadButtonCode[VirtualPadButtonCode["BUTTON_LEFT"] = 6] = "BUTTON_LEFT";
|
|
10
|
+
VirtualPadButtonCode[VirtualPadButtonCode["BUTTON_UP"] = 7] = "BUTTON_UP";
|
|
11
|
+
VirtualPadButtonCode[VirtualPadButtonCode["BUTTON_RIGHT"] = 8] = "BUTTON_RIGHT";
|
|
12
|
+
VirtualPadButtonCode[VirtualPadButtonCode["BUTTON_DOWN"] = 9] = "BUTTON_DOWN";
|
|
13
|
+
})(VirtualPadButtonCode || (VirtualPadButtonCode = {}));
|
|
14
|
+
export var VirtualPadState;
|
|
15
|
+
(function (VirtualPadState) {
|
|
16
|
+
VirtualPadState[VirtualPadState["NONE"] = 0] = "NONE";
|
|
17
|
+
VirtualPadState[VirtualPadState["TOUCH"] = 1] = "TOUCH";
|
|
18
|
+
VirtualPadState[VirtualPadState["TOUCHING"] = 2] = "TOUCHING";
|
|
19
|
+
VirtualPadState[VirtualPadState["LEAVE"] = 3] = "LEAVE";
|
|
20
|
+
})(VirtualPadState || (VirtualPadState = {}));
|
|
21
|
+
var VirtualPadMoveButtonCodes = [
|
|
22
|
+
VirtualPadButtonCode.BUTTON_LEFT,
|
|
23
|
+
VirtualPadButtonCode.BUTTON_UP,
|
|
24
|
+
VirtualPadButtonCode.BUTTON_RIGHT,
|
|
25
|
+
VirtualPadButtonCode.BUTTON_DOWN
|
|
26
|
+
];
|
|
27
|
+
var VirtualPadStore = (function () {
|
|
28
|
+
function VirtualPadStore(buttons, moveButtons, onTouchStart, onTouchEnd) {
|
|
29
|
+
if (moveButtons === void 0) { moveButtons = null; }
|
|
30
|
+
if (onTouchStart === void 0) { onTouchStart = null; }
|
|
31
|
+
if (onTouchEnd === void 0) { onTouchEnd = null; }
|
|
32
|
+
var _this = this;
|
|
33
|
+
this._enabled = Object.keys(buttons).length > 0;
|
|
34
|
+
this._onTouchStart = onTouchStart || null;
|
|
35
|
+
this._onTouchEnd = onTouchEnd || null;
|
|
36
|
+
this._availableButtons = [];
|
|
37
|
+
this._isTouchingButtons = {};
|
|
38
|
+
this._moveButtonsElement = moveButtons;
|
|
39
|
+
var _loop_1 = function (buttonTypeString) {
|
|
40
|
+
var buttonCode = parseInt(buttonTypeString);
|
|
41
|
+
var button = buttons[buttonCode];
|
|
42
|
+
this_1._availableButtons.push(buttonCode);
|
|
43
|
+
button.setAttribute("type", buttonTypeString);
|
|
44
|
+
this_1._isTouchingButtons[buttonCode] = {
|
|
45
|
+
prev: false,
|
|
46
|
+
current: false,
|
|
47
|
+
next: false
|
|
48
|
+
};
|
|
49
|
+
var cancelBrowserTouchEvent = function (event) {
|
|
50
|
+
if (event.cancelable) {
|
|
51
|
+
event.preventDefault();
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
var cancelVirtualPad = function (event) {
|
|
55
|
+
cancelBrowserTouchEvent(event);
|
|
56
|
+
_this.allClear();
|
|
57
|
+
};
|
|
58
|
+
button.addEventListener("touchstart", function (event) {
|
|
59
|
+
cancelBrowserTouchEvent(event);
|
|
60
|
+
_this.setTouchInfo(buttonCode);
|
|
61
|
+
});
|
|
62
|
+
button.addEventListener("cancel", cancelVirtualPad);
|
|
63
|
+
button.addEventListener("touchcancel", cancelVirtualPad);
|
|
64
|
+
if (VirtualPadStore.isMoveButton(buttonCode)) {
|
|
65
|
+
button.addEventListener("touchmove", this_1._detectMovingMoveButton.bind(this_1));
|
|
66
|
+
button.addEventListener("touchend", this_1.allMoveClear.bind(this_1));
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
button.addEventListener("touchend", function (event) {
|
|
70
|
+
cancelBrowserTouchEvent(event);
|
|
71
|
+
_this.clearTouchInfo(buttonCode);
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
var this_1 = this;
|
|
76
|
+
for (var buttonTypeString in buttons) {
|
|
77
|
+
_loop_1(buttonTypeString);
|
|
78
|
+
}
|
|
79
|
+
if (moveButtons !== null) {
|
|
80
|
+
moveButtons.addEventListener("touchmove", this._detectMovingMoveButton.bind(this));
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
VirtualPadStore.prototype._detectMovingMoveButton = function (event) {
|
|
84
|
+
event.preventDefault();
|
|
85
|
+
this.allMoveClear();
|
|
86
|
+
var moveButtonRect = this._moveButtonsElement.getBoundingClientRect();
|
|
87
|
+
var bodyRect = document.body.getBoundingClientRect();
|
|
88
|
+
var centerPositionX = moveButtonRect.left - bodyRect.left + (moveButtonRect.width / 2);
|
|
89
|
+
var centerPositionY = moveButtonRect.top - bodyRect.top + (moveButtonRect.height / 2);
|
|
90
|
+
var touch = event.targetTouches.item(0);
|
|
91
|
+
var touchX = touch.pageX - centerPositionX;
|
|
92
|
+
var touchY = touch.pageY - centerPositionY;
|
|
93
|
+
if (touchX >= touchY) {
|
|
94
|
+
if (touchX <= -touchY) {
|
|
95
|
+
this.setTouchInfo(VirtualPadButtonCode.BUTTON_UP);
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
this.setTouchInfo(VirtualPadButtonCode.BUTTON_RIGHT);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
if (touchX >= -touchY) {
|
|
103
|
+
this.setTouchInfo(VirtualPadButtonCode.BUTTON_DOWN);
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
this.setTouchInfo(VirtualPadButtonCode.BUTTON_LEFT);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
VirtualPadStore.prototype.checkTouchButton = function (buttonType) {
|
|
111
|
+
if (!this._enabled) {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
var state = this.getButtonState(buttonType);
|
|
115
|
+
return state === VirtualPadState.TOUCH;
|
|
116
|
+
};
|
|
117
|
+
VirtualPadStore.prototype.checkTouchingButton = function (buttonType) {
|
|
118
|
+
if (!this._enabled) {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
var state = this.getButtonState(buttonType);
|
|
122
|
+
return state === VirtualPadState.TOUCH || state === VirtualPadState.TOUCHING;
|
|
123
|
+
};
|
|
124
|
+
VirtualPadStore.prototype.getButtonState = function (buttonType) {
|
|
125
|
+
if (!this._enabled) {
|
|
126
|
+
return VirtualPadState.NONE;
|
|
127
|
+
}
|
|
128
|
+
var touched = this._isTouchingButtons[buttonType].prev;
|
|
129
|
+
var isTouching = this._isTouchingButtons[buttonType].current;
|
|
130
|
+
if (touched && isTouching) {
|
|
131
|
+
return VirtualPadState.TOUCHING;
|
|
132
|
+
}
|
|
133
|
+
else if (isTouching) {
|
|
134
|
+
return VirtualPadState.TOUCH;
|
|
135
|
+
}
|
|
136
|
+
else if (touched) {
|
|
137
|
+
return VirtualPadState.LEAVE;
|
|
138
|
+
}
|
|
139
|
+
return VirtualPadState.NONE;
|
|
140
|
+
};
|
|
141
|
+
VirtualPadStore.prototype.setTouchInfo = function (buttonType) {
|
|
142
|
+
if (!this._enabled) {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
this._isTouchingButtons[buttonType].next = true;
|
|
146
|
+
};
|
|
147
|
+
VirtualPadStore.prototype.clearTouchInfo = function (buttonType) {
|
|
148
|
+
if (!this._enabled) {
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
this._isTouchingButtons[buttonType].next = false;
|
|
152
|
+
};
|
|
153
|
+
VirtualPadStore.prototype.allMoveClear = function () {
|
|
154
|
+
var _this = this;
|
|
155
|
+
VirtualPadMoveButtonCodes.forEach(function (buttonCode) {
|
|
156
|
+
if (_this._availableButtons.includes(buttonCode)) {
|
|
157
|
+
_this.clearTouchInfo(buttonCode);
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
};
|
|
161
|
+
VirtualPadStore.prototype.allClear = function () {
|
|
162
|
+
var _this = this;
|
|
163
|
+
this._availableButtons.forEach(function (buttonCode) {
|
|
164
|
+
_this._isTouchingButtons[buttonCode].next = false;
|
|
165
|
+
});
|
|
166
|
+
};
|
|
167
|
+
VirtualPadStore.isMoveButton = function (buttonType) {
|
|
168
|
+
return VirtualPadMoveButtonCodes.includes(buttonType);
|
|
169
|
+
};
|
|
170
|
+
VirtualPadStore.prototype.update = function () {
|
|
171
|
+
var _this = this;
|
|
172
|
+
this._availableButtons.forEach(function (buttonCode) {
|
|
173
|
+
var currentButtonTouching = _this._isTouchingButtons[buttonCode];
|
|
174
|
+
_this._isTouchingButtons[buttonCode].prev = currentButtonTouching.current;
|
|
175
|
+
_this._isTouchingButtons[buttonCode].current = currentButtonTouching.next;
|
|
176
|
+
switch (_this.getButtonState(buttonCode)) {
|
|
177
|
+
case VirtualPadState.TOUCH:
|
|
178
|
+
_this._onTouchStart(buttonCode);
|
|
179
|
+
break;
|
|
180
|
+
case VirtualPadState.LEAVE:
|
|
181
|
+
_this._onTouchEnd(buttonCode);
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
};
|
|
186
|
+
return VirtualPadStore;
|
|
187
|
+
}());
|
|
188
|
+
export default VirtualPadStore;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export function initializeRotate() {
|
|
2
|
+
var headElement = document.getElementsByTagName('head')[0];
|
|
3
|
+
var viewportElement = document.createElement('meta');
|
|
4
|
+
viewportElement.setAttribute('name', 'viewport');
|
|
5
|
+
headElement.appendChild(viewportElement);
|
|
6
|
+
autoRotate();
|
|
7
|
+
}
|
|
8
|
+
export default function autoRotate() {
|
|
9
|
+
var WWA_WIDTH = 560;
|
|
10
|
+
var WWA_HEIGHT = 440;
|
|
11
|
+
var viewportElement = document.querySelector("meta[name='viewport']");
|
|
12
|
+
var browserWidth = window.innerWidth;
|
|
13
|
+
var browserHeight = window.innerHeight;
|
|
14
|
+
var viewportValue = "user-scalable=no";
|
|
15
|
+
if (browserWidth > browserHeight) {
|
|
16
|
+
var width = Math.floor((browserWidth / browserHeight) * WWA_HEIGHT);
|
|
17
|
+
viewportValue = "width=".concat(width, ",").concat(viewportValue);
|
|
18
|
+
}
|
|
19
|
+
else if (browserWidth <= browserHeight) {
|
|
20
|
+
viewportValue = "width=".concat(WWA_WIDTH, ",").concat(viewportValue);
|
|
21
|
+
}
|
|
22
|
+
viewportElement.setAttribute("content", "".concat(viewportValue));
|
|
23
|
+
}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import VirtualPadStore, { VirtualPadState, VirtualPadButtonCode, VirtualPadButtons } from './VirtualPad';
|
|
2
|
+
import autoRotate, { initializeRotate } from './autoRotate';
|
|
3
|
+
import makeInject from './makeInject';
|
|
4
|
+
export { VirtualPadStore, VirtualPadState, VirtualPadButtonCode, VirtualPadButtons, autoRotate, initializeRotate, makeInject };
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import VirtualPadStore, { VirtualPadState, VirtualPadButtonCode } from './VirtualPad';
|
|
2
|
+
import autoRotate, { initializeRotate } from './autoRotate';
|
|
3
|
+
import makeInject from './makeInject';
|
|
4
|
+
export { VirtualPadStore, VirtualPadState, VirtualPadButtonCode, autoRotate, initializeRotate, makeInject };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function makeInject(): string;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export default function makeInject() {
|
|
2
|
+
return "\n <div id=\"wwa-virtualpad-left\">\n <button class=\"wwa-virtualpad__button\" id=\"wwa-up-button\"></button>\n <button class=\"wwa-virtualpad__button\" id=\"wwa-left-button\"></button>\n <button class=\"wwa-virtualpad__button\" id=\"wwa-right-button\"></button>\n <button class=\"wwa-virtualpad__button\" id=\"wwa-down-button\"></button>\n <div class=\"wwa-virtualpad__hole\"></div>\n </div>\n <div id=\"wwa-virtualpad-right\">\n <button class=\"wwa-virtualpad__button\" id=\"wwa-slow-button\">I</button>\n <button class=\"wwa-virtualpad__button\" id=\"wwa-fast-button\">P</button>\n <button class=\"wwa-virtualpad__button\" id=\"wwa-enter-button\">Y</button>\n <button class=\"wwa-virtualpad__button\" id=\"wwa-esc-button\">N</button>\n <button class=\"wwa-virtualpad__button\" id=\"wwa-estimate-button\">M</button>\n </div>";
|
|
3
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@wwawing/virtual-pad",
|
|
3
|
+
"version": "3.8.0-beta.1",
|
|
4
|
+
"description": "WWA Wing Virtual Pad for mobile phone",
|
|
5
|
+
"main": "lib/index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
8
|
+
"build": "tsc -p .",
|
|
9
|
+
"prepare": "npm run build"
|
|
10
|
+
},
|
|
11
|
+
"author": "WWA Wing Team",
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"devDependencies": {
|
|
14
|
+
"typescript": "^4.2.4"
|
|
15
|
+
},
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public"
|
|
18
|
+
},
|
|
19
|
+
"gitHead": "f27dbc4de044cc28ab944997ea1c3361e94228cc"
|
|
20
|
+
}
|
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
export enum VirtualPadButtonCode {
|
|
2
|
+
BUTTON_ENTER,
|
|
3
|
+
BUTTON_ESC,
|
|
4
|
+
BUTTON_SIDEBAR,
|
|
5
|
+
BUTTON_ESTIMATE,
|
|
6
|
+
BUTTON_FAST,
|
|
7
|
+
BUTTON_SLOW,
|
|
8
|
+
BUTTON_LEFT,
|
|
9
|
+
BUTTON_UP,
|
|
10
|
+
BUTTON_RIGHT,
|
|
11
|
+
BUTTON_DOWN
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* NONE: ボタンに一切触れていません
|
|
16
|
+
* TOUCH: ボタンに触れ始めました
|
|
17
|
+
* TOUCHING: ボタンに触れています
|
|
18
|
+
* LEAVE: ボタンから離れました
|
|
19
|
+
*/
|
|
20
|
+
export enum VirtualPadState {
|
|
21
|
+
NONE,
|
|
22
|
+
TOUCH,
|
|
23
|
+
TOUCHING,
|
|
24
|
+
LEAVE
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export type VirtualPadButtons = {
|
|
28
|
+
[VirtualPadButtonCode.BUTTON_ENTER]: HTMLButtonElement,
|
|
29
|
+
[VirtualPadButtonCode.BUTTON_ESC]: HTMLButtonElement,
|
|
30
|
+
[VirtualPadButtonCode.BUTTON_SIDEBAR]?: HTMLButtonElement,
|
|
31
|
+
[VirtualPadButtonCode.BUTTON_ESTIMATE]: HTMLButtonElement,
|
|
32
|
+
[VirtualPadButtonCode.BUTTON_FAST]: HTMLButtonElement,
|
|
33
|
+
[VirtualPadButtonCode.BUTTON_SLOW]: HTMLButtonElement,
|
|
34
|
+
[VirtualPadButtonCode.BUTTON_LEFT]: HTMLButtonElement,
|
|
35
|
+
[VirtualPadButtonCode.BUTTON_UP]: HTMLButtonElement,
|
|
36
|
+
[VirtualPadButtonCode.BUTTON_RIGHT]: HTMLButtonElement,
|
|
37
|
+
[VirtualPadButtonCode.BUTTON_DOWN]: HTMLButtonElement
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
type VirtualPadButtonTouching = {
|
|
41
|
+
prev: boolean,
|
|
42
|
+
current: boolean,
|
|
43
|
+
next: boolean
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
type VirtualPadEventFunction = (buttonCode: VirtualPadButtonCode) => void;
|
|
47
|
+
|
|
48
|
+
const VirtualPadMoveButtonCodes = [
|
|
49
|
+
VirtualPadButtonCode.BUTTON_LEFT,
|
|
50
|
+
VirtualPadButtonCode.BUTTON_UP,
|
|
51
|
+
VirtualPadButtonCode.BUTTON_RIGHT,
|
|
52
|
+
VirtualPadButtonCode.BUTTON_DOWN
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* 仮想パッドの状態管理を行うクラスです。
|
|
57
|
+
* @todo PCといった、タッチデバイスでないデバイスでは、このクラスのインスタンスを生成しないようにする。
|
|
58
|
+
* (this._enabled で判別しているけど、いちいち判定処理書くのつらい...)
|
|
59
|
+
*/
|
|
60
|
+
export default class VirtualPadStore {
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* 仮想パッドが有効か
|
|
64
|
+
* @property
|
|
65
|
+
*/
|
|
66
|
+
private _enabled: boolean;
|
|
67
|
+
|
|
68
|
+
private _onTouchStart: VirtualPadEventFunction | null;
|
|
69
|
+
private _onTouchEnd: VirtualPadEventFunction | null;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* 有効なボタンが格納されている配列です。各ボタンを繰り返し処理する場合に使用します。
|
|
73
|
+
* @property
|
|
74
|
+
*/
|
|
75
|
+
private _availableButtons: [VirtualPadButtonCode?];
|
|
76
|
+
private _isTouchingButtons: {
|
|
77
|
+
[key in VirtualPadButtonCode]?: VirtualPadButtonTouching
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* 移動ボタンの要素自体です。主に移動ボタンで指を動かす際に使用します。
|
|
82
|
+
* @property
|
|
83
|
+
*/
|
|
84
|
+
private _moveButtonsElement: HTMLElement;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* @param buttons 仮想パッドの各要素
|
|
88
|
+
* @param moveButtons 仮想パッドの移動ボタンの要素
|
|
89
|
+
* @param onTouchStart 仮想パッドを押下した場合に発生するコールバック関数
|
|
90
|
+
* @param onTouchEnd 仮想パッドを話した場合に発生するコールバック関数
|
|
91
|
+
*/
|
|
92
|
+
constructor(
|
|
93
|
+
buttons: VirtualPadButtons | {},
|
|
94
|
+
moveButtons: HTMLElement = null,
|
|
95
|
+
onTouchStart: VirtualPadEventFunction = null,
|
|
96
|
+
onTouchEnd: VirtualPadEventFunction = null
|
|
97
|
+
) {
|
|
98
|
+
this._enabled = Object.keys(buttons).length > 0;
|
|
99
|
+
this._onTouchStart = onTouchStart || null;
|
|
100
|
+
this._onTouchEnd = onTouchEnd || null;
|
|
101
|
+
this._availableButtons = [];
|
|
102
|
+
this._isTouchingButtons = {};
|
|
103
|
+
this._moveButtonsElement = moveButtons;
|
|
104
|
+
|
|
105
|
+
for (let buttonTypeString in buttons) {
|
|
106
|
+
/**
|
|
107
|
+
* for in ... で渡される buttonTypeString は必ず文字列型になります。
|
|
108
|
+
* このまま buttons の配列のキーに渡すと、正しく要素が受け取れません。
|
|
109
|
+
* このため、一度 parseInt で数字に変換した上で渡しています。
|
|
110
|
+
*/
|
|
111
|
+
let buttonCode = parseInt(buttonTypeString);
|
|
112
|
+
let button: HTMLButtonElement = buttons[buttonCode];
|
|
113
|
+
this._availableButtons.push(buttonCode);
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* type 属性について
|
|
117
|
+
* HTML側の各仮想パッドボタンは、 type 属性を元に各ボタンを特定しています。
|
|
118
|
+
* 各仮想パッドボタンの種類を判別するために、初期化時に type 属性を割り振っています。
|
|
119
|
+
*/
|
|
120
|
+
button.setAttribute("type", buttonTypeString);
|
|
121
|
+
|
|
122
|
+
this._isTouchingButtons[buttonCode] = {
|
|
123
|
+
prev: false,
|
|
124
|
+
current: false,
|
|
125
|
+
next: false
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
const cancelBrowserTouchEvent = (event: TouchEvent) => {
|
|
129
|
+
if (event.cancelable) {
|
|
130
|
+
event.preventDefault();
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* 何かしらの割り込み処理が発生した場合に、緊急で仮想パッドを停止する処理です。
|
|
136
|
+
* @param event
|
|
137
|
+
*/
|
|
138
|
+
const cancelVirtualPad = (event: TouchEvent) => {
|
|
139
|
+
cancelBrowserTouchEvent(event);
|
|
140
|
+
this.allClear();
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
button.addEventListener("touchstart", (event: TouchEvent) => {
|
|
144
|
+
cancelBrowserTouchEvent(event);
|
|
145
|
+
this.setTouchInfo(buttonCode);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
button.addEventListener("cancel", cancelVirtualPad);
|
|
149
|
+
button.addEventListener("touchcancel", cancelVirtualPad);
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* 移動ボタンに関しては、指先を移動しながら操作することがあるため、 touchmove イベントにも対応します。
|
|
153
|
+
*/
|
|
154
|
+
if (VirtualPadStore.isMoveButton(buttonCode)) {
|
|
155
|
+
button.addEventListener("touchmove", this._detectMovingMoveButton.bind(this));
|
|
156
|
+
button.addEventListener("touchend", this.allMoveClear.bind(this));
|
|
157
|
+
} else {
|
|
158
|
+
button.addEventListener("touchend", (event: TouchEvent) => {
|
|
159
|
+
cancelBrowserTouchEvent(event);
|
|
160
|
+
this.clearTouchInfo(buttonCode);
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
if (moveButtons !== null) {
|
|
165
|
+
moveButtons.addEventListener("touchmove", this._detectMovingMoveButton.bind(this));
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* TouchMove した要素から触れた先の要素に、触れたことを呼び出します。
|
|
171
|
+
* @param event
|
|
172
|
+
*/
|
|
173
|
+
private _detectMovingMoveButton(event: TouchEvent) {
|
|
174
|
+
event.preventDefault();
|
|
175
|
+
this.allMoveClear();
|
|
176
|
+
|
|
177
|
+
// 中央のポジションを取得
|
|
178
|
+
const moveButtonRect = this._moveButtonsElement.getBoundingClientRect();
|
|
179
|
+
const bodyRect = document.body.getBoundingClientRect();
|
|
180
|
+
const centerPositionX = moveButtonRect.left - bodyRect.left + (moveButtonRect.width / 2);
|
|
181
|
+
const centerPositionY = moveButtonRect.top - bodyRect.top + (moveButtonRect.height / 2);
|
|
182
|
+
|
|
183
|
+
const touch = event.targetTouches.item(0);
|
|
184
|
+
const touchX = touch.pageX - centerPositionX;
|
|
185
|
+
const touchY = touch.pageY - centerPositionY;
|
|
186
|
+
|
|
187
|
+
if (touchX >= touchY) { // 上と右
|
|
188
|
+
/**
|
|
189
|
+
* touchY をマイナスにして、グラフの空間上で擬似的に表現します。
|
|
190
|
+
*/
|
|
191
|
+
if (touchX <= -touchY) { // 上
|
|
192
|
+
this.setTouchInfo(VirtualPadButtonCode.BUTTON_UP);
|
|
193
|
+
} else { // 右
|
|
194
|
+
this.setTouchInfo(VirtualPadButtonCode.BUTTON_RIGHT);
|
|
195
|
+
}
|
|
196
|
+
} else { // 左と下
|
|
197
|
+
if (touchX >= -touchY) { // 下
|
|
198
|
+
this.setTouchInfo(VirtualPadButtonCode.BUTTON_DOWN);
|
|
199
|
+
} else { // 左
|
|
200
|
+
this.setTouchInfo(VirtualPadButtonCode.BUTTON_LEFT);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* 指定したボタンが押されたかを判別します。
|
|
207
|
+
* 戦闘予測ボタンといった、1回しか押さないボタンの判定に使用します。
|
|
208
|
+
* @param buttonType
|
|
209
|
+
*/
|
|
210
|
+
public checkTouchButton(buttonType: VirtualPadButtonCode): boolean {
|
|
211
|
+
if (!this._enabled) {
|
|
212
|
+
return false;
|
|
213
|
+
}
|
|
214
|
+
const state = this.getButtonState(buttonType);
|
|
215
|
+
return state === VirtualPadState.TOUCH;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* 指定したボタンが押されているかを判別します。
|
|
220
|
+
* 移動ボタンといった、長時間押すボタンの判定に使用します。
|
|
221
|
+
* @param buttonType
|
|
222
|
+
*/
|
|
223
|
+
public checkTouchingButton(buttonType: VirtualPadButtonCode): boolean {
|
|
224
|
+
if (!this._enabled) {
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
const state = this.getButtonState(buttonType);
|
|
228
|
+
return state === VirtualPadState.TOUCH || state === VirtualPadState.TOUCHING;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* 今の仮想パッドのボタンの状態を出力します
|
|
233
|
+
* @param buttonType
|
|
234
|
+
*/
|
|
235
|
+
public getButtonState(buttonType: VirtualPadButtonCode): VirtualPadState {
|
|
236
|
+
if (!this._enabled) {
|
|
237
|
+
return VirtualPadState.NONE;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const touched = this._isTouchingButtons[buttonType].prev;
|
|
241
|
+
const isTouching = this._isTouchingButtons[buttonType].current;
|
|
242
|
+
if (touched && isTouching) {
|
|
243
|
+
return VirtualPadState.TOUCHING;
|
|
244
|
+
} else if (isTouching) {
|
|
245
|
+
return VirtualPadState.TOUCH;
|
|
246
|
+
} else if (touched) {
|
|
247
|
+
return VirtualPadState.LEAVE;
|
|
248
|
+
}
|
|
249
|
+
return VirtualPadState.NONE;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* ボタンにタッチ信号を与えます
|
|
254
|
+
* @param buttonType
|
|
255
|
+
*/
|
|
256
|
+
public setTouchInfo(buttonType: VirtualPadButtonCode) {
|
|
257
|
+
if (!this._enabled) {
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
this._isTouchingButtons[buttonType].next = true;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* ボタンのタッチ信号を解除します
|
|
266
|
+
* @param buttonType
|
|
267
|
+
*/
|
|
268
|
+
public clearTouchInfo(buttonType: VirtualPadButtonCode) {
|
|
269
|
+
if (!this._enabled) {
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
this._isTouchingButtons[buttonType].next = false;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* すべての移動ボタンのタッチ信号をキャンセルします
|
|
278
|
+
*/
|
|
279
|
+
public allMoveClear(): void {
|
|
280
|
+
VirtualPadMoveButtonCodes.forEach((buttonCode) => {
|
|
281
|
+
if (this._availableButtons.includes(buttonCode)) {
|
|
282
|
+
this.clearTouchInfo(buttonCode);
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* すべてのボタンのタッチ信号をキャンセルします。
|
|
289
|
+
*/
|
|
290
|
+
public allClear(): void {
|
|
291
|
+
this._availableButtons.forEach((buttonCode) => {
|
|
292
|
+
this._isTouchingButtons[buttonCode].next = false;
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* 押したボタンが移動ボタンか判定します。
|
|
298
|
+
* @param buttonType
|
|
299
|
+
*/
|
|
300
|
+
public static isMoveButton(buttonType: VirtualPadButtonCode): boolean {
|
|
301
|
+
return VirtualPadMoveButtonCodes.includes(buttonType);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* 今の仮想パッドボタンの状態を次の状態に送ります。
|
|
306
|
+
*/
|
|
307
|
+
public update() {
|
|
308
|
+
this._availableButtons.forEach((buttonCode) => {
|
|
309
|
+
let currentButtonTouching = this._isTouchingButtons[buttonCode];
|
|
310
|
+
this._isTouchingButtons[buttonCode].prev = currentButtonTouching.current;
|
|
311
|
+
this._isTouchingButtons[buttonCode].current = currentButtonTouching.next;
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* ボタンの状態に応じて、コールバック関数を実行
|
|
315
|
+
*/
|
|
316
|
+
switch (this.getButtonState(buttonCode)) {
|
|
317
|
+
case VirtualPadState.TOUCH:
|
|
318
|
+
this._onTouchStart(buttonCode);
|
|
319
|
+
break;
|
|
320
|
+
case VirtualPadState.LEAVE:
|
|
321
|
+
this._onTouchEnd(buttonCode);
|
|
322
|
+
break;
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 自動回転制御の初期化を行うメソッドです。
|
|
3
|
+
*/
|
|
4
|
+
export function initializeRotate() {
|
|
5
|
+
const headElement = document.getElementsByTagName('head')[0];
|
|
6
|
+
let viewportElement = document.createElement('meta');
|
|
7
|
+
|
|
8
|
+
viewportElement.setAttribute('name', 'viewport');
|
|
9
|
+
headElement.appendChild(viewportElement);
|
|
10
|
+
autoRotate();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 回転の自動制御メソッドです。 "resize" イベントと併せてご利用ください。
|
|
15
|
+
* @example window.addEventListener("resize", autoRotate);
|
|
16
|
+
*/
|
|
17
|
+
export default function autoRotate() {
|
|
18
|
+
const WWA_WIDTH = 560;
|
|
19
|
+
const WWA_HEIGHT = 440;
|
|
20
|
+
|
|
21
|
+
const viewportElement = document.querySelector("meta[name='viewport']");
|
|
22
|
+
const browserWidth = window.innerWidth;
|
|
23
|
+
const browserHeight = window.innerHeight;
|
|
24
|
+
/**
|
|
25
|
+
* autoRotate を有効化すると、誤動作を防ぐため、拡大操作が無効になります。
|
|
26
|
+
* Webページの中に設置する場合は、特にご注意ください。
|
|
27
|
+
*/
|
|
28
|
+
let viewportValue = "user-scalable=no";
|
|
29
|
+
|
|
30
|
+
if (browserWidth > browserHeight) {
|
|
31
|
+
const width = Math.floor((browserWidth / browserHeight) * WWA_HEIGHT);
|
|
32
|
+
viewportValue = `width=${width},${viewportValue}`;
|
|
33
|
+
} else if (browserWidth <= browserHeight) {
|
|
34
|
+
viewportValue = `width=${WWA_WIDTH},${viewportValue}`;
|
|
35
|
+
}
|
|
36
|
+
viewportElement.setAttribute("content", `${viewportValue}`);
|
|
37
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import VirtualPadStore, { VirtualPadState, VirtualPadButtonCode, VirtualPadButtons } from './VirtualPad';
|
|
2
|
+
import autoRotate, { initializeRotate } from './autoRotate';
|
|
3
|
+
import makeInject from './makeInject';
|
|
4
|
+
|
|
5
|
+
export {
|
|
6
|
+
VirtualPadStore,
|
|
7
|
+
VirtualPadState,
|
|
8
|
+
VirtualPadButtonCode,
|
|
9
|
+
VirtualPadButtons,
|
|
10
|
+
autoRotate,
|
|
11
|
+
initializeRotate,
|
|
12
|
+
makeInject
|
|
13
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export default function makeInject() {
|
|
2
|
+
return `
|
|
3
|
+
<div id="wwa-virtualpad-left">
|
|
4
|
+
<button class="wwa-virtualpad__button" id="wwa-up-button"></button>
|
|
5
|
+
<button class="wwa-virtualpad__button" id="wwa-left-button"></button>
|
|
6
|
+
<button class="wwa-virtualpad__button" id="wwa-right-button"></button>
|
|
7
|
+
<button class="wwa-virtualpad__button" id="wwa-down-button"></button>
|
|
8
|
+
<div class="wwa-virtualpad__hole"></div>
|
|
9
|
+
</div>
|
|
10
|
+
<div id="wwa-virtualpad-right">
|
|
11
|
+
<button class="wwa-virtualpad__button" id="wwa-slow-button">I</button>
|
|
12
|
+
<button class="wwa-virtualpad__button" id="wwa-fast-button">P</button>
|
|
13
|
+
<button class="wwa-virtualpad__button" id="wwa-enter-button">Y</button>
|
|
14
|
+
<button class="wwa-virtualpad__button" id="wwa-esc-button">N</button>
|
|
15
|
+
<button class="wwa-virtualpad__button" id="wwa-estimate-button">M</button>
|
|
16
|
+
</div>`;
|
|
17
|
+
}
|