@mml-io/3d-web-client-core 0.12.2 → 0.13.0

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.
@@ -31,7 +31,13 @@ export declare class CameraManager {
31
31
  private lerpTarget;
32
32
  private lerpFactor;
33
33
  private lerpDuration;
34
+ private hasTouchControl;
35
+ private lastTouchX;
36
+ private lastTouchY;
34
37
  constructor(targetElement: HTMLElement, collisionsManager: CollisionsManager, initialPhi?: number, initialTheta?: number);
38
+ private onTouchStart;
39
+ private onTouchMove;
40
+ private onTouchEnd;
35
41
  private onMouseDown;
36
42
  private onMouseUp;
37
43
  private onMouseMove;
package/build/index.js CHANGED
@@ -82,6 +82,169 @@ var EventHandlerCollection = class _EventHandlerCollection {
82
82
  }
83
83
  };
84
84
 
85
+ // src/input/VirtualJoystick.ts
86
+ var _VirtualJoystick = class _VirtualJoystick {
87
+ constructor(attrs) {
88
+ this.left = false;
89
+ this.right = false;
90
+ this.up = false;
91
+ this.down = false;
92
+ this.hasDirection = false;
93
+ this.clearFlags = () => {
94
+ this.left = false;
95
+ this.right = false;
96
+ this.up = false;
97
+ this.down = false;
98
+ this.hasDirection = false;
99
+ this.control.style.left = `${this.width / 2 - this.inner_radius}px`;
100
+ this.control.style.top = `${this.height / 2 - this.inner_radius}px`;
101
+ };
102
+ this.radius = attrs.radius || 50;
103
+ this.inner_radius = attrs.inner_radius || this.radius / 2;
104
+ this.anchor = attrs.anchor || "left";
105
+ this.x = attrs.x || 0;
106
+ this.y = attrs.y || 0;
107
+ this.width = attrs.width || this.radius * 2 + this.inner_radius * 2;
108
+ this.height = attrs.height || this.radius * 2 + this.inner_radius * 2;
109
+ this.mouse_support = this.checkTouch() || attrs.mouse_support === true;
110
+ this.initializeJoystick();
111
+ }
112
+ static checkForTouch() {
113
+ try {
114
+ document.createEvent("TouchEvent");
115
+ return true;
116
+ } catch (e) {
117
+ return false;
118
+ }
119
+ }
120
+ static isTouchOnJoystick(touch) {
121
+ if (!_VirtualJoystick.JOYSTICK_DIV) {
122
+ return false;
123
+ }
124
+ const divRect = _VirtualJoystick.JOYSTICK_DIV.getBoundingClientRect();
125
+ return touch.clientX >= divRect.left && touch.clientX <= divRect.right && touch.clientY >= divRect.top && touch.clientY <= divRect.bottom;
126
+ }
127
+ checkTouch() {
128
+ return _VirtualJoystick.checkForTouch();
129
+ }
130
+ initializeJoystick() {
131
+ if (!_VirtualJoystick.JOYSTICK_DIV) {
132
+ this.div = document.createElement("div");
133
+ const divStyle = this.div.style;
134
+ divStyle.display = this.checkTouch() || this.mouse_support ? "visible" : "none";
135
+ divStyle.position = "fixed";
136
+ if (this.anchor === "left") {
137
+ divStyle.left = `${this.x}px`;
138
+ } else {
139
+ divStyle.right = `${this.x}px`;
140
+ }
141
+ divStyle.bottom = `${this.y}px`;
142
+ divStyle.width = `${this.width}px`;
143
+ divStyle.height = `${this.height}px`;
144
+ divStyle.zIndex = "10000";
145
+ divStyle.overflow = "hidden";
146
+ document.body.appendChild(this.div);
147
+ _VirtualJoystick.JOYSTICK_DIV = this.div;
148
+ }
149
+ this.setupBaseAndControl();
150
+ this.bindEvents();
151
+ }
152
+ setupBaseAndControl() {
153
+ this.base = document.createElement("span");
154
+ let divStyle = this.base.style;
155
+ divStyle.width = `${this.radius * 2}px`;
156
+ divStyle.height = `${this.radius * 2}px`;
157
+ divStyle.position = "absolute";
158
+ divStyle.left = `${this.width / 2 - this.radius}px`;
159
+ divStyle.bottom = `${this.height / 2 - this.radius}px`;
160
+ divStyle.borderRadius = "50%";
161
+ divStyle.borderColor = "rgba(200,200,200,0.5)";
162
+ divStyle.borderWidth = "2px";
163
+ divStyle.borderStyle = "solid";
164
+ this.div.appendChild(this.base);
165
+ this.control = document.createElement("span");
166
+ divStyle = this.control.style;
167
+ divStyle.width = `${this.inner_radius * 2}px`;
168
+ divStyle.height = `${this.inner_radius * 2}px`;
169
+ divStyle.position = "absolute";
170
+ divStyle.left = `${this.width / 2 - this.inner_radius}px`;
171
+ divStyle.bottom = `${this.height / 2 - this.inner_radius}px`;
172
+ divStyle.borderRadius = "50%";
173
+ divStyle.backgroundColor = "rgba(200,200,200,0.3)";
174
+ divStyle.borderWidth = "1px";
175
+ divStyle.borderColor = "rgba(200,200,200,0.8)";
176
+ divStyle.borderStyle = "solid";
177
+ this.div.appendChild(this.control);
178
+ }
179
+ bindEvents() {
180
+ this.div.addEventListener("touchstart", this.handleTouchStart.bind(this), false);
181
+ this.div.addEventListener("touchmove", this.handleTouchMove.bind(this), false);
182
+ this.div.addEventListener("touchend", this.clearFlags.bind(this), false);
183
+ if (this.mouse_support) {
184
+ this.div.addEventListener("mousedown", this.handleMouseDown.bind(this));
185
+ this.div.addEventListener("mousemove", this.handleMouseMove.bind(this));
186
+ this.div.addEventListener("mouseup", this.handleMouseUp.bind(this));
187
+ }
188
+ }
189
+ handleTouchStart(evt) {
190
+ evt.preventDefault();
191
+ if (evt.touches) {
192
+ const touch = evt.touches[0];
193
+ this.updateControlAndDirection(touch);
194
+ }
195
+ }
196
+ handleTouchMove(evt) {
197
+ evt.preventDefault();
198
+ if (evt.touches.length > 0) {
199
+ const touch = evt.touches[0];
200
+ this.updateControlAndDirection(touch);
201
+ }
202
+ }
203
+ handleMouseDown(evt) {
204
+ evt.preventDefault();
205
+ this.updateControlAndDirection(evt);
206
+ }
207
+ handleMouseMove(evt) {
208
+ if (evt.buttons === 1) {
209
+ evt.preventDefault();
210
+ this.updateControlAndDirection(evt);
211
+ }
212
+ }
213
+ handleMouseUp(evt) {
214
+ this.clearFlags();
215
+ }
216
+ updateControlAndDirection(input) {
217
+ const rect = this.div.getBoundingClientRect();
218
+ const dx = input.clientX - (rect.left + this.div.offsetWidth / 2);
219
+ const dy = input.clientY - (rect.top + this.div.offsetHeight / 2);
220
+ const distance = Math.min(Math.sqrt(dx * dx + dy * dy), this.radius);
221
+ const angle = Math.atan2(dy, dx);
222
+ const constrainedX = distance * Math.cos(angle);
223
+ const constrainedY = distance * Math.sin(angle);
224
+ this.control.style.left = `${constrainedX + this.width / 2 - this.inner_radius}px`;
225
+ this.control.style.top = `${constrainedY + this.height / 2 - this.inner_radius}px`;
226
+ this.up = this.isUp(dx, dy);
227
+ this.down = this.isDown(dx, dy);
228
+ this.left = this.isLeft(dx, dy);
229
+ this.right = this.isRight(dx, dy);
230
+ this.hasDirection = this.up || this.down || this.left || this.right;
231
+ }
232
+ isUp(dx, dy) {
233
+ return dy < 0 && Math.abs(dx) <= 2 * Math.abs(dy);
234
+ }
235
+ isDown(dx, dy) {
236
+ return dy > 0 && Math.abs(dx) <= 2 * Math.abs(dy);
237
+ }
238
+ isLeft(dx, dy) {
239
+ return dx < 0 && Math.abs(dy) <= 2 * Math.abs(dx);
240
+ }
241
+ isRight(dx, dy) {
242
+ return dx > 0 && Math.abs(dy) <= 2 * Math.abs(dx);
243
+ }
244
+ };
245
+ _VirtualJoystick.JOYSTICK_DIV = null;
246
+ var VirtualJoystick = _VirtualJoystick;
247
+
85
248
  // src/tweakpane/tweakPaneActivity.ts
