|
1 function RotationSupport(accelerationCallback) { |
|
2 this.controls = new RotationControls(accelerationCallback); |
|
3 } |
|
4 |
|
5 function RotationControls(accelCallback) { |
|
6 this.angleX = 0; |
|
7 this.angleY = 0; |
|
8 this.angleZ = 0; |
|
9 var control = this; |
|
10 this.accelerationCallback = accelCallback; |
|
11 |
|
12 setupListeners("xaxis", "xleft", "xright", updateAngleX, this.angleX); |
|
13 setupListeners("yaxis", "yleft", "yright", updateAngleY, this.angleY); |
|
14 setupListeners("zaxis", "zleft", "zright", updateAngleZ, this.angleZ); |
|
15 |
|
16 window.setTimeout(function() { |
|
17 control.paint(true); |
|
18 }, 50); |
|
19 |
|
20 function setupListeners(inputId, leftArrow, rightArrow, fn, initial) { |
|
21 var input = $("#" + inputId); |
|
22 input.numeric(); |
|
23 input.val(initial); |
|
24 input.change(function() { |
|
25 adjust(input, fn, 0); |
|
26 }); |
|
27 handleButton(leftArrow, input, fn, -1); |
|
28 handleButton(rightArrow, input, fn, 1); |
|
29 } |
|
30 |
|
31 function handleButton(buttonId, input, fn, increment) { |
|
32 var id = false; |
|
33 var timeout = false; |
|
34 var stop = function() { |
|
35 if (timeout) { |
|
36 window.clearTimeout(timeout); |
|
37 timeout = false; |
|
38 adjust(input, fn, increment); |
|
39 } |
|
40 if (id) { |
|
41 window.clearInterval(id); |
|
42 id = false; |
|
43 } |
|
44 }; |
|
45 |
|
46 $("#" + buttonId).mousedown(function() { |
|
47 if (!timeout && !id) { |
|
48 timeout = window.setTimeout(function() { |
|
49 id = window.setInterval(function() { |
|
50 timeout = false; |
|
51 adjust(input, fn, increment); |
|
52 }, 10); |
|
53 }, 250); |
|
54 } |
|
55 }).mouseup(stop).focusout(stop).blur(stop).mouseleave(stop).dblclick( |
|
56 stop); |
|
57 } |
|
58 |
|
59 function adjust(input, callback, increment) { |
|
60 var n = parseInt(input.val()); |
|
61 if (isNaN(n)) { |
|
62 n = 0; |
|
63 } |
|
64 var val = fix(n + increment); |
|
65 input.val(val); |
|
66 callback(val); |
|
67 } |
|
68 |
|
69 function fix(n) { |
|
70 while (n < -180) { |
|
71 n = n + 360; |
|
72 } |
|
73 while (n >= 180) { |
|
74 n = n - 360; |
|
75 } |
|
76 return n; |
|
77 } |
|
78 |
|
79 function updateAngleX(angle) { |
|
80 control.angleX = angle; |
|
81 control.paint(); |
|
82 } |
|
83 |
|
84 function updateAngleY(angle) { |
|
85 control.angleY = angle; |
|
86 control.paint(); |
|
87 } |
|
88 |
|
89 function updateAngleZ(angle) { |
|
90 control.angleZ = angle; |
|
91 control.paint(); |
|
92 } |
|
93 } |
|
94 |
|
95 RotationControls.prototype.paint = function(ignoreListeners) { |
|
96 var width = 50, height = 100, depth = 10; |
|
97 var margin = 5, bottomMargin = 15; |
|
98 |
|
99 var canvas = document.getElementById("phoneposition"); |
|
100 var ctx = canvas.getContext("2d"); |
|
101 ctx.clearRect(0, 0, canvas.width, canvas.height); |
|
102 |
|
103 var r = 62; |
|
104 |
|
105 var xy = (180 - this.angleX) * Math.PI / 180; |
|
106 var yz = (this.angleY - 180) * Math.PI / 180; |
|
107 var xz = (180 - this.angleZ) * Math.PI / 180 + Math.PI / 2; |
|
108 |
|
109 var back = translateBack(xy, xz, yz); |
|
110 if ((back[0].z + back[2].z) / 2 < 0) { |
|
111 paint(canvas, ctx, back); |
|
112 } else { |
|
113 paint(canvas, ctx, translateFace(xy, xz, yz)); |
|
114 paintScreen(canvas, ctx, translateScreen(xy, xz, yz)); |
|
115 } |
|
116 |
|
117 var dz = 0; |
|
118 if (back[0].z > back[3].z) { |
|
119 var bottom = translateBottom(xy, xz, yz); |
|
120 paint(canvas, ctx, bottom); |
|
121 dz = bottom[1].y - bottom[0].y; |
|
122 } else if (back[0].z != back[3].z) { |
|
123 var top = translateTop(xy, xz, yz); |
|
124 paint(canvas, ctx, top); |
|
125 dz = top[1].y - top[0].y; |
|
126 } |
|
127 |
|
128 if (back[1].z > back[0].z) { |
|
129 paint(canvas, ctx, translateLeft(xy, xz, yz)); |
|
130 } else if (back[1].z != back[0].z) { |
|
131 paint(canvas, ctx, translateRight(xy, xz, yz)); |
|
132 } |
|
133 if (!ignoreListeners) { |
|
134 var accelX = (back[1].y - back[0].y) / width; |
|
135 var accelY = (back[0].y - back[3].y) / height; |
|
136 var accelZ = dz / depth; |
|
137 notifyAcceleration(accelX, accelY, accelZ); |
|
138 } |
|
139 function translateFace(xy, xz, yz) { |
|
140 var px = width / 2; |
|
141 var py = height / 2; |
|
142 var pz = depth / 2; |
|
143 var points = [ { |
|
144 x : px, |
|
145 y : py, |
|
146 z : pz |
|
147 }, { |
|
148 x : px, |
|
149 y : -py, |
|
150 z : pz |
|
151 }, { |
|
152 x : -px, |
|
153 y : -py, |
|
154 z : pz |
|
155 }, { |
|
156 x : -px, |
|
157 y : py, |
|
158 z : pz |
|
159 } ]; |
|
160 return rotate(points, xy, xz, yz); |
|
161 } |
|
162 |
|
163 function translateScreen(xy, xz, yz) { |
|
164 var px = width / 2; |
|
165 var py = height / 2; |
|
166 var pz = depth / 2; |
|
167 var points = [ { |
|
168 x : px - margin, |
|
169 y : py - bottomMargin, |
|
170 z : pz |
|
171 }, { |
|
172 x : px - margin, |
|
173 y : -py + bottomMargin, |
|
174 z : pz |
|
175 }, { |
|
176 x : -px + margin, |
|
177 y : -py + margin, |
|
178 z : pz |
|
179 }, { |
|
180 x : -px + margin, |
|
181 y : py - margin, |
|
182 z : pz |
|
183 } ]; |
|
184 return rotate(points, xy, xz, yz); |
|
185 } |
|
186 |
|
187 function translateBack(xy, xz, yz) { |
|
188 var px = width / 2; |
|
189 var py = height / 2; |
|
190 var pz = -depth / 2; |
|
191 var points = [ { |
|
192 x : px, |
|
193 y : py, |
|
194 z : pz |
|
195 }, { |
|
196 x : px, |
|
197 y : -py, |
|
198 z : pz |
|
199 }, { |
|
200 x : -px, |
|
201 y : -py, |
|
202 z : pz |
|
203 }, { |
|
204 x : -px, |
|
205 y : py, |
|
206 z : pz |
|
207 } ]; |
|
208 return rotate(points, xy, xz, yz); |
|
209 } |
|
210 |
|
211 function translateTop(xy, xz, yz) { |
|
212 var px = width / 2; |
|
213 var py = height / 2; |
|
214 var pz = depth / 2; |
|
215 var points = [ { |
|
216 x : px, |
|
217 y : -py, |
|
218 z : pz |
|
219 }, { |
|
220 x : px, |
|
221 y : -py, |
|
222 z : -pz |
|
223 }, { |
|
224 x : px, |
|
225 y : py, |
|
226 z : -pz |
|
227 }, { |
|
228 x : px, |
|
229 y : py, |
|
230 z : pz |
|
231 } ]; |
|
232 return rotate(points, xy, xz, yz); |
|
233 } |
|
234 |
|
235 function translateBottom(xy, xz, yz) { |
|
236 var px = -width / 2; |
|
237 var py = height / 2; |
|
238 var pz = depth / 2; |
|
239 var points = [ { |
|
240 x : px, |
|
241 y : -py, |
|
242 z : pz |
|
243 }, { |
|
244 x : px, |
|
245 y : -py, |
|
246 z : -pz |
|
247 }, { |
|
248 x : px, |
|
249 y : py, |
|
250 z : -pz |
|
251 }, { |
|
252 x : px, |
|
253 y : py, |
|
254 z : pz |
|
255 } ]; |
|
256 return rotate(points, xy, xz, yz); |
|
257 } |
|
258 |
|
259 function translateLeft(xy, xz, yz) { |
|
260 var px = width / 2; |
|
261 var py = height / 2; |
|
262 var pz = depth / 2; |
|
263 var points = [ { |
|
264 x : px, |
|
265 y : py, |
|
266 z : pz |
|
267 }, { |
|
268 x : px, |
|
269 y : py, |
|
270 z : -pz |
|
271 }, { |
|
272 x : -px, |
|
273 y : py, |
|
274 z : -pz |
|
275 }, { |
|
276 x : -px, |
|
277 y : py, |
|
278 z : pz |
|
279 } ]; |
|
280 return rotate(points, xy, xz, yz); |
|
281 } |
|
282 |
|
283 function translateRight(xy, xz, yz) { |
|
284 var px = width / 2; |
|
285 var py = -height / 2; |
|
286 var pz = depth / 2; |
|
287 var points = [ { |
|
288 x : px, |
|
289 y : py, |
|
290 z : pz |
|
291 }, { |
|
292 x : px, |
|
293 y : py, |
|
294 z : -pz |
|
295 }, { |
|
296 x : -px, |
|
297 y : py, |
|
298 z : -pz |
|
299 }, { |
|
300 x : -px, |
|
301 y : py, |
|
302 z : pz |
|
303 } ]; |
|
304 return rotate(points, xy, xz, yz); |
|
305 } |
|
306 |
|
307 function rotate(points, xy, xz, yz) { |
|
308 var res = new Array(); |
|
309 for ( var p in points) { |
|
310 var px = points[p].x; |
|
311 var py = points[p].y; |
|
312 var pz = points[p].z; |
|
313 |
|
314 var rx = Math.sqrt(px * px + py * py); |
|
315 var angXY = Math.atan(px / py) + (px < 0 ? Math.PI : 0); |
|
316 |
|
317 px = rx * Math.sin(angXY + xy); |
|
318 py = rx * Math.cos(angXY + xy); |
|
319 |
|
320 var rz = Math.sqrt(px * px + pz * pz); |
|
321 var angXZ = (px == 0 ? 0 : Math.atan(pz / px)) |
|
322 + (px < 0 ? Math.PI : 0); |
|
323 |
|
324 px = rz * Math.sin(angXZ + xz); |
|
325 pz = rz * Math.cos(angXZ + xz); |
|
326 |
|
327 var ry = Math.sqrt(py * py + pz * pz); |
|
328 var angYZ = (pz == 0 ? 0 : Math.atan(py / pz)) |
|
329 + (pz < 0 ? Math.PI : 0); |
|
330 |
|
331 py = ry * Math.sin(angYZ + yz); |
|
332 pz = ry * Math.cos(angYZ + yz); |
|
333 |
|
334 res.push( { |
|
335 x : px, |
|
336 y : py, |
|
337 z : pz |
|
338 }); |
|
339 } |
|
340 return res; |
|
341 } |
|
342 |
|
343 function paint(canvas, ctx, points) { |
|
344 var xcoord = canvas.width / 2; |
|
345 var ycoord = canvas.height / 2; |
|
346 |
|
347 ctx.fillStyle = "#FAC82F"; |
|
348 ctx.strokeStyle = "black"; |
|
349 ctx.beginPath(); |
|
350 ctx.moveTo(xcoord + points[3].x, ycoord + points[3].y); |
|
351 for (point in points) { |
|
352 ctx.lineTo(xcoord + points[point].x, ycoord + points[point].y); |
|
353 } |
|
354 ctx.fill(); |
|
355 ctx.beginPath(); |
|
356 ctx.moveTo(xcoord + points[3].x, ycoord + points[3].y); |
|
357 for (point in points) { |
|
358 ctx.lineTo(xcoord + points[point].x, ycoord + points[point].y); |
|
359 } |
|
360 ctx.stroke(); |
|
361 } |
|
362 |
|
363 function paintScreen(canvas, ctx, screen) { |
|
364 var xcoord = canvas.width / 2; |
|
365 var ycoord = canvas.height / 2; |
|
366 |
|
367 ctx.fillStyle = "grey"; |
|
368 ctx.beginPath(); |
|
369 ctx.moveTo(xcoord + screen[3].x, ycoord + screen[3].y); |
|
370 for (point in screen) { |
|
371 ctx.lineTo(xcoord + screen[point].x, ycoord + screen[point].y); |
|
372 } |
|
373 ctx.fill(); |
|
374 } |
|
375 |
|
376 function notifyAcceleration(x, y, z) { |
|
377 accelerationCallback(x, y, z); |
|
378 } |
|
379 }; |
|
380 |
|
381 RotationSupport.prototype.setAngles = function(x, y, z) { |
|
382 this.controls.angleX = x; |
|
383 this.controls.angleY = z; // It is extremly messy - this UI was developed |
|
384 // separately from the rest and follows |
|
385 this.controls.angleZ = y; // different conventions |
|
386 |
|
387 $("#xaxis").val(this.controls.angleX); |
|
388 $("#yaxis").val(this.controls.angleY); |
|
389 $("#zaxis").val(this.controls.angleZ); |
|
390 |
|
391 this.controls.paint(true); |
|
392 }; |