PageSourceSearch

https://vc64web.github.io/js/virtualjoystick.js

js vc64web.github.io collected 2026-10-03 10:08:06 UTC 14,545 bytes, 473 lines download raw bytes

1var 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
15	this._container.appendChild(this._baseEl)
16	this._baseEl.style.position	= "absolute"
17	this._baseEl.style.display	= "none"
18	this._container.appendChild(this._stickEl)
19	this._stickEl.style.position	= "absolute"
20	this._stickEl.style.display	= "none"
21
22	this._pressed	= false;
23	this._touchIdx	= null;
24	
25	if(this._stationaryBase === true){
26		this._baseEl.style.display	= "";
27		if(left_handed)
28			this._baseEl.style.right=`min(60px, ((100vw / 2) - ${this._baseEl.width}px) / 2)`;	
29		else
30			this._baseEl.style.left=`min(60px, ((100vw / 2) - ${this._baseEl.width}px) / 2)`;
31
32		this._baseX=this._baseEl.offsetLeft+this._baseEl.width/2;
33
34		let middle=current_vjoy_touch.includes("middle");
35		this._baseEl.style.top=
36		 `calc(${middle?50:90}vh - ${(middle?this._baseEl.height/2:this._baseEl.height) +10}px)`
37		this._baseY=this._baseEl.offsetTop+this._baseEl.height/2;
38	
39	}
40    	
41	var __bind	= function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
42	this._$onTouchStart	= __bind(this._onTouchStart	, this);
43	this._$onTouchEnd	= __bind(this._onTouchEnd	, this);
44	this._$onTouchMove	= __bind(this._onTouchMove	, this);
45	this._container.addEventListener( 'touchstart'	, this._$onTouchStart	, false );
46	this._container.addEventListener( 'touchend'	, this._$onTouchEnd	, false );
47	this._container.addEventListener( 'touchmove'	, this._$onTouchMove	, false );
48	if( this._mouseSupport ){
49		this._$onMouseDown	= __bind(this._onMouseDown	, this);
50		this._$onMouseUp	= __bind(this._onMouseUp	, this);
51		this._$onMouseMove	= __bind(this._onMouseMove	, this);
52		this._container.addEventListener( 'mousedown'	, this._$onMouseDown	, false );
53		this._container.addEventListener( 'mouseup'	, this._$onMouseUp	, false );
54		this._container.addEventListener( 'mousemove'	, this._$onMouseMove	, false );
55	}
56}
57
58VirtualJoystick.prototype.destroy	= function()
59{
60	this._container.removeChild(this._baseEl);
61	this._container.removeChild(this._stickEl);
62
63	this._container.removeEventListener( 'touchstart'	, this._$onTouchStart	, false );
64	this._container.removeEventListener( 'touchend'		, this._$onTouchEnd	, false );
65	this._container.removeEventListener( 'touchmove'	, this._$onTouchMove	, false );
66	if( this._mouseSupport ){
67		this._container.removeEventListener( 'mouseup'		, this._$onMouseUp	, false );
68		this._container.removeEventListener( 'mousedown'	, this._$onMouseDown	, false );
69		this._container.removeEventListener( 'mousemove'	, this._$onMouseMove	, false );
70	}
71}
72
73/**
74 * @returns {Boolean} true if touchscreen is currently available, false otherwise
75*/
76VirtualJoystick.touchScreenAvailable	= function()
77{
78	return 'createTouch' in document ? true : false;
79}
80
81/**
82 * microevents.js - https://github.com/jeromeetienne/microevent.js
83*/
84;(function(destObj){
85	destObj.addEventListener	= function(event, fct){
86		if(this._events === undefined) 	this._events	= {};
87		this._events[event] = this._events[event]	|| [];
88		this._events[event].push(fct);
89		return fct;
90	};
91	destObj.removeEventListener	= function(event, fct){
92		if(this._events === undefined) 	this._events	= {};
93		if( event in this._events === false  )	return;
94		this._events[event].splice(this._events[event].indexOf(fct), 1);
95	};
96	destObj.dispatchEvent		= function(event /* , args... */){
97		if(this._events === undefined) 	this._events	= {};
98		if( this._events[event] === undefined )	return;
99		var tmpArray	= this._events[event].slice(); 
100		for(var i = 0; i < tmpArray.length; i++){
101			var result	= tmpArray[i].apply(this, Array.prototype.slice.call(arguments, 1))
102			if( result !== undefined )	return result;
103		}
104		return undefined
105	};
106})(VirtualJoystick.prototype);
107
108//////////////////////////////////////////////////////////////////////////////////
109//										//
110//////////////////////////////////////////////////////////////////////////////////
111
112VirtualJoystick.prototype.deltaX	= function(){ return this._stickX - this._baseX;	}
113VirtualJoystick.prototype.deltaY	= function(){ return this._stickY - this._baseY;	}
114rest_zone=12;
115VirtualJoystick.prototype.up	= function(){
116	if( this._pressed === false )	return false;
117	//var deltaX	= this.deltaX();
118	var deltaY	= this.deltaY();
119	if( deltaY >= 0 )				return false;
120	//if( Math.abs(deltaX) > 2*Math.abs(deltaY) )	return false;
121	return Math.abs(deltaY)>rest_zone;
122}
123VirtualJoystick.prototype.down	= function(){
124	if( this._pressed === false )	return false;
125	//var deltaX	= this.deltaX();
126	var deltaY	= this.deltaY();
127	if( deltaY <= 0 )				return false;
128	//if( Math.abs(deltaX) > 2*Math.abs(deltaY) )	return false;
129	return Math.abs(deltaY)>rest_zone;
130}
131VirtualJoystick.prototype.right	= function(){
132	if( this._pressed === false )	return false;
133	var deltaX	= this.deltaX();
134	//var deltaY	= this.deltaY();
135	if( deltaX <= 0 )				return false;
136	//if( Math.abs(deltaY) > 2*Math.abs(deltaX) )	return false;
137	return Math.abs(deltaX)>rest_zone;	
138}
139VirtualJoystick.prototype.left	= function(){
140	if( this._pressed === false )	return false;
141	var deltaX	= this.deltaX();
142	//var deltaY	= this.deltaY();
143	if( deltaX >= 0 )				return false;
144	//if( Math.abs(deltaY) > 2*Math.abs(deltaX) )	return false;
145	return Math.abs(deltaX)>rest_zone;
146}
147
148//////////////////////////////////////////////////////////////////////////////////
149//										//
150//////////////////////////////////////////////////////////////////////////////////
151
152VirtualJoystick.prototype._onUp	= function()
153{
154	this._pressed	= false; 
155	this._stickEl.style.display	= "none";
156	
157	if(this._stationaryBase == false){	
158		this._baseEl.style.display	= "none";
159	
160		this._baseX	= this._baseY	= 0;
161		this._stickX	= this._stickY	= 0;
162	}
163}
164
165VirtualJoystick.prototype._onDown	= function(x, y)
166{
167	this._pressed	= true; 
168	if(this._stationaryBase == false){
169		this._baseX	= x;
170		this._baseY	= y;
171		this._baseEl.style.display	= "";
172		this._move(this._baseEl.style, (this._baseX - this._baseEl.width /2), (this._baseY - this._baseEl.height/2));
173	}
174	
175	this._stickX	= x;
176	this._stickY	= y;
177	
178	if(this._limitStickTravel === true){
179		var deltaX	= this.deltaX();
180		var deltaY	= this.deltaY();
181		var stickDistance = Math.sqrt( (deltaX * deltaX) + (deltaY * deltaY) );
182		if(stickDistance > this._stickRadius){
183			var stickNormalizedX = deltaX / stickDistance;
184			var stickNormalizedY = deltaY / stickDistance;
185			
186			this._stickX = stickNormalizedX * this._stickRadius + this._baseX;
187			this._stickY = stickNormalizedY * this._stickRadius + this._baseY;
188		} 	
189	}
190	
191	this._stickEl.style.display	= "";
192	this._move(this._stickEl.style, (this._stickX - this._stickEl.width /2), (this._stickY - this._stickEl.height/2));	
193}
194
195VirtualJoystick.prototype._onMove	= function(x, y)
196{
197	if( this._pressed === true ){
198		this._stickX	= x;
199		this._stickY	= y;
200
201		if(this._limitStickTravel === true){
202			var deltaX	= this.deltaX();
203			var deltaY	= this.deltaY();
204			var stickDistance = Math.sqrt( (deltaX * deltaX) + (deltaY * deltaY) );
205			if(stickDistance > this._stickRadius){
206				var stickNormalizedX = deltaX / stickDistance;
207				var stickNormalizedY = deltaY / stickDistance;
208			
209				this._stickX = stickNormalizedX * this._stickRadius + this._baseX;
210				this._stickY = stickNormalizedY * this._stickRadius + this._baseY;
211			} 		
212
213			//vc64web patch start let the base move too, when innercircle collides with outercircle 
214			if(this._stationaryBase)
215			{
216				this._baseX=this._baseEl.offsetLeft+this._baseEl.width/2;
217				this._baseY=this._baseEl.offsetTop+this._baseEl.height/2;
218			}
219			else
220			{
221				var base_radius = this._baseEl.width/2;
222				if(stickDistance >= base_radius/2){
223					this._baseX	= this._stickX - ((this._stickX - this._baseX)/stickDistance)*base_radius/2; 
224					this._baseY	= this._stickY - ((this._stickY - this._baseY)/stickDistance)*base_radius/2;
225					this._baseEl.style.display	= "";
226					if(!fixed_touch_joystick_base)
227						this._move(this._baseEl.style, (this._baseX - base_radius), (this._baseY - base_radius));	
228				}
229			}
230			//vc64web patch end
231		}
232		
233        this._move(this._stickEl.style, (this._stickX - this._stickEl.width /2), (this._stickY - this._stickEl.height/2));	
234	}	
235}
236
237
238//////////////////////////////////////////////////////////////////////////////////
239//		bind touch events (and mouse events for debug)			//
240//////////////////////////////////////////////////////////////////////////////////
241
242VirtualJoystick.prototype._onMouseUp	= function(event)
243{
244	return this._onUp();
245}
246
247VirtualJoystick.prototype._onMouseDown	= function(event)
248{
249	var isValid	= this.dispatchEvent('touchStartValidation', event);
250	if( isValid === false )	return;
251
252	event.preventDefault();
253	var x	= event.clientX;
254	var y	= event.clientY;
255	return this._onDown(x, y);
256}
257
258VirtualJoystick.prototype._onMouseMove	= function(event)
259{
260	var x	= event.clientX;
261	var y	= event.clientY;
262	return this._onMove(x, y);
263}
264
265//////////////////////////////////////////////////////////////////////////////////
266//		comment								//
267//////////////////////////////////////////////////////////////////////////////////
268
269VirtualJoystick.prototype._onTouchStart	= function(event)
270{
271	// if there is already a touch inprogress do nothing
272//	if( this._touchIdx !== null )	return;
273
274	if(typeof dragItems !== 'undefined' && dragItems.includes(event.target)) return;
275
276	// notify event for validation
277	var isValid	= this.dispatchEvent('touchStartValidation', event);
278	if( isValid === false )	return;
279	
280	// dispatch touchStart
281	this.dispatchEvent('touchStart', event);
282
283	event.preventDefault();
284	// get the first who changed
285	var touch	= event.changedTouches[0];
286	// set the touchIdx of this joystick
287	this._touchIdx	= touch.identifier;
288
289	// forward the action
290	var x		= touch.pageX;
291	var y		= touch.pageY;
292	return this._onDown(x, y)
293}
294
295//touch_check=true;
296VirtualJoystick.prototype._onTouchEnd	= function(event)
297{
298	// if there is no touch in progress, do nothing
299//	if( touch_check && this._touchIdx === null )	return;
300
301	// dispatch touchEnd
302	this.dispatchEvent('touchEnd', event);
303
304	// try to find our touch event
305	var touchList	= event.changedTouches;
306	for(var i = 0; i < touchList.length && touchList[i].identifier !== this._touchIdx; i++);
307	// if touch event isnt found, 
308	if( i === touchList.length)	return;
309
310	// reset touchIdx - mark it as no-touch-in-progress
311	this._touchIdx	= null;
312
313	event.preventDefault();
314
315	return this._onUp()
316}
317
318VirtualJoystick.prototype._onTouchMove	= function(event)
319{
320	// if there is no touch in progress, do nothing
321//	if( touch_check && this._touchIdx === null )	return;
322
323	// try to find our touch event
324	var touchList	= event.changedTouches;
325	for(var i = 0; i < touchList.length && touchList[i].identifier !== this._touchIdx; i++ );
326	// if touch event with the proper identifier isnt found, do nothing
327	if( i === touchList.length)	return;
328	var touch	= touchList[i];
329
330	event.preventDefault();
331
332	var x		= touch.pageX;
333	var y		= touch.pageY;
334	return this._onMove(x, y)
335}
336
337
338//////////////////////////////////////////////////////////////////////////////////
339//		build default stickEl and baseEl				//
340//////////////////////////////////////////////////////////////////////////////////
341
342/**
343 * build the canvas for joystick base
344 */
345VirtualJoystick.prototype._buildJoystickBase	= function()
346{
347	var canvas	= document.createElement( 'canvas' );
348	canvas.width	= 148;
349	canvas.height	= 148;
350	this._drawJoystickBase(canvas);	
351	return canvas;
352}
353
354VirtualJoystick.prototype._drawJoystickBase	= function(canvas)
355{
356	var ctx		= canvas.getContext('2d');	
357	if(this._strokeStyle=='white')
358	{
359		ctx.beginPath();
360		ctx.strokeStyle="rgba(80, 80, 80, 0.5)";
361		ctx.lineWidth	= 28; 
362		ctx.arc(148/2, 148/2, 60, 0, 2*Math.PI);
363		ctx.stroke();
364		
365		ctx.globalCompositeOperation = "destination-out";
366		ctx.lineWidth	= 1; 
367		let path = new Path2D();
368		path.moveTo(5,0);
369		path.lineTo(148,148-5);
370		path.lineTo(148-5,148);
371		path.lineTo(0,5);
372		path.lineTo(5,0);
373		path.moveTo(148-5,0);
374		path.lineTo(0,148-5);
375		path.lineTo(5,148);
376		path.lineTo(148,5);
377		path.lineTo(148-55,0);
378		
379		ctx.fillStyle="rgba(0, 0, 0, 1.0)";
380		ctx.fill(path);	
381		ctx.globalCompositeOperation = 'source-over';
382	}
383	else
384	{
385		ctx.beginPath();
386		ctx.strokeStyle="rgba(255, 0, 0, 0.25)";
387		ctx.lineWidth	= 26; 
388		ctx.arc(148/2, 148/2, 48, 0, 2*Math.PI);
389		ctx.stroke();
390	}
391}
392
393VirtualJoystick.prototype.redraw_base= function(cmd)
394{
395	if(this._strokeStyle=='white')
396	{
397		let ctx=this._baseEl.getContext('2d');	
398		ctx.clearRect(0,0,this._baseEl.width,this._baseEl.height);
399		this._drawJoystickBase(this._baseEl);
400
401		ctx.strokeStyle = this._strokeStyle; 
402		let width=this._baseEl.width;
403		let height=this._baseEl.height;
404		let m=width/2;
405		let w=8;
406		let h=8;
407		let border=10;
408
409		ctx.fillStyle="white"
410		ctx.lineWidth=3;
411
412		ctx.beginPath();
413
414		if(cmd.includes("UP"))
415		{
416			ctx.moveTo(m,border);
417			ctx.lineTo(m+w,border+h);
418			ctx.moveTo(m-w,border+h);
419			ctx.lineTo(m,border);
420		}
421		else if(cmd.includes("DOWN"))
422		{
423			ctx.moveTo(m,height-border);
424			ctx.lineTo(m+w,height-border-h);
425			ctx.moveTo(m-w,height-border-h);
426			ctx.lineTo(m,height-border);
427		}
428		if(cmd.includes("LEFT"))
429		{
430			ctx.moveTo(border,m);
431			ctx.lineTo(border+h,m+w);
432			ctx.moveTo(border+h,m-w);
433			ctx.lineTo(border,m);
434		} 
435		else if(cmd.includes("RIGHT"))
436		{
437			ctx.moveTo(width-border,m);
438			ctx.lineTo(width-border-h,m+w);
439			ctx.moveTo(width-border-h,m-w);
440			ctx.lineTo(width-border,m);
441		}
442		ctx.stroke();
443	}
444}
445
446/**
447 * build the canvas for joystick stick
448 */
449VirtualJoystick.prototype._buildJoystickStick	= function()
450{
451	var canvas	= document.createElement( 'canvas' );
452	canvas.width	= 92;
453	canvas.height	= 92;
454	var ctx		= canvas.getContext('2d');
455	
456	if(this._strokeStyle=='white')
457	{
458		ctx.beginPath(); 
459		ctx.strokeStyle	= "rgba(180,180,180,0.2)"//this._strokeStyle; 
460		ctx.lineWidth	= 10; 
461		ctx.arc( canvas.width/2, canvas.width/2, 38, 0, Math.PI*2, true); 
462		ctx.stroke();
463	}
464	else
465	{
466	}
467	return canvas;
468}
469
470VirtualJoystick.prototype._move = function(style, x, y)
471{
472	style["transform"] = 'translate3d(' + x + 'px,' + y + 'px, 0)';
473}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.