Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
FogNetwork
GitHub Repository: FogNetwork/Tsunami
Path: blob/main/public/games/files/pacman/js/virtualjoystick.js
1036 views
1
var VirtualJoystick = function(opts)
2
{
3
opts = opts || {};
4
this._container = opts.container || document.body;
5
this._strokeStyle = opts.strokeStyle || 'cyan';
6
this._stickEl = opts.stickElement || this._buildJoystickStick();
7
this._baseEl = opts.baseElement || this._buildJoystickBase();
8
this._mouseSupport = opts.mouseSupport !== undefined ? opts.mouseSupport : false;
9
this._stationaryBase = opts.stationaryBase || false;
10
this._baseX = this._stickX = opts.baseX || 0
11
this._baseY = this._stickY = opts.baseY || 0
12
this._limitStickTravel = opts.limitStickTravel || false
13
this._stickRadius = opts.stickRadius !== undefined ? opts.stickRadius : 100
14
this._useCssTransform = opts.useCssTransform !== undefined ? opts.useCssTransform : false
15
16
this._container.style.position = "relative"
17
18
this._container.appendChild(this._baseEl)
19
this._baseEl.style.position = "absolute"
20
this._baseEl.style.display = "none"
21
this._container.appendChild(this._stickEl)
22
this._stickEl.style.position = "absolute"
23
this._stickEl.style.display = "none"
24
25
this._pressed = false;
26
this._touchIdx = null;
27
28
if(this._stationaryBase === true){
29
this._baseEl.style.display = "";
30
this._baseEl.style.left = (this._baseX - this._baseEl.width /2)+"px";
31
this._baseEl.style.top = (this._baseY - this._baseEl.height/2)+"px";
32
}
33
34
this._transform = this._useCssTransform ? this._getTransformProperty() : false;
35
this._has3d = this._check3D();
36
37
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
38
this._$onTouchStart = __bind(this._onTouchStart , this);
39
this._$onTouchEnd = __bind(this._onTouchEnd , this);
40
this._$onTouchMove = __bind(this._onTouchMove , this);
41
this._container.addEventListener( 'touchstart' , this._$onTouchStart , false );
42
this._container.addEventListener( 'touchend' , this._$onTouchEnd , false );
43
this._container.addEventListener( 'touchmove' , this._$onTouchMove , false );
44
if( this._mouseSupport ){
45
this._$onMouseDown = __bind(this._onMouseDown , this);
46
this._$onMouseUp = __bind(this._onMouseUp , this);
47
this._$onMouseMove = __bind(this._onMouseMove , this);
48
this._container.addEventListener( 'mousedown' , this._$onMouseDown , false );
49
this._container.addEventListener( 'mouseup' , this._$onMouseUp , false );
50
this._container.addEventListener( 'mousemove' , this._$onMouseMove , false );
51
}
52
}
53
54
VirtualJoystick.prototype.destroy = function()
55
{
56
this._container.removeChild(this._baseEl);
57
this._container.removeChild(this._stickEl);
58
59
this._container.removeEventListener( 'touchstart' , this._$onTouchStart , false );
60
this._container.removeEventListener( 'touchend' , this._$onTouchEnd , false );
61
this._container.removeEventListener( 'touchmove' , this._$onTouchMove , false );
62
if( this._mouseSupport ){
63
this._container.removeEventListener( 'mouseup' , this._$onMouseUp , false );
64
this._container.removeEventListener( 'mousedown' , this._$onMouseDown , false );
65
this._container.removeEventListener( 'mousemove' , this._$onMouseMove , false );
66
}
67
}
68
69
/**
70
* @returns {Boolean} true if touchscreen is currently available, false otherwise
71
*/
72
VirtualJoystick.touchScreenAvailable = function()
73
{
74
return 'createTouch' in document ? true : false;
75
}
76
77
/**
78
* microevents.js - https://github.com/jeromeetienne/microevent.js
79
*/
80
;(function(destObj){
81
destObj.addEventListener = function(event, fct){
82
if(this._events === undefined) this._events = {};
83
this._events[event] = this._events[event] || [];
84
this._events[event].push(fct);
85
return fct;
86
};
87
destObj.removeEventListener = function(event, fct){
88
if(this._events === undefined) this._events = {};
89
if( event in this._events === false ) return;
90
this._events[event].splice(this._events[event].indexOf(fct), 1);
91
};
92
destObj.dispatchEvent = function(event /* , args... */){
93
if(this._events === undefined) this._events = {};
94
if( this._events[event] === undefined ) return;
95
var tmpArray = this._events[event].slice();
96
for(var i = 0; i < tmpArray.length; i++){
97
var result = tmpArray[i].apply(this, Array.prototype.slice.call(arguments, 1))
98
if( result !== undefined ) return result;
99
}
100
return undefined
101
};
102
})(VirtualJoystick.prototype);
103
104
//////////////////////////////////////////////////////////////////////////////////
105
// //
106
//////////////////////////////////////////////////////////////////////////////////
107
108
VirtualJoystick.prototype.deltaX = function(){ return this._stickX - this._baseX; }
109
VirtualJoystick.prototype.deltaY = function(){ return this._stickY - this._baseY; }
110
111
VirtualJoystick.prototype.up = function(){
112
if( this._pressed === false ) return false;
113
var deltaX = this.deltaX();
114
var deltaY = this.deltaY();
115
if( deltaY >= 0 ) return false;
116
if( Math.abs(deltaX) > 2*Math.abs(deltaY) ) return false;
117
return true;
118
}
119
VirtualJoystick.prototype.down = function(){
120
if( this._pressed === false ) return false;
121
var deltaX = this.deltaX();
122
var deltaY = this.deltaY();
123
if( deltaY <= 0 ) return false;
124
if( Math.abs(deltaX) > 2*Math.abs(deltaY) ) return false;
125
return true;
126
}
127
VirtualJoystick.prototype.right = function(){
128
if( this._pressed === false ) return false;
129
var deltaX = this.deltaX();
130
var deltaY = this.deltaY();
131
if( deltaX <= 0 ) return false;
132
if( Math.abs(deltaY) > 2*Math.abs(deltaX) ) return false;
133
return true;
134
}
135
VirtualJoystick.prototype.left = function(){
136
if( this._pressed === false ) return false;
137
var deltaX = this.deltaX();
138
var deltaY = this.deltaY();
139
if( deltaX >= 0 ) return false;
140
if( Math.abs(deltaY) > 2*Math.abs(deltaX) ) return false;
141
return true;
142
}
143
144
//////////////////////////////////////////////////////////////////////////////////
145
// //
146
//////////////////////////////////////////////////////////////////////////////////
147
148
VirtualJoystick.prototype._onUp = function()
149
{
150
this._pressed = false;
151
this._stickEl.style.display = "none";
152
153
if(this._stationaryBase == false){
154
this._baseEl.style.display = "none";
155
156
this._baseX = this._baseY = 0;
157
this._stickX = this._stickY = 0;
158
}
159
}
160
161
VirtualJoystick.prototype._onDown = function(x, y)
162
{
163
this._pressed = true;
164
if(this._stationaryBase == false){
165
this._baseX = x;
166
this._baseY = y;
167
this._baseEl.style.display = "";
168
this._move(this._baseEl.style, (this._baseX - this._baseEl.width /2), (this._baseY - this._baseEl.height/2));
169
}
170
171
this._stickX = x;
172
this._stickY = y;
173
174
if(this._limitStickTravel === true){
175
var deltaX = this.deltaX();
176
var deltaY = this.deltaY();
177
var stickDistance = Math.sqrt( (deltaX * deltaX) + (deltaY * deltaY) );
178
if(stickDistance > this._stickRadius){
179
var stickNormalizedX = deltaX / stickDistance;
180
var stickNormalizedY = deltaY / stickDistance;
181
182
this._stickX = stickNormalizedX * this._stickRadius + this._baseX;
183
this._stickY = stickNormalizedY * this._stickRadius + this._baseY;
184
}
185
}
186
187
this._stickEl.style.display = "";
188
this._move(this._stickEl.style, (this._stickX - this._stickEl.width /2), (this._stickY - this._stickEl.height/2));
189
}
190
191
VirtualJoystick.prototype._onMove = function(x, y)
192
{
193
if( this._pressed === true ){
194
this._stickX = x;
195
this._stickY = y;
196
197
if(this._limitStickTravel === true){
198
var deltaX = this.deltaX();
199
var deltaY = this.deltaY();
200
var stickDistance = Math.sqrt( (deltaX * deltaX) + (deltaY * deltaY) );
201
if(stickDistance > this._stickRadius){
202
var stickNormalizedX = deltaX / stickDistance;
203
var stickNormalizedY = deltaY / stickDistance;
204
205
this._stickX = stickNormalizedX * this._stickRadius + this._baseX;
206
this._stickY = stickNormalizedY * this._stickRadius + this._baseY;
207
}
208
}
209
210
this._move(this._stickEl.style, (this._stickX - this._stickEl.width /2), (this._stickY - this._stickEl.height/2));
211
}
212
}
213
214
215
//////////////////////////////////////////////////////////////////////////////////
216
// bind touch events (and mouse events for debug) //
217
//////////////////////////////////////////////////////////////////////////////////
218
219
VirtualJoystick.prototype._onMouseUp = function(event)
220
{
221
return this._onUp();
222
}
223
224
VirtualJoystick.prototype._onMouseDown = function(event)
225
{
226
event.preventDefault();
227
var x = event.clientX;
228
var y = event.clientY;
229
return this._onDown(x, y);
230
}
231
232
VirtualJoystick.prototype._onMouseMove = function(event)
233
{
234
var x = event.clientX;
235
var y = event.clientY;
236
return this._onMove(x, y);
237
}
238
239
//////////////////////////////////////////////////////////////////////////////////
240
// comment //
241
//////////////////////////////////////////////////////////////////////////////////
242
243
VirtualJoystick.prototype._onTouchStart = function(event)
244
{
245
// if there is already a touch inprogress do nothing
246
if( this._touchIdx !== null ) return;
247
248
// notify event for validation
249
var isValid = this.dispatchEvent('touchStartValidation', event);
250
if( isValid === false ) return;
251
252
// dispatch touchStart
253
this.dispatchEvent('touchStart', event);
254
255
event.preventDefault();
256
// get the first who changed
257
var touch = event.changedTouches[0];
258
// set the touchIdx of this joystick
259
this._touchIdx = touch.identifier;
260
261
// forward the action
262
var x = touch.pageX;
263
var y = touch.pageY;
264
return this._onDown(x, y)
265
}
266
267
VirtualJoystick.prototype._onTouchEnd = function(event)
268
{
269
// if there is no touch in progress, do nothing
270
if( this._touchIdx === null ) return;
271
272
// dispatch touchEnd
273
this.dispatchEvent('touchEnd', event);
274
275
// try to find our touch event
276
var touchList = event.changedTouches;
277
for(var i = 0; i < touchList.length && touchList[i].identifier !== this._touchIdx; i++);
278
// if touch event isnt found,
279
if( i === touchList.length) return;
280
281
// reset touchIdx - mark it as no-touch-in-progress
282
this._touchIdx = null;
283
284
//??????
285
// no preventDefault to get click event on ios
286
event.preventDefault();
287
288
return this._onUp()
289
}
290
291
VirtualJoystick.prototype._onTouchMove = function(event)
292
{
293
// if there is no touch in progress, do nothing
294
if( this._touchIdx === null ) return;
295
296
// try to find our touch event
297
var touchList = event.changedTouches;
298
for(var i = 0; i < touchList.length && touchList[i].identifier !== this._touchIdx; i++ );
299
// if touch event with the proper identifier isnt found, do nothing
300
if( i === touchList.length) return;
301
var touch = touchList[i];
302
303
event.preventDefault();
304
305
var x = touch.pageX;
306
var y = touch.pageY;
307
return this._onMove(x, y)
308
}
309
310
311
//////////////////////////////////////////////////////////////////////////////////
312
// build default stickEl and baseEl //
313
//////////////////////////////////////////////////////////////////////////////////
314
315
/**
316
* build the canvas for joystick base
317
*/
318
VirtualJoystick.prototype._buildJoystickBase = function()
319
{
320
var canvas = document.createElement( 'canvas' );
321
canvas.width = 126;
322
canvas.height = 126;
323
324
var ctx = canvas.getContext('2d');
325
ctx.beginPath();
326
ctx.strokeStyle = this._strokeStyle;
327
ctx.lineWidth = 6;
328
ctx.arc( canvas.width/2, canvas.width/2, 40, 0, Math.PI*2, true);
329
ctx.stroke();
330
331
ctx.beginPath();
332
ctx.strokeStyle = this._strokeStyle;
333
ctx.lineWidth = 2;
334
ctx.arc( canvas.width/2, canvas.width/2, 60, 0, Math.PI*2, true);
335
ctx.stroke();
336
337
return canvas;
338
}
339
340
/**
341
* build the canvas for joystick stick
342
*/
343
VirtualJoystick.prototype._buildJoystickStick = function()
344
{
345
var canvas = document.createElement( 'canvas' );
346
canvas.width = 86;
347
canvas.height = 86;
348
var ctx = canvas.getContext('2d');
349
ctx.beginPath();
350
ctx.strokeStyle = this._strokeStyle;
351
ctx.lineWidth = 6;
352
ctx.arc( canvas.width/2, canvas.width/2, 40, 0, Math.PI*2, true);
353
ctx.stroke();
354
return canvas;
355
}
356
357
//////////////////////////////////////////////////////////////////////////////////
358
// move using translate3d method with fallback to translate > 'top' and 'left'
359
// modified from https://github.com/component/translate and dependents
360
//////////////////////////////////////////////////////////////////////////////////
361
362
VirtualJoystick.prototype._move = function(style, x, y)
363
{
364
if (this._transform) {
365
if (this._has3d) {
366
style[this._transform] = 'translate3d(' + x + 'px,' + y + 'px, 0)';
367
} else {
368
style[this._transform] = 'translate(' + x + 'px,' + y + 'px)';
369
}
370
} else {
371
style.left = x + 'px';
372
style.top = y + 'px';
373
}
374
}
375
376
VirtualJoystick.prototype._getTransformProperty = function()
377
{
378
var styles = [
379
'webkitTransform',
380
'MozTransform',
381
'msTransform',
382
'OTransform',
383
'transform'
384
];
385
386
var el = document.createElement('p');
387
var style;
388
389
for (var i = 0; i < styles.length; i++) {
390
style = styles[i];
391
if (null != el.style[style]) {
392
return style;
393
}
394
}
395
}
396
397
VirtualJoystick.prototype._check3D = function()
398
{
399
var prop = this._getTransformProperty();
400
// IE8<= doesn't have `getComputedStyle`
401
if (!prop || !window.getComputedStyle) return module.exports = false;
402
403
var map = {
404
webkitTransform: '-webkit-transform',
405
OTransform: '-o-transform',
406
msTransform: '-ms-transform',
407
MozTransform: '-moz-transform',
408
transform: 'transform'
409
};
410
411
// from: https://gist.github.com/lorenzopolidori/3794226
412
var el = document.createElement('div');
413
el.style[prop] = 'translate3d(1px,1px,1px)';
414
document.body.insertBefore(el, null);
415
var val = getComputedStyle(el).getPropertyValue(map[prop]);
416
document.body.removeChild(el);
417
var exports = null != val && val.length && 'none' != val;
418
return exports;
419
}
420