└── 2d test ├── joy.html ├── js └── joy.js └── style.css /2d test/joy.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Joy 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 |
17 |
18 | Posizione X:
19 | Posizione Y:
20 | Direzione:
21 | X :
22 | Y : 23 |
24 | 25 |
26 | 27 | 28 | 29 | 30 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /2d test/js/joy.js: -------------------------------------------------------------------------------- 1 | let StickStatus = 2 | { 3 | xPosition: 0, 4 | yPosition: 0, 5 | x: 0, 6 | y: 0, 7 | cardinalDirection: "C" 8 | }; 9 | 10 | /** 11 | * @desc Principal object that draw a joystick, you only need to initialize the object and suggest the HTML container 12 | * @costructor 13 | * @param container {String} - HTML object that contains the Joystick 14 | * @param parameters (optional) - object with following keys: 15 | * title {String} (optional) - The ID of canvas (Default value is 'joystick') 16 | * width {Int} (optional) - The width of canvas, if not specified is setted at width of container object (Default value is the width of container object) 17 | * height {Int} (optional) - The height of canvas, if not specified is setted at height of container object (Default value is the height of container object) 18 | * internalFillColor {String} (optional) - Internal color of Stick (Default value is '#00AA00') 19 | * internalLineWidth {Int} (optional) - Border width of Stick (Default value is 2) 20 | * internalStrokeColor {String}(optional) - Border color of Stick (Default value is '#003300') 21 | * externalLineWidth {Int} (optional) - External reference circonference width (Default value is 2) 22 | * externalStrokeColor {String} (optional) - External reference circonference color (Default value is '#008000') 23 | * autoReturnToCenter {Bool} (optional) - Sets the behavior of the stick, whether or not, it should return to zero position when released (Default value is True and return to zero) 24 | * @param callback {StickStatus} - 25 | */ 26 | var JoyStick = (function(container, parameters, callback) 27 | { 28 | parameters = parameters || {}; 29 | var title = (typeof parameters.title === "undefined" ? "joystick" : parameters.title), 30 | width = (typeof parameters.width === "undefined" ? 0 : parameters.width), 31 | height = (typeof parameters.height === "undefined" ? 0 : parameters.height), 32 | internalFillColor = (typeof parameters.internalFillColor === "undefined" ? "#00AA00" : parameters.internalFillColor), 33 | internalLineWidth = (typeof parameters.internalLineWidth === "undefined" ? 2 : parameters.internalLineWidth), 34 | internalStrokeColor = (typeof parameters.internalStrokeColor === "undefined" ? "#003300" : parameters.internalStrokeColor), 35 | externalLineWidth = (typeof parameters.externalLineWidth === "undefined" ? 2 : parameters.externalLineWidth), 36 | externalStrokeColor = (typeof parameters.externalStrokeColor === "undefined" ? "#008000" : parameters.externalStrokeColor), 37 | autoReturnToCenter = (typeof parameters.autoReturnToCenter === "undefined" ? true : parameters.autoReturnToCenter); 38 | 39 | callback = callback || function(StickStatus) {}; 40 | 41 | // Create Canvas element and add it in the Container object 42 | var objContainer = document.getElementById(container); 43 | 44 | // Fixing Unable to preventDefault inside passive event listener due to target being treated as passive in Chrome [Thanks to https://github.com/artisticfox8 for this suggestion] 45 | objContainer.style.touchAction = "none"; 46 | 47 | var canvas = document.createElement("canvas"); 48 | canvas.id = title; 49 | if(width === 0) { width = objContainer.clientWidth; } 50 | if(height === 0) { height = objContainer.clientHeight; } 51 | canvas.width = width; 52 | canvas.height = height; 53 | objContainer.appendChild(canvas); 54 | var context=canvas.getContext("2d"); 55 | 56 | var pressed = 0; // Bool - 1=Yes - 0=No 57 | var circumference = 2 * Math.PI; 58 | var internalRadius = (canvas.width-((canvas.width/2)+10))/2; 59 | var maxMoveStick = internalRadius + 5; 60 | var externalRadius = internalRadius + 30; 61 | var centerX = canvas.width / 2; 62 | var centerY = canvas.height / 2; 63 | var directionHorizontalLimitPos = canvas.width / 10; 64 | var directionHorizontalLimitNeg = directionHorizontalLimitPos * -1; 65 | var directionVerticalLimitPos = canvas.height / 10; 66 | var directionVerticalLimitNeg = directionVerticalLimitPos * -1; 67 | // Used to save current position of stick 68 | var movedX=centerX; 69 | var movedY=centerY; 70 | 71 | // Check if the device support the touch or not 72 | if("ontouchstart" in document.documentElement) 73 | { 74 | canvas.addEventListener("touchstart", onTouchStart, false); 75 | document.addEventListener("touchmove", onTouchMove, false); 76 | document.addEventListener("touchend", onTouchEnd, false); 77 | } 78 | else 79 | { 80 | canvas.addEventListener("mousedown", onMouseDown, false); 81 | document.addEventListener("mousemove", onMouseMove, false); 82 | document.addEventListener("mouseup", onMouseUp, false); 83 | } 84 | // Draw the object 85 | drawExternal(); 86 | drawInternal(); 87 | 88 | /****************************************************** 89 | * Private methods 90 | *****************************************************/ 91 | 92 | /** 93 | * @desc Draw the external circle used as reference position 94 | */ 95 | function drawExternal() 96 | { 97 | context.beginPath(); 98 | context.arc(centerX, centerY, externalRadius, 0, circumference, false); 99 | context.lineWidth = externalLineWidth; 100 | context.strokeStyle = externalStrokeColor; 101 | context.stroke(); 102 | } 103 | 104 | /** 105 | * @desc Draw the internal stick in the current position the user have moved it 106 | */ 107 | function drawInternal() 108 | { 109 | context.beginPath(); 110 | if(movedX canvas.width) { movedX = canvas.width-(maxMoveStick); } 112 | if(movedY canvas.height) { movedY = canvas.height-(maxMoveStick); } 114 | context.arc(movedX, movedY, internalRadius, 0, circumference, false); 115 | // create radial gradient 116 | var grd = context.createRadialGradient(centerX, centerY, 5, centerX, centerY, 200); 117 | // Light color 118 | grd.addColorStop(0, internalFillColor); 119 | // Dark color 120 | grd.addColorStop(1, internalStrokeColor); 121 | context.fillStyle = grd; 122 | context.fill(); 123 | context.lineWidth = internalLineWidth; 124 | context.strokeStyle = internalStrokeColor; 125 | context.stroke(); 126 | } 127 | 128 | /** 129 | * @desc Events for manage touch 130 | */ 131 | function onTouchStart(event) 132 | { 133 | pressed = 1; 134 | } 135 | 136 | function onTouchMove(event) 137 | { 138 | if(pressed === 1 && event.targetTouches[0].target === canvas) 139 | { 140 | movedX = event.targetTouches[0].pageX; 141 | movedY = event.targetTouches[0].pageY; 142 | // Manage offset 143 | if(canvas.offsetParent.tagName.toUpperCase() === "BODY") 144 | { 145 | movedX -= canvas.offsetLeft; 146 | movedY -= canvas.offsetTop; 147 | } 148 | else 149 | { 150 | movedX -= canvas.offsetParent.offsetLeft; 151 | movedY -= canvas.offsetParent.offsetTop; 152 | } 153 | // Delete canvas 154 | context.clearRect(0, 0, canvas.width, canvas.height); 155 | // Redraw object 156 | drawExternal(); 157 | drawInternal(); 158 | 159 | // Set attribute of callback 160 | StickStatus.xPosition = movedX; 161 | StickStatus.yPosition = movedY; 162 | StickStatus.x = (100*((movedX - centerX)/maxMoveStick)).toFixed(); 163 | StickStatus.y = ((100*((movedY - centerY)/maxMoveStick))*-1).toFixed(); 164 | StickStatus.cardinalDirection = getCardinalDirection(); 165 | callback(StickStatus); 166 | } 167 | } 168 | 169 | function onTouchEnd(event) 170 | { 171 | pressed = 0; 172 | // If required reset position store variable 173 | if(autoReturnToCenter) 174 | { 175 | movedX = centerX; 176 | movedY = centerY; 177 | } 178 | // Delete canvas 179 | context.clearRect(0, 0, canvas.width, canvas.height); 180 | // Redraw object 181 | drawExternal(); 182 | drawInternal(); 183 | 184 | // Set attribute of callback 185 | StickStatus.xPosition = movedX; 186 | StickStatus.yPosition = movedY; 187 | StickStatus.x = (100*((movedX - centerX)/maxMoveStick)).toFixed(); 188 | StickStatus.y = ((100*((movedY - centerY)/maxMoveStick))*-1).toFixed(); 189 | StickStatus.cardinalDirection = getCardinalDirection(); 190 | callback(StickStatus); 191 | } 192 | 193 | /** 194 | * @desc Events for manage mouse 195 | */ 196 | function onMouseDown(event) 197 | { 198 | pressed = 1; 199 | } 200 | 201 | /* To simplify this code there was a new experimental feature here: https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/offsetX , but it present only in Mouse case not metod presents in Touch case :-( */ 202 | function onMouseMove(event) 203 | { 204 | if(pressed === 1) 205 | { 206 | movedX = event.pageX; 207 | movedY = event.pageY; 208 | // Manage offset 209 | if(canvas.offsetParent.tagName.toUpperCase() === "BODY") 210 | { 211 | movedX -= canvas.offsetLeft; 212 | movedY -= canvas.offsetTop; 213 | } 214 | else 215 | { 216 | movedX -= canvas.offsetParent.offsetLeft; 217 | movedY -= canvas.offsetParent.offsetTop; 218 | } 219 | // Delete canvas 220 | context.clearRect(0, 0, canvas.width, canvas.height); 221 | // Redraw object 222 | drawExternal(); 223 | drawInternal(); 224 | 225 | // Set attribute of callback 226 | StickStatus.xPosition = movedX; 227 | StickStatus.yPosition = movedY; 228 | StickStatus.x = (100*((movedX - centerX)/maxMoveStick)).toFixed(); 229 | StickStatus.y = ((100*((movedY - centerY)/maxMoveStick))*-1).toFixed(); 230 | StickStatus.cardinalDirection = getCardinalDirection(); 231 | callback(StickStatus); 232 | } 233 | } 234 | 235 | function onMouseUp(event) 236 | { 237 | pressed = 0; 238 | // If required reset position store variable 239 | if(autoReturnToCenter) 240 | { 241 | movedX = centerX; 242 | movedY = centerY; 243 | } 244 | // Delete canvas 245 | context.clearRect(0, 0, canvas.width, canvas.height); 246 | // Redraw object 247 | drawExternal(); 248 | drawInternal(); 249 | 250 | // Set attribute of callback 251 | StickStatus.xPosition = movedX; 252 | StickStatus.yPosition = movedY; 253 | StickStatus.x = (100*((movedX - centerX)/maxMoveStick)).toFixed(); 254 | StickStatus.y = ((100*((movedY - centerY)/maxMoveStick))*-1).toFixed(); 255 | StickStatus.cardinalDirection = getCardinalDirection(); 256 | callback(StickStatus); 257 | } 258 | 259 | function getCardinalDirection() 260 | { 261 | let result = ""; 262 | let orizontal = movedX - centerX; 263 | let vertical = movedY - centerY; 264 | 265 | if(vertical >= directionVerticalLimitNeg && vertical <= directionVerticalLimitPos) 266 | { 267 | result = "C"; 268 | } 269 | if(vertical < directionVerticalLimitNeg) 270 | { 271 | result = "N"; 272 | } 273 | if(vertical > directionVerticalLimitPos) 274 | { 275 | result = "S"; 276 | } 277 | 278 | if(orizontal < directionHorizontalLimitNeg) 279 | { 280 | if(result === "C") 281 | { 282 | result = "W"; 283 | } 284 | else 285 | { 286 | result += "W"; 287 | } 288 | } 289 | if(orizontal > directionHorizontalLimitPos) 290 | { 291 | if(result === "C") 292 | { 293 | result = "E"; 294 | } 295 | else 296 | { 297 | result += "E"; 298 | } 299 | } 300 | 301 | return result; 302 | } 303 | 304 | /****************************************************** 305 | * Public methods 306 | *****************************************************/ 307 | 308 | /** 309 | * @desc The width of canvas 310 | * @return Number of pixel width 311 | */ 312 | this.GetWidth = function () 313 | { 314 | return canvas.width; 315 | }; 316 | 317 | /** 318 | * @desc The height of canvas 319 | * @return Number of pixel height 320 | */ 321 | this.GetHeight = function () 322 | { 323 | return canvas.height; 324 | }; 325 | 326 | /** 327 | * @desc The X position of the cursor relative to the canvas that contains it and to its dimensions 328 | * @return Number that indicate relative position 329 | */ 330 | this.GetPosX = function () 331 | { 332 | return movedX; 333 | }; 334 | 335 | /** 336 | * @desc The Y position of the cursor relative to the canvas that contains it and to its dimensions 337 | * @return Number that indicate relative position 338 | */ 339 | this.GetPosY = function () 340 | { 341 | return movedY; 342 | }; 343 | 344 | /** 345 | * @desc Normalizzed value of X move of stick 346 | * @return Integer from -100 to +100 347 | */ 348 | this.GetX = function () 349 | { 350 | return (100*((movedX - centerX)/maxMoveStick)).toFixed(); 351 | }; 352 | 353 | /** 354 | * @desc Normalizzed value of Y move of stick 355 | * @return Integer from -100 to +100 356 | */ 357 | this.GetY = function () 358 | { 359 | return ((100*((movedY - centerY)/maxMoveStick))*-1).toFixed(); 360 | }; 361 | 362 | /** 363 | * @desc Get the direction of the cursor as a string that indicates the cardinal points where this is oriented 364 | * @return String of cardinal point N, NE, E, SE, S, SW, W, NW and C when it is placed in the center 365 | */ 366 | this.GetDir = function() 367 | { 368 | return getCardinalDirection(); 369 | }; 370 | }); 371 | -------------------------------------------------------------------------------- /2d test/style.css: -------------------------------------------------------------------------------- 1 | /* *{ 2 | margin: 0; 3 | padding: 0; 4 | box-sizing: border-box; 5 | } */ 6 | --------------------------------------------------------------------------------