86
249
  var isTweakpaneActive = false;
87
250
  function setTweakpaneActive(status) {
@@ -119,6 +282,9 @@ var CameraManager = class {
119
282
  this.lerpTarget = new Vector32();
120
283
  this.lerpFactor = 0;
121
284
  this.lerpDuration = 2.1;
285
+ this.hasTouchControl = false;
286
+ this.lastTouchX = 0;
287
+ this.lastTouchY = 0;
122
288
  this.phi = initialPhi;
123
289
  this.targetPhi = initialPhi;
124
290
  this.theta = initialTheta;
@@ -126,12 +292,61 @@ var CameraManager = class {
126
292
  this.camera = new PerspectiveCamera(this.fov, window.innerWidth / window.innerHeight, 0.1, 400);
127
293
  this.camera.position.set(0, 1.4, -this.initialDistance);
128
294
  this.rayCaster = new Raycaster();
295
+ this.hasTouchControl = VirtualJoystick.checkForTouch();
129
296
  this.eventHandlerCollection = EventHandlerCollection.create([
130
297
  [targetElement, "mousedown", this.onMouseDown.bind(this)],
131
298
  [document, "mouseup", this.onMouseUp.bind(this)],
132
299
  [document, "mousemove", this.onMouseMove.bind(this)],
133
300
  [targetElement, "wheel", this.onMouseWheel.bind(this)]
134
301
  ]);
302
+ if (this.hasTouchControl) {
303
+ this.eventHandlerCollection.add(targetElement, "touchstart", this.onTouchStart.bind(this), {
304
+ passive: false
305
+ });
306
+ this.eventHandlerCollection.add(document, "touchmove", this.onTouchMove.bind(this), {
307
+ passive: false
308
+ });
309
+ this.eventHandlerCollection.add(document, "touchend", this.onTouchEnd.bind(this), {
310
+ passive: false
311
+ });
312
+ }
313
+ }
314
+ onTouchStart(evt) {
315
+ Array.from(evt.touches).forEach((touch) => {
316
+ if (!VirtualJoystick.isTouchOnJoystick(touch)) {
317
+ this.dragging = true;
318
+ this.lastTouchX = touch.clientX;
319
+ this.lastTouchY = touch.clientY;
320
+ }
321
+ });
322
+ }
323
+ onTouchMove(evt) {
324
+ if (!this.dragging || getTweakpaneActive()) {
325
+ return;
326
+ }
327
+ evt.preventDefault();
328
+ const touch = Array.from(evt.touches).find((t) => !VirtualJoystick.isTouchOnJoystick(t));
329
+ if (touch) {
330
+ const dx = touch.clientX - this.lastTouchX;
331
+ const dy = touch.clientY - this.lastTouchY;
332
+ this.lastTouchX = touch.clientX;
333
+ this.lastTouchY = touch.clientY;
334
+ if (this.targetTheta !== null && this.targetPhi !== null) {
335
+ this.targetTheta += dx * 0.01;
336
+ this.targetPhi -= dy * 0.01;
337
+ this.targetPhi = Math.max(this.minPolarAngle, Math.min(this.maxPolarAngle, this.targetPhi));
338
+ }
339
+ }
340
+ }
341
+ onTouchEnd(evt) {
342
+ if (this.dragging) {
343
+ const touchEnded = Array.from(evt.changedTouches).some(
344
+ (t) => !VirtualJoystick.isTouchOnJoystick(t)
345
+ );
346
+ if (touchEnded) {
347
+ this.dragging = false;
348
+ }
349
+ }
135
350
  }
136
351
  onMouseDown() {
137
352
  this.dragging = true;
@@ -1795,9 +2010,17 @@ var KeyInputManager = class {
1795
2010
  this.shouldCaptureKeyPress = shouldCaptureKeyPress;
1796
2011
  this.keys = /* @__PURE__ */ new Map();
1797
2012
  this.eventHandlerCollection = new EventHandlerCollection();
2013
+ this.directionJoystick = null;
1798
2014
  this.eventHandlerCollection.add(document, "keydown", this.onKeyDown.bind(this));
1799
2015
  this.eventHandlerCollection.add(document, "keyup", this.onKeyUp.bind(this));
1800
2016
  this.eventHandlerCollection.add(window, "blur", this.handleUnfocus.bind(this));
2017
+ this.directionJoystick = new VirtualJoystick({
2018
+ radius: 70,
2019
+ inner_radius: 20,
2020
+ x: 70,
2021
+ y: 0,
2022
+ mouse_support: false
2023
+ });
1801
2024
  }
1802
2025
  handleUnfocus(_event) {
1803
2026
  this.keys.clear();
@@ -1821,19 +2044,19 @@ var KeyInputManager = class {
1821
2044
  return this.keys.get(key) || false;
1822
2045
  }
1823
2046
  isMovementKeyPressed() {
1824
- return ["w" /* W */, "a" /* A */, "s" /* S */, "d" /* D */].some((key) => this.isKeyPressed(key));
2047
+ return ["w" /* W */, "a" /* A */, "s" /* S */, "d" /* D */].some((key) => this.isKeyPressed(key)) || this.directionJoystick.hasDirection;
1825
2048
  }
1826
2049
  get forward() {
1827
- return this.isKeyPressed("w" /* W */);
2050
+ return this.isKeyPressed("w" /* W */) || this.directionJoystick.up;
1828
2051
  }
1829
2052
  get backward() {
1830
- return this.isKeyPressed("s" /* S */);
2053
+ return this.isKeyPressed("s" /* S */) || this.directionJoystick.down;
1831
2054
  }
1832
2055
  get left() {
1833
- return this.isKeyPressed("a" /* A */);
2056
+ return this.isKeyPressed("a" /* A */) || this.directionJoystick.left;
1834
2057
  }
1835
2058
  get right() {
1836
- return this.isKeyPressed("d" /* D */);
2059
+ return this.isKeyPressed("d" /* D */) || this.directionJoystick.right;
1837
2060
  }
1838
2061
  get run() {
1839
2062
  return this.isKeyPressed("shift" /* SHIFT */);