/Resources/ui/screens/ARScreen.js
JavaScript | 618 lines | 412 code | 36 blank | 170 comment | 23 complexity | 77ba1a8505e40b792c9c9bbf22d5b131 MD5 | raw file
Possible License(s): Apache-2.0
1/*
2 * ARScreen
3 * ==========
4 *
5 * This file contains the Augmented Reality window.
6 *
7 * It displays the data from google place.
8 *
9 * Using callbacks to process the next stage of the build
10 *
11 */
12
13/*
14 * Load the required modules for this function
15 */
16var layout = require('/ui/layout');
17var images = require('/ui/images');
18var common = require('/tools/common');
19var persHandler = require('/tools/persHandler');
20var augmentedReality = require('/tools/augmentedReality');
21var androidPlatform = null;
22
23/*
24 * The variables needed to pass views around for changes...
25 */
26
27var arWin = null;
28var arBaseView = null;
29var arRadarImg = null;
30var googleData = null;
31var cameraView = null;
32var poiView1 = null;
33var poiView2 = null;
34var poiView3 = null;
35var poiView4 = null;
36var screenWidth = parseInt(persHandler.retPersData({
37 type : 'width'
38}), 10);
39var screenHeight = parseInt(persHandler.retPersData({
40 type : 'height'
41}), 10);
42
43/*
44 * The required flags to only allow processing when the processing is not already happening
45 */
46
47var rotateFlag = true;
48
49/*
50 * showARDetail
51 * ============
52 *
53 * This function create a view of the POI's data and then displays it over
54 * the AR view. When closed it cleans up the View and variables.
55 *
56 */
57function showARDetail(inParam)
58{
59 var arDetailView = Ti.UI.createView({
60 top : 0,
61 left : 0,
62 right : 0,
63 bottom : 0,
64 backgroundColor : layout.css.ar.detail.bkc,
65 opacity : 0.75,
66 zIndex : 125
67 });
68 var arDetailTitle = Ti.UI.createLabel({
69 top : '75dp',
70 height : '50dp',
71 left : '30dp',
72 right : '30dp',
73 text : inParam.TITLE,
74 textAlign : 'center',
75 color : layout.css.ar.detail.fc,
76 font : {
77 fontFamily : layout.css.hs.tbfnf,
78 fontWeight : layout.css.hs.tbfnw,
79 fontSize : layout.css.hs.tbfns
80 }
81 });
82 var arDetailDesc = Ti.UI.createTextArea({
83 top : '130dp',
84 height : '300dp',
85 left : '30dp',
86 right : '30dp',
87 backgroundColor : 'transparent',
88 editable : false,
89 value : inParam.DESC,
90 textAlign : 'center',
91 color : layout.css.ar.detail.fc,
92 font : {
93 fontFamily : layout.css.hs.tbfnf,
94 fontWeight : layout.css.hs.tbfnw,
95 fontSize : layout.css.hs.tbfns
96 }
97 });
98 arDetailView.add(arDetailTitle);
99 arDetailView.add(arDetailDesc);
100
101 /*
102 * The close button
103 */
104 var arDetailClose = Ti.UI.createLabel({
105 bottom : '25dp',
106 width : layout.css.butt.wi,
107 height : layout.css.butt.hi,
108 text : Ti.Locale.getString('butt_close'),
109 textAlign : layout.css.butt.ta,
110 backgroundColor : layout.css.butt.bkc,
111 color : layout.css.butt.fc,
112 borderRadius : layout.css.butt.br,
113 borderWidth : layout.css.butt.bw,
114 borderColor : layout.css.butt.bc,
115 font : {
116 fontFamily : layout.css.butt.ff,
117 fontWeight : layout.css.butt.fw,
118 fontSize : layout.css.butt.fs
119 },
120 zIndex : 150
121 });
122 arDetailView.add(arDetailClose);
123 /*
124 * The event listeners to facilitate actions
125 */
126 arDetailClose.addEventListener('touchstart', function()
127 {
128 arDetailClose.backgroundColor = layout.css.butt.tbkc;
129 arDetailClose.borderColor = layout.css.butt.tbc;
130 arDetailClose.color = layout.css.butt.tfc;
131 });
132 arDetailClose.addEventListener('touchend', function()
133 {
134 arDetailClose.backgroundColor = layout.css.butt.bkc;
135 arDetailClose.borderColor = layout.css.butt.bc;
136 arDetailClose.color = layout.css.butt.fc;
137 arBaseView.remove(arDetailView);
138 arDetailView = null;
139 });
140 arBaseView.add(arDetailView);
141}
142
143/*
144 * rotateDisplay
145 * =============
146 *
147 * These function rotates the Augmented Reality Display as the device is rotated
148 *
149 * The right is set as opposed to the left as it rotates the screen correctly. If the
150 * left position of the view is set it rotates the display in the opposite direction.
151 *
152 */
153function removeFlag()
154{
155 rotateFlag = false;
156}
157
158function rotateDisplay()
159{
160 if(!rotateFlag) {
161 rotateFlag = true;
162 var currBearing = parseInt(persHandler.retPersData({
163 type : 'bearing'
164 }), 10);
165 if(currBearing <= 90) {
166 poiView1.right = ((currBearing - 0) * (screenWidth / 90)) + (screenWidth * 3);
167 poiView2.right = poiView1.right - screenWidth;
168 poiView3.right = poiView2.right - screenWidth;
169 poiView4.right = poiView1.right + screenWidth;
170 }
171 else
172 if(currBearing <= 180) {
173 poiView2.right = ((currBearing - 90) * (screenWidth / 90)) + (screenWidth * 3);
174 poiView3.right = poiView2.right - screenWidth;
175 poiView4.right = poiView3.right - screenWidth;
176 poiView1.right = poiView2.right + screenWidth;
177 }
178 else
179 if(currBearing <= 270) {
180 poiView3.right = ((currBearing - 180) * (screenWidth / 90)) + (screenWidth * 3);
181 poiView4.right = poiView3.right - screenWidth;
182 poiView1.right = poiView4.right - screenWidth;
183 poiView2.right = poiView3.right + screenWidth;
184 }
185 else {
186 poiView4.right = ((currBearing - 270) * (screenWidth / 90)) + (screenWidth * 3);
187 poiView1.right = poiView4.right - screenWidth;
188 poiView2.right = poiView1.right - screenWidth;
189 poiView3.right = poiView4.right + screenWidth;
190 }
191 arRadarImg.transform = Ti.UI.create2DMatrix().rotate(-augmentedReality.toDegree(augmentedReality.toRadius(currBearing)));
192
193 removeFlag();
194 }
195}
196
197/*
198 * displayOverlay
199 * ==============
200 *
201 * This function displays the AR view either through the camera or
202 */
203function displayOverlay()
204{
205 /*
206 * camearView
207 * ==========
208 *
209 * This section displays the view through the camera, using the overlay created.
210 *
211 * If there is no camera, it adds the overlay to the base window.
212 */
213 //if (androidPlatform) { cameraView = false ;}
214 if(cameraView) {
215 Ti.Media.showCamera({
216 success : function(event)
217 {
218 },
219 cancel : function()
220 {
221 },
222 error : function(error)
223 {
224 if(error.code == Ti.Media.NO_CAMERA) {
225 common.launchEvent({
226 TYPE : 'ERROR',
227 MESS : 'E0006'
228 });
229 }
230 else {
231 common.launchEvent({
232 TYPE : 'ERROR',
233 MESS : 'E0006'
234 });
235 }
236 },
237 mediaTypes : [Ti.Media.MEDIA_TYPE_VIDEO, Ti.Media.MEDIA_TYPE_PHOTO],
238 showControls : false,
239 autohide : false,
240 autofocus : "off",
241 animated : false,
242 overlay : arBaseView
243 });
244 }
245 else {
246 arWin.add(arBaseView);
247 }
248}
249
250/*
251 * startMovement
252 * =============
253 *
254 * This function starts the movement of the display and places the radar blips
255 * and display panels in the right position.
256 *
257 */
258function startMovement()
259{
260 /*
261 * Now set the screen position of blips and POI's
262 */
263 displayOverlay();
264 rotateFlag = false;
265 rotateDisplay();
266}
267
268/*
269 * addPOIEvent
270 * ===========
271 *
272 * This function creates and event listener for each POI.
273 *
274 * It has been separated from the loop as it is bad practice to add
275 * event listeners in the loop.
276 *
277 */
278function addPOIEvent(inParam)
279{
280 inParam.VIEW.addEventListener('click', function()
281 {
282 showARDetail({
283 TITLE : googleData[inParam.POS].name,
284 DESC : googleData[inParam.POS].vicinity
285 });
286 });
287}
288
289/*
290 * buildARData
291 * ==========
292 *
293 * This function builds the AR Data.
294 *
295 * It takes the passed google data shows the POI's icon and positions it onto the relevant
296 * view in relation to its heading.
297 *
298 * It also scales the Icon depending on the distance away from the current location.
299 *
300 * Finally creating the blips for the radar display.
301 */
302
303function buildARData(callBack)
304{
305 for(var iPos = 0; iPos < googleData.length; iPos++) {
306 // The POI's
307 var scale = (10 / googleData[iPos].distance).toFixed(2);
308
309 if(scale >= 1) {
310 scale = 1.00;
311 }
312 if(scale <= 0.35) {
313 scale = 0.35;
314 }
315 var tmpDegCal = 0;
316 var tmpView = null;
317
318 if(googleData[iPos].degree <= 45 || googleData[iPos].degree >= 315) {
319 tmpDegCal = -45;
320 tmpView = poiView1;
321 }
322 else
323 if(googleData[iPos].degree <= 135) {
324 tmpDegCal = 45;
325 tmpView = poiView2;
326 }
327 else
328 if(googleData[iPos].degree <= 225) {
329 tmpDegCal = 135;
330 tmpView = poiView3;
331 }
332 else {
333 tmpDegCal = 225;
334 tmpView = poiView4;
335 }
336 var tmpLeft = ((googleData[iPos].degree - tmpDegCal) * (screenWidth / 90)) - ((layout.css.ar.detail.ics * scale) / 2);
337 var tmpTop = (screenHeight / 2) * scale;
338
339 if((tmpLeft + ((layout.css.ar.detail.ics * scale / 2))) >= screenWidth) {
340 tmpLeft = screenWidth - (layout.css.ar.detail.ics * scale);
341 }
342 if(tmpLeft <= 0) {
343 tmpLeft = 0;
344 }
345 var poiItem = Ti.UI.createImageView({
346 height : layout.css.ar.detail.ics * scale,
347 width : layout.css.ar.detail.ics * scale,
348 left : tmpLeft,
349 top : tmpTop,
350 image : googleData[iPos].icon
351 });
352 addPOIEvent({
353 VIEW : poiItem,
354 POS : iPos
355 });
356
357 tmpView.add(poiItem);
358 tmpView = null;
359
360 // The Radar Blips ....
361 var ro = ((images.file.radar.wCalc) * (googleData[iPos].distance.toFixed(4) / 1000) / 2);
362 var centerX = ((images.file.radar.wCalc) / 2) + (ro * Math.sin(googleData[iPos].bearing));
363 var centerY = ((images.file.radar.wCalc) / 2) - (ro * Math.cos(googleData[iPos].bearing));
364
365 var displayBlip = Ti.UI.createView({
366 height : layout.css.ar.blip.height,
367 width : layout.css.ar.blip.width,
368 backgroundColor : layout.css.ar.blip.color,
369 borderRadius : 2,
370 top : centerY - 1,
371 left : centerX - 1,
372 lat : googleData[iPos].location.lat,
373 lng : googleData[iPos].location.lng
374 });
375 arRadarImg.add(displayBlip);
376 }
377 startMovement();
378}
379
380/*
381 * buildARDisplay
382 * ==============
383 *
384 * This function builds the main display panels and adds the data to the screen.
385 *
386 * This function requires some explanation as to why it is done this way.
387 *
388 * In AR most solutions display all the POI's on the screen and then moves them
389 * around hiding and showing the ones required.
390 *
391 * This takes a lot of processing and means that you get a jerky display.
392 *
393 * The solution below uses 4 views each representing a 90degree angle. The POI's
394 * are then positioned within these views and the views moved.
395 *
396 */
397function buildARDisplay(callBack)
398{
399 var poiDisplay = Ti.UI.createView({
400 top : 0,
401 height : screenHeight,
402 left : 0 - (screenWidth * 3),
403 width : (screenWidth * 7),
404 backgroundColor : 'transparent',
405 zIndex : 50
406 });
407 poiView1 = Ti.UI.createView({
408 top : 0,
409 height : screenHeight,
410 right : 0,
411 width : screenWidth
412 });
413 poiView2 = Ti.UI.createView({
414 top : 0,
415 height : screenHeight,
416 right : screenWidth,
417 width : screenWidth
418 });
419 poiView3 = Ti.UI.createView({
420 top : 0,
421 height : screenHeight,
422 right : (screenWidth * 2),
423 width : screenWidth
424 });
425 poiView4 = Ti.UI.createView({
426 top : 0,
427 height : screenHeight,
428 right : -screenWidth,
429 width : screenWidth
430 });
431 poiDisplay.add(poiView1);
432 poiDisplay.add(poiView2);
433 poiDisplay.add(poiView3);
434 poiDisplay.add(poiView4);
435
436 arBaseView.add(poiDisplay);
437
438 if(callBack) {
439 callBack();
440 }
441}
442
443function buildAROverlay()
444{
445 /*
446 * Build the parent AR view
447 *
448 * This view is crucial to how the whole AR display works as you will see as the display is
449 * developed.
450 *
451 * We initially have a single screen sized view with a transparent background containing the
452 * Radar image. This is set with a zIndex of 10 and will always be behind the other views.
453 *
454 */
455 arBaseView = Ti.UI.createView({
456 top : 0,
457 left : 0,
458 right : 0,
459 bottom : 0,
460 backgroundColor : 'transparent',
461 zIndex : 10
462 });
463
464 /*
465 * The radar image
466 *
467 * The radar displays blips of the POI's giving an indication of the direction of
468 * the POI's
469 *
470 * Positioned top right.
471 *
472 */
473 var arRadarBck = Ti.UI.createView({
474 top : '10dp',
475 right : '10dp',
476 height : images.file.radar.height,
477 width : images.file.radar.width,
478 backgroundImage : images.file.radar.file,
479 zIndex : 30
480 });
481 /*
482 * The radar view to rotate the blips...
483 */
484 arRadarImg = Ti.UI.createView({
485 top : 0,
486 left : 0,
487 height : images.file.radar.height,
488 width : images.file.radar.width,
489 backgroundcolor : 'transparent',
490 zIndex : 31
491 });
492 /*
493 * Add the window components
494 */
495 arRadarBck.add(arRadarImg);
496 arBaseView.add(arRadarBck);
497
498 /*
499 * The close button
500 */
501 var closeButton = Ti.UI.createLabel({
502 bottom : '25dp',
503 width : layout.css.butt.wi,
504 height : layout.css.butt.hi,
505 text : Ti.Locale.getString('butt_close'),
506 textAlign : layout.css.butt.ta,
507 backgroundColor : layout.css.butt.bkc,
508 color : layout.css.butt.fc,
509 borderRadius : layout.css.butt.br,
510 borderWidth : layout.css.butt.bw,
511 borderColor : layout.css.butt.bc,
512 font : {
513 fontFamily : layout.css.butt.ff,
514 fontWeight : layout.css.butt.fw,
515 fontSize : layout.css.butt.fs
516 },
517 zIndex : 75
518 });
519 arBaseView.add(closeButton);
520 /*
521 * The event listeners to facilitate actions
522 */
523 closeButton.addEventListener('touchstart', function()
524 {
525 closeButton.backgroundColor = layout.css.butt.tbkc;
526 closeButton.borderColor = layout.css.butt.tbc;
527 closeButton.color = layout.css.butt.tfc;
528 });
529 closeButton.addEventListener('touchend', function()
530 {
531 closeButton.backgroundColor = layout.css.butt.bkc;
532 closeButton.borderColor = layout.css.butt.bc;
533 closeButton.color = layout.css.butt.fc;
534 if(cameraView) {
535 if(!androidPlatform) {
536 Ti.Media.hideCamera();
537 }
538 }
539 cameraView = null;
540 /*
541 * Now return control to the controller.
542 */
543 common.launchEvent({
544 TYPE : 'startApp'
545 });
546 });
547 /*
548 * Making it legal adding the google logo as required for using places.
549 */
550 var googleLogo = Ti.UI.createImageView({
551 bottom : '5dp',
552 right : '5dp',
553 height : images.file.google.height,
554 width : images.file.google.width,
555 image : images.file.google.file
556 });
557 arBaseView.add(googleLogo);
558
559 /*
560 * build the radar blips
561 */
562 buildARDisplay(function()
563 {
564 buildARData();
565 });
566
567 return;
568}
569
570function loadARScreen(inParams)
571{
572 /*
573 * Load the data in
574 */
575 googleData = inParams.DATA;
576 cameraView = inParams.SERVICES.camera;
577 androidPlatform = inParams.ANDROID;
578
579 arWin = Ti.UI.createWindow({
580 backgroundColor : layout.css.sbkc.hs,
581 navBarHidden : true,
582 exitOnClose : false,
583 orientationModes : [Ti.UI.PORTRAIT]
584 });
585 /*
586 * Set orientation fixed for Android
587 */
588 arWin.orientationModes = [Ti.UI.PORTRAIT];
589
590 /*
591 * Add a close event listener to clean everything up nicely.
592 */
593 arWin.addEventListener('close', function()
594 {
595 arWin = null;
596 arBaseView = null;
597 arRadarImg = null;
598 googleData = null;
599 });
600
601 /*
602 * Open the window here so we can process the data separately.
603 */
604 arWin.open();
605
606 /*
607 * Build the data display
608 */
609 buildAROverlay();
610
611 return arWin;
612}
613
614/*
615 * Export the required functions for access
616 */
617exports.loadARScreen = loadARScreen;
618exports.rotateDisplay = rotateDisplay;