Path: blob/main/public/games/files/pacman/js/virtualjoystick.js
1036 views
var VirtualJoystick = function(opts)1{2opts = opts || {};3this._container = opts.container || document.body;4this._strokeStyle = opts.strokeStyle || 'cyan';5this._stickEl = opts.stickElement || this._buildJoystickStick();6this._baseEl = opts.baseElement || this._buildJoystickBase();7this._mouseSupport = opts.mouseSupport !== undefined ? opts.mouseSupport : false;8this._stationaryBase = opts.stationaryBase || false;9this._baseX = this._stickX = opts.baseX || 010this._baseY = this._stickY = opts.baseY || 011this._limitStickTravel = opts.limitStickTravel || false12this._stickRadius = opts.stickRadius !== undefined ? opts.stickRadius : 10013this._useCssTransform = opts.useCssTransform !== undefined ? opts.useCssTransform : false1415this._container.style.position = "relative"1617this._container.appendChild(this._baseEl)18this._baseEl.style.position = "absolute"19this._baseEl.style.display = "none"20this._container.appendChild(this._stickEl)21this._stickEl.style.position = "absolute"22this._stickEl.style.display = "none"2324this._pressed = false;25this._touchIdx = null;2627if(this._stationaryBase === true){28this._baseEl.style.display = "";29this._baseEl.style.left = (this._baseX - this._baseEl.width /2)+"px";30this._baseEl.style.top = (this._baseY - this._baseEl.height/2)+"px";31}3233this._transform = this._useCssTransform ? this._getTransformProperty() : false;34this._has3d = this._check3D();3536var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };37this._$onTouchStart = __bind(this._onTouchStart , this);38this._$onTouchEnd = __bind(this._onTouchEnd , this);39this._$onTouchMove = __bind(this._onTouchMove , this);40this._container.addEventListener( 'touchstart' , this._$onTouchStart , false );41this._container.addEventListener( 'touchend' , this._$onTouchEnd , false );42this._container.addEventListener( 'touchmove' , this._$onTouchMove , false );43if( this._mouseSupport ){44this._$onMouseDown = __bind(this._onMouseDown , this);45this._$onMouseUp = __bind(this._onMouseUp , this);46this._$onMouseMove = __bind(this._onMouseMove , this);47this._container.addEventListener( 'mousedown' , this._$onMouseDown , false );48this._container.addEventListener( 'mouseup' , this._$onMouseUp , false );49this._container.addEventListener( 'mousemove' , this._$onMouseMove , false );50}51}5253VirtualJoystick.prototype.destroy = function()54{55this._container.removeChild(this._baseEl);56this._container.removeChild(this._stickEl);5758this._container.removeEventListener( 'touchstart' , this._$onTouchStart , false );59this._container.removeEventListener( 'touchend' , this._$onTouchEnd , false );60this._container.removeEventListener( 'touchmove' , this._$onTouchMove , false );61if( this._mouseSupport ){62this._container.removeEventListener( 'mouseup' , this._$onMouseUp , false );63this._container.removeEventListener( 'mousedown' , this._$onMouseDown , false );64this._container.removeEventListener( 'mousemove' , this._$onMouseMove , false );65}66}6768/**69* @returns {Boolean} true if touchscreen is currently available, false otherwise70*/71VirtualJoystick.touchScreenAvailable = function()72{73return 'createTouch' in document ? true : false;74}7576/**77* microevents.js - https://github.com/jeromeetienne/microevent.js78*/79;(function(destObj){80destObj.addEventListener = function(event, fct){81if(this._events === undefined) this._events = {};82this._events[event] = this._events[event] || [];83this._events[event].push(fct);84return fct;85};86destObj.removeEventListener = function(event, fct){87if(this._events === undefined) this._events = {};88if( event in this._events === false ) return;89this._events[event].splice(this._events[event].indexOf(fct), 1);90};91destObj.dispatchEvent = function(event /* , args... */){92if(this._events === undefined) this._events = {};93if( this._events[event] === undefined ) return;94var tmpArray = this._events[event].slice();95for(var i = 0; i < tmpArray.length; i++){96var result = tmpArray[i].apply(this, Array.prototype.slice.call(arguments, 1))97if( result !== undefined ) return result;98}99return undefined100};101})(VirtualJoystick.prototype);102103//////////////////////////////////////////////////////////////////////////////////104// //105//////////////////////////////////////////////////////////////////////////////////106107VirtualJoystick.prototype.deltaX = function(){ return this._stickX - this._baseX; }108VirtualJoystick.prototype.deltaY = function(){ return this._stickY - this._baseY; }109110VirtualJoystick.prototype.up = function(){111if( this._pressed === false ) return false;112var deltaX = this.deltaX();113var deltaY = this.deltaY();114if( deltaY >= 0 ) return false;115if( Math.abs(deltaX) > 2*Math.abs(deltaY) ) return false;116return true;117}118VirtualJoystick.prototype.down = function(){119if( this._pressed === false ) return false;120var deltaX = this.deltaX();121var deltaY = this.deltaY();122if( deltaY <= 0 ) return false;123if( Math.abs(deltaX) > 2*Math.abs(deltaY) ) return false;124return true;125}126VirtualJoystick.prototype.right = function(){127if( this._pressed === false ) return false;128var deltaX = this.deltaX();129var deltaY = this.deltaY();130if( deltaX <= 0 ) return false;131if( Math.abs(deltaY) > 2*Math.abs(deltaX) ) return false;132return true;133}134VirtualJoystick.prototype.left = function(){135if( this._pressed === false ) return false;136var deltaX = this.deltaX();137var deltaY = this.deltaY();138if( deltaX >= 0 ) return false;139if( Math.abs(deltaY) > 2*Math.abs(deltaX) ) return false;140return true;141}142143//////////////////////////////////////////////////////////////////////////////////144// //145//////////////////////////////////////////////////////////////////////////////////146147VirtualJoystick.prototype._onUp = function()148{149this._pressed = false;150this._stickEl.style.display = "none";151152if(this._stationaryBase == false){153this._baseEl.style.display = "none";154155this._baseX = this._baseY = 0;156this._stickX = this._stickY = 0;157}158}159160VirtualJoystick.prototype._onDown = function(x, y)161{162this._pressed = true;163if(this._stationaryBase == false){164this._baseX = x;165this._baseY = y;166this._baseEl.style.display = "";167this._move(this._baseEl.style, (this._baseX - this._baseEl.width /2), (this._baseY - this._baseEl.height/2));168}169170this._stickX = x;171this._stickY = y;172173if(this._limitStickTravel === true){174var deltaX = this.deltaX();175var deltaY = this.deltaY();176var stickDistance = Math.sqrt( (deltaX * deltaX) + (deltaY * deltaY) );177if(stickDistance > this._stickRadius){178var stickNormalizedX = deltaX / stickDistance;179var stickNormalizedY = deltaY / stickDistance;180181this._stickX = stickNormalizedX * this._stickRadius + this._baseX;182this._stickY = stickNormalizedY * this._stickRadius + this._baseY;183}184}185186this._stickEl.style.display = "";187this._move(this._stickEl.style, (this._stickX - this._stickEl.width /2), (this._stickY - this._stickEl.height/2));188}189190VirtualJoystick.prototype._onMove = function(x, y)191{192if( this._pressed === true ){193this._stickX = x;194this._stickY = y;195196if(this._limitStickTravel === true){197var deltaX = this.deltaX();198var deltaY = this.deltaY();199var stickDistance = Math.sqrt( (deltaX * deltaX) + (deltaY * deltaY) );200if(stickDistance > this._stickRadius){201var stickNormalizedX = deltaX / stickDistance;202var stickNormalizedY = deltaY / stickDistance;203204this._stickX = stickNormalizedX * this._stickRadius + this._baseX;205this._stickY = stickNormalizedY * this._stickRadius + this._baseY;206}207}208209this._move(this._stickEl.style, (this._stickX - this._stickEl.width /2), (this._stickY - this._stickEl.height/2));210}211}212213214//////////////////////////////////////////////////////////////////////////////////215// bind touch events (and mouse events for debug) //216//////////////////////////////////////////////////////////////////////////////////217218VirtualJoystick.prototype._onMouseUp = function(event)219{220return this._onUp();221}222223VirtualJoystick.prototype._onMouseDown = function(event)224{225event.preventDefault();226var x = event.clientX;227var y = event.clientY;228return this._onDown(x, y);229}230231VirtualJoystick.prototype._onMouseMove = function(event)232{233var x = event.clientX;234var y = event.clientY;235return this._onMove(x, y);236}237238//////////////////////////////////////////////////////////////////////////////////239// comment //240//////////////////////////////////////////////////////////////////////////////////241242VirtualJoystick.prototype._onTouchStart = function(event)243{244// if there is already a touch inprogress do nothing245if( this._touchIdx !== null ) return;246247// notify event for validation248var isValid = this.dispatchEvent('touchStartValidation', event);249if( isValid === false ) return;250251// dispatch touchStart252this.dispatchEvent('touchStart', event);253254event.preventDefault();255// get the first who changed256var touch = event.changedTouches[0];257// set the touchIdx of this joystick258this._touchIdx = touch.identifier;259260// forward the action261var x = touch.pageX;262var y = touch.pageY;263return this._onDown(x, y)264}265266VirtualJoystick.prototype._onTouchEnd = function(event)267{268// if there is no touch in progress, do nothing269if( this._touchIdx === null ) return;270271// dispatch touchEnd272this.dispatchEvent('touchEnd', event);273274// try to find our touch event275var touchList = event.changedTouches;276for(var i = 0; i < touchList.length && touchList[i].identifier !== this._touchIdx; i++);277// if touch event isnt found,278if( i === touchList.length) return;279280// reset touchIdx - mark it as no-touch-in-progress281this._touchIdx = null;282283//??????284// no preventDefault to get click event on ios285event.preventDefault();286287return this._onUp()288}289290VirtualJoystick.prototype._onTouchMove = function(event)291{292// if there is no touch in progress, do nothing293if( this._touchIdx === null ) return;294295// try to find our touch event296var touchList = event.changedTouches;297for(var i = 0; i < touchList.length && touchList[i].identifier !== this._touchIdx; i++ );298// if touch event with the proper identifier isnt found, do nothing299if( i === touchList.length) return;300var touch = touchList[i];301302event.preventDefault();303304var x = touch.pageX;305var y = touch.pageY;306return this._onMove(x, y)307}308309310//////////////////////////////////////////////////////////////////////////////////311// build default stickEl and baseEl //312//////////////////////////////////////////////////////////////////////////////////313314/**315* build the canvas for joystick base316*/317VirtualJoystick.prototype._buildJoystickBase = function()318{319var canvas = document.createElement( 'canvas' );320canvas.width = 126;321canvas.height = 126;322323var ctx = canvas.getContext('2d');324ctx.beginPath();325ctx.strokeStyle = this._strokeStyle;326ctx.lineWidth = 6;327ctx.arc( canvas.width/2, canvas.width/2, 40, 0, Math.PI*2, true);328ctx.stroke();329330ctx.beginPath();331ctx.strokeStyle = this._strokeStyle;332ctx.lineWidth = 2;333ctx.arc( canvas.width/2, canvas.width/2, 60, 0, Math.PI*2, true);334ctx.stroke();335336return canvas;337}338339/**340* build the canvas for joystick stick341*/342VirtualJoystick.prototype._buildJoystickStick = function()343{344var canvas = document.createElement( 'canvas' );345canvas.width = 86;346canvas.height = 86;347var ctx = canvas.getContext('2d');348ctx.beginPath();349ctx.strokeStyle = this._strokeStyle;350ctx.lineWidth = 6;351ctx.arc( canvas.width/2, canvas.width/2, 40, 0, Math.PI*2, true);352ctx.stroke();353return canvas;354}355356//////////////////////////////////////////////////////////////////////////////////357// move using translate3d method with fallback to translate > 'top' and 'left'358// modified from https://github.com/component/translate and dependents359//////////////////////////////////////////////////////////////////////////////////360361VirtualJoystick.prototype._move = function(style, x, y)362{363if (this._transform) {364if (this._has3d) {365style[this._transform] = 'translate3d(' + x + 'px,' + y + 'px, 0)';366} else {367style[this._transform] = 'translate(' + x + 'px,' + y + 'px)';368}369} else {370style.left = x + 'px';371style.top = y + 'px';372}373}374375VirtualJoystick.prototype._getTransformProperty = function()376{377var styles = [378'webkitTransform',379'MozTransform',380'msTransform',381'OTransform',382'transform'383];384385var el = document.createElement('p');386var style;387388for (var i = 0; i < styles.length; i++) {389style = styles[i];390if (null != el.style[style]) {391return style;392}393}394}395396VirtualJoystick.prototype._check3D = function()397{398var prop = this._getTransformProperty();399// IE8<= doesn't have `getComputedStyle`400if (!prop || !window.getComputedStyle) return module.exports = false;401402var map = {403webkitTransform: '-webkit-transform',404OTransform: '-o-transform',405msTransform: '-ms-transform',406MozTransform: '-moz-transform',407transform: 'transform'408};409410// from: https://gist.github.com/lorenzopolidori/3794226411var el = document.createElement('div');412el.style[prop] = 'translate3d(1px,1px,1px)';413document.body.insertBefore(el, null);414var val = getComputedStyle(el).getPropertyValue(map[prop]);415document.body.removeChild(el);416var exports = null != val && val.length && 'none' != val;417return exports;418}419420