└── 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 |
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 |
--------------------------------------------------------------------------------