APIs

Show:
  1. /**
  2. Add block view is a UI component which allows selection and insertion of a GPS location view coords
  3. @class AddBlockLocationView
  4. @constructor
  5. @return {object} instantiated AddBlockLocationView
  6. **/
  7. define(['jquery', 'backbone', 'StackView', 'ScreenTemplateFactory', 'bootbox', 'async'], function ($, Backbone, StackView, ScreenTemplateFactory, Bootbox, async) {
  8.  
  9. /** SERVICES **/
  10. BB.SERVICES.ADD_BLOCK_LOCATION_VIEW = 'googleMapsLocationView';
  11. BB.SERVICES.ADD_BLOCK_LOCATION_SCENE_VIEW = 'googleMapsLocationSceneView';
  12.  
  13. var AddBlockLocationView = BB.View.extend({
  14.  
  15. /**
  16. Constructor
  17. @method initialize
  18. **/
  19. initialize: function (options) {
  20. var self = this;
  21. self.m_map;
  22. self.m_mapPoints = [];
  23. self.m_placement = options.placement;
  24. self.m_loadedMaps = false;
  25. self.m_markerOnClick = false;
  26. self.m_mapData = {points: []};
  27. self._setSimulationMode(false);
  28.  
  29. // Clone the AddBlockTemplate
  30. var e = $(Elements.ADD_BLOCK_LOCATION_TEMPLATE).clone();
  31. $(self.options.el).append(e).fadeIn();
  32.  
  33. var id = _.uniqueId('slideLocSim');
  34. $(Elements.CLASS_LOCATION_SIMULATION_MODE, self.el).attr('id', id);
  35. $('label', self.el).attr('for', BB.lib.unhash(id));
  36. self._listenModeChange('#' + id);
  37.  
  38. $(e).show();
  39. self.el = self.$el[0];
  40.  
  41. $(self.el).find('#prev').on('click', function () {
  42. self._goBack();
  43. return false;
  44. });
  45.  
  46. self.listenTo(self.options.stackView, BB.EVENTS.SELECTED_STACK_VIEW, function (e) {
  47. if (e == self)
  48. self._render();
  49. });
  50.  
  51. self._listenStationRefresh();
  52. },
  53.  
  54. /**
  55. Listen to mode change between simulation mode and real mode
  56. @method _listenModeChange
  57. **/
  58. _listenModeChange: function (i_id) {
  59. var self = this;
  60. self.sliderInput = function () {
  61. var mode = $(i_id).prop('checked');
  62. self._setSimulationMode(mode);
  63. if (mode) {
  64. $(Elements.CLASS_LOCATION_SIMULATION_PROPS, self.el).slideDown();
  65. } else {
  66. $(Elements.CLASS_LOCATION_SIMULATION_PROPS, self.el).slideUp();
  67. }
  68. };
  69. $(i_id, self.el).on('change', self.sliderInput);
  70. },
  71.  
  72. _setSimulationMode: function (i_mode) {
  73. var self = this;
  74. self.m_simulationMode = i_mode;
  75. },
  76.  
  77. _getSimulationMode: function () {
  78. var self = this;
  79. return self.m_simulationMode;
  80. },
  81.  
  82. /**
  83. Listen stations refresh so we rebuild list of available station in the drop down selection
  84. @method _listenStationRefresh
  85. **/
  86. _listenStationRefresh: function () {
  87. var self = this;
  88. $(Elements.CLASS_LOCATION_SIMULATION_PROPS, self.el).find('button').on('click', function () {
  89. self._loadStationList();
  90. });
  91. },
  92.  
  93. /**
  94. Init the google map module. We also create a class for _mapPoint which when it gets instantiated
  95. internally holds a reference to it's own coordinates as well as Marker and Circle.
  96. Once we do a new on _mapPoint we insert it into an array of m_mapPoints so we can hold
  97. a reference to all points in a map (used for example when we want to clear the map so
  98. we can cycle through the points and remove them).
  99. @method _initMap
  100. **/
  101. _initMap: function () {
  102. var self = this;
  103. Number.prototype.toRad = function () {
  104. return this * Math.PI / 180;
  105. };
  106. Number.prototype.toDeg = function () {
  107. return this * 180 / Math.PI;
  108. };
  109. self._mapPoint = function (latLng, radius, mapPoints, map, that) {
  110. var self = this;
  111. self.$el;
  112. self.circle;
  113. self.marker;
  114. self.latLng = latLng;
  115.  
  116. self.remove = function () {
  117. // remove circle
  118. self.circle.setMap(null);
  119. // remove marker
  120. self.marker.setMap(null);
  121. // remove UI
  122. // self.$el.remove();
  123. };
  124.  
  125. // Draw the circle
  126. self.circle = new google.maps.Circle({
  127. center: latLng,
  128. radius: radius * 1000, // Convert to meters
  129. fillColor: '#FF0000',
  130. fillOpacity: 0.2,
  131. map: map,
  132. clickable: true,
  133. editable: false
  134. });
  135.  
  136. google.maps.event.addListener(self.circle, 'click', function (event) {
  137. var lat = event.latLng.lat();
  138. var lng = event.latLng.lng();
  139. var inst;
  140. console.log('location map is in ' + that.options.placement);
  141. if (that.options.placement == BB.CONSTS.PLACEMENT_SCENE) {
  142. inst = BB.comBroker.getService(BB.SERVICES.ADD_BLOCK_LOCATION_SCENE_VIEW);
  143. } else {
  144. inst = BB.comBroker.getService(BB.SERVICES.ADD_BLOCK_LOCATION_VIEW);
  145. }
  146. if (inst._getSimulationMode()) {
  147. console.log('within range ' + lat + ' ' + lng);
  148. inst._simulateEvent(lat, lng, true);
  149. }
  150.  
  151. });
  152.  
  153. // Show marker at circle center
  154. self.marker = new google.maps.Marker({
  155. position: latLng,
  156. map: map
  157. });
  158.  
  159. // UI
  160. /*
  161. var tmpl = document.getElementById('map-point');
  162. document.getElementById("map-points").appendChild(tmpl.content.cloneNode(true));
  163. self.$el = $('#map-points li:last');
  164.  
  165. self.$el.find('.p-center').html(this.circle.getCenter().toUrlValue());
  166.  
  167. self.$el.find('.remove').click(function () {
  168. self.remove();
  169. mapPoints.splice(mapPoints.indexOf(self), 1);
  170. });
  171.  
  172. // radius slider
  173. $('#map-points li:last .radius-slider').slider({
  174. formatter: function (value) {
  175. return 'Current value: ' + value;
  176. }
  177. }).on('change', function (event) {
  178. self.circle.setRadius(event.value.newValue);
  179. });
  180.  
  181. self.$el.find('.radius-slider').on('change', function (e) {
  182. var a = $(e.target).val();
  183. self.circle.setRadius(Number(a));
  184. });
  185.  
  186. // pan to point
  187. self.$el.click(function () {
  188. map.panTo(self.circle.getCenter());
  189.  
  190. $('#map-points li').css('background-color', '#FFF');
  191. $(this).css('background-color', '#ACF19A');
  192. });
  193. */
  194. };
  195. self._createMap();
  196. },
  197.  
  198. /**
  199. Get all pointData (deprecated)
  200. @method _pointData
  201. **/
  202. _pointData: function () {
  203. var self = this;
  204. var data = {
  205. points: []
  206. };
  207. for (var i = 0; i < self.m_mapPoints.length; ++i) {
  208. var point = self.m_mapPoints[i];
  209. var center = point.circle.getCenter();
  210. data.points.push({
  211. center: {lat: center.lat(), lng: center.lng()},
  212. radius: parseInt(point.circle.getRadius().toString()) / 1000
  213. });
  214. }
  215. return data;
  216. },
  217.  
  218. /**
  219. Create the google map and listen to corresponding events such map clicks (not within a circle or marker)
  220. as well as the Search box find input etc
  221. @method _createMap
  222. **/
  223. _createMap: function () {
  224. var self = this;
  225. google.maps.LatLng.prototype.destinationPoint = function (brng, dist) {
  226. dist = dist / 6371;
  227. brng = brng.toRad();
  228.  
  229. var lat1 = this.lat().toRad(), lon1 = this.lng().toRad();
  230.  
  231. var lat2 = Math.asin(Math.sin(lat1) * Math.cos(dist) +
  232. Math.cos(lat1) * Math.sin(dist) * Math.cos(brng));
  233.  
  234. var lon2 = lon1 + Math.atan2(Math.sin(brng) * Math.sin(dist) *
  235. Math.cos(lat1),
  236. Math.cos(dist) - Math.sin(lat1) *
  237. Math.sin(lat2));
  238.  
  239. if (isNaN(lat2) || isNaN(lon2)) return null;
  240.  
  241. return new google.maps.LatLng(lat2.toDeg(), lon2.toDeg());
  242. };
  243.  
  244. var pointA = new google.maps.LatLng(34.155260, -118.787163); // Circle center
  245. var radius = 1; // 10km
  246.  
  247. var mapOpt = {
  248. mapTypeId: google.maps.MapTypeId.TERRAIN,
  249. center: pointA,
  250. zoom: 10
  251. };
  252. var map = $('.map', self.el);
  253. self.m_map = new google.maps.Map(map[0], mapOpt);
  254.  
  255. // Create the search box and link it to the UI element.
  256. //var input = $('#pac-input', self.el)[0];
  257. var c = $('.inputPlacement', self.el);
  258. $(c).append('<input class="pac-input" class="controls" type="text" placeholder="Search Box">');
  259. var input = $(c).find('input')[0];
  260. var searchBox = new google.maps.places.SearchBox(input);
  261. self.m_map.controls[google.maps.ControlPosition.TOP_LEFT].push(input);
  262.  
  263. // Bias the SearchBox results towards current map's viewport.
  264. self.m_map.addListener('bounds_changed', function () {
  265. searchBox.setBounds(self.m_map.getBounds());
  266. });
  267.  
  268. var markers = [];
  269. // Listen for the event fired when the user selects a prediction and retrieve details for location
  270. searchBox.addListener('places_changed', function () {
  271. var places = searchBox.getPlaces();
  272.  
  273. if (places.length == 0) {
  274. return;
  275. }
  276.  
  277. // Clear out the old markers.
  278. markers.forEach(function (marker) {
  279. marker.setMap(null);
  280. });
  281. markers = [];
  282.  
  283. // For each place, get the icon, name and location.
  284. var bounds = new google.maps.LatLngBounds();
  285. places.forEach(function (place) {
  286. var icon = {
  287. url: place.icon,
  288. size: new google.maps.Size(71, 71),
  289. origin: new google.maps.Point(0, 0),
  290. anchor: new google.maps.Point(17, 34),
  291. scaledSize: new google.maps.Size(25, 25)
  292. };
  293.  
  294. // Create a marker for each place.
  295. markers.push(new google.maps.Marker({
  296. map: self.m_map,
  297. icon: icon,
  298. title: place.name,
  299. position: place.geometry.location
  300. }));
  301.  
  302. if (place.geometry.viewport) {
  303. // Only geocodes have viewport.
  304. bounds.union(place.geometry.viewport);
  305. } else {
  306. bounds.extend(place.geometry.location);
  307. }
  308. });
  309. self.m_map.fitBounds(bounds);
  310. });
  311.  
  312. google.maps.event.addListener(self.m_map, 'click', function (event) {
  313. var lat = event.latLng.lat();
  314. var lng = event.latLng.lng();
  315. if (self._getSimulationMode()) {
  316. console.log('out of range ' + lat + ' ' + lng);
  317. self._simulateEvent(lat, lng, false);
  318. return;
  319. }
  320. if (self.m_markerOnClick) {
  321. self.addPoint(event.latLng, 0.10);
  322. self.m_markerOnClick = false;
  323. BB.comBroker.fire(BB.EVENTS.ADD_LOCATION_POINT, self, null, {lat: lat, lng: lng});
  324. }
  325. });
  326. },
  327.  
  328. /**
  329. Build lists of components, resources and scenes (respectively showing what's needed per placement mode)
  330. Once an LI is selected proper event fired to announce block is added.
  331. @method _render
  332. @return undefined
  333. **/
  334. _render: function () {
  335. var self = this;
  336. if (self.m_loadedMaps) {
  337. self.loadJson();
  338. return;
  339. }
  340. require(['async!https://maps.googleapis.com/maps/api/js?libraries=places'], function (e) {
  341. self._initMap();
  342. self._loadStationList();
  343. google.maps.LatLng.prototype.destinationPoint = function (brng, dist) {
  344. dist = dist / 6371;
  345. brng = brng.toRad();
  346.  
  347. var lat1 = this.lat().toRad(), lon1 = this.lng().toRad();
  348.  
  349. var lat2 = Math.asin(Math.sin(lat1) * Math.cos(dist) +
  350. Math.cos(lat1) * Math.sin(dist) * Math.cos(brng));
  351.  
  352. var lon2 = lon1 + Math.atan2(Math.sin(brng) * Math.sin(dist) *
  353. Math.cos(lat1),
  354. Math.cos(dist) - Math.sin(lat1) *
  355. Math.sin(lat2));
  356.  
  357. if (isNaN(lat2) || isNaN(lon2)) return null;
  358.  
  359. return new google.maps.LatLng(lat2.toDeg(), lon2.toDeg());
  360. };
  361. self.m_loadedMaps = true;
  362. self.loadJson();
  363. return;
  364. });
  365.  
  366. /*
  367. $('.log-data').click(function () {
  368. console.log(JSON.stringify(self._pointData()));
  369. });
  370. $('.clear-map').click(function () {
  371. self._clearMap();
  372. });
  373. */
  374. },
  375.  
  376. /**
  377. Clear the entire map of markers and circles by iterating over the m_mapPoints array
  378. @method _clearMap
  379. **/
  380. _clearMap: function () {
  381. var self = this;
  382. for (var i = 0; i < self.m_mapPoints.length; ++i) {
  383. var point = self.m_mapPoints[i];
  384. point.remove();
  385. }
  386. self.m_mapPoints = [];
  387. },
  388.  
  389. /**
  390. Simulate a trigger event of GPS coordinates by user clicks within the google map
  391. @method _simulateEvent
  392. @param {Number} lat
  393. @param {Number} lng
  394. @param {Boolean} inRange true if clicked within a marked circle radius
  395. **/
  396. _simulateEvent: function (lat, lng, inRange) {
  397. var self = this;
  398. var selected = $(Elements.CLASS_LOCATION_SIMULATION_PROPS, self.el).find('select').eq(0).find('option:selected');
  399. var postMode = $(Elements.CLASS_LOCATION_SIMULATION_PROPS, self.el).find('select').eq(1).find('option:selected').attr('value');
  400. var msg = (postMode == 'local') ? 'click link to send post...' : 'sending post...';
  401. var id = $(selected).attr('data-stationid');
  402. var ip = $(selected).attr('data-ip');
  403. var stationRecord = BB.Pepper.getStationRecord(id);
  404. var port = stationRecord.lan_server_port;
  405. var $messages = $(Elements.CLASS_LOCATION_SIMULATION_PROPS, self.el).find('h5');
  406. if (inRange) {
  407. $messages.css({color: 'green'});
  408. } else {
  409. $messages.css({color: 'red'});
  410. }
  411. var url = BB.Pepper.sendLocalEventGPS(postMode, lat, lng, id, ip, port, function (e) {
  412. console.log(e);
  413. });
  414. $messages.eq(0).text(msg);
  415. $messages.eq(1).text(lng);
  416. $messages.eq(2).text(lat);
  417. $messages.eq(3).text(url);
  418. $messages.eq(3).off('click');
  419. if (postMode=="local"){
  420. $messages.eq(3).on('click', function(){
  421. window.open(url, '_blank');
  422. });
  423. }
  424. },
  425.  
  426. /**
  427. Load and refresh the station list so we can pull station id for simulation
  428. @method _loadStationList
  429. **/
  430. _loadStationList: function () {
  431. var self = this;
  432. var userData = pepper.getUserData();
  433. var url = window.g_protocol + userData.domain + '/WebService/getStatus.ashx?user=' + userData.userName + '&password=' + userData.userPass + '&callback=?';
  434. var select = $(Elements.CLASS_LOCATION_SIMULATION_PROPS, self.el).find('select').eq(0);
  435. $(select).children().remove();
  436. $.getJSON(url, function (data) {
  437. var s64 = data['ret'];
  438. var str = $.base64.decode(s64);
  439. var xml = $.parseXML(str);
  440. $(xml).find('Station').each(function (key, value) {
  441. var stationID = $(value).attr('id');
  442. var stationName = $(value).attr('name');
  443. var stationPort = $(value).attr('localPort') || 9999;
  444. var stationIp = $(value).attr('localAddress');
  445. var buff = '<option data-ip="' + stationIp + '" data-stationid="' + stationID + '">' + stationName + '</option>'
  446. $(select).append(buff);
  447. });
  448. });
  449. },
  450.  
  451. /**
  452. Go back after selection
  453. @method _goBack
  454. **/
  455. _goBack: function () {
  456. var self = this;
  457. switch (self.options.placement) {
  458. case BB.CONSTS.PLACEMENT_CHANNEL:
  459. {
  460. self.options.stackView.slideToPage(self.options.from, 'left');
  461. break;
  462. }
  463. case BB.CONSTS.PLACEMENT_SCENE:
  464. {
  465. self.m_sceneSliderView = BB.comBroker.getService(BB.SERVICES['SCENE_SLIDER_VIEW']);
  466. self.m_sceneSliderView.slideToPage(Elements.SCENE_SLIDER_ELEMENT_VIEW, 'left');
  467. break;
  468. }
  469. case BB.CONSTS.PLACEMENT_LISTS:
  470. {
  471. self.options.stackView.slideToPage(self.options.from, 'left');
  472. break;
  473. }
  474. }
  475. self.m_markerOnClick = false;
  476. BB.comBroker.fire(BB.EVENTS.ADD_LOCATION_POINT, self);
  477. },
  478.  
  479. /**
  480. Load and populate the map fro json data, keep in mind data needs to be available from previous method call fills up m_mapData
  481. @method loadJson
  482. **/
  483. loadJson: function () {
  484. var self = this;
  485. if (!self.m_loadedMaps)
  486. return;
  487. self._clearMap();
  488. //var data = JSON.parse(str);
  489. var points = self.m_mapData.points;
  490. for (var i = 0; i < points.length; ++i) {
  491. var point = points[i];
  492. var center = new google.maps.LatLng(point.center.lat, point.center.lng);
  493. var radius = point.radius;
  494. self.addPoint(center, radius);
  495. }
  496. },
  497.  
  498. /**
  499. Select current view which will animate page loading
  500. @method selectView
  501. @params {Object} i_mapData load map data
  502. @params {Boolean} i_markerOnClick if true, we allow a single click to add a new marker in map
  503. **/
  504. selectView: function (i_markerOnClick) {
  505. var self = this;
  506. self.m_markerOnClick = i_markerOnClick;
  507. self.options.stackView.slideToPage(self, 'right');
  508. },
  509.  
  510. /**
  511. Set current map data (we dont actaully render it yet, just get it ready)
  512. @method selectView
  513. @params {Object} i_mapData load map data
  514. **/
  515. setData: function (i_mapData) {
  516. var self = this;
  517. self.m_mapData = i_mapData;
  518. },
  519.  
  520. /**
  521. Deselect current view which will animate page unloading
  522. @method selectView
  523. **/
  524. deSelectView: function () {
  525. var self = this;
  526. self._goBack();
  527. },
  528.  
  529. /**
  530. Add a new point to the map (a point is constructed of marker and circle radius and inserted into m_mapPoints)
  531. @method addPoint
  532. @param {Number} latLng
  533. @param {Number} radius
  534. @param {Boolean} notCenter
  535. **/
  536. addPoint: function (latLng, radius, notCenter) {
  537. var self = this;
  538. if (notCenter)
  539. latLng = new google.maps.LatLng(latLng.H, latLng.L);
  540. radius = radius || 0.10;
  541. var newPoint = new self._mapPoint(latLng, radius, self.m_mapPoints, self.m_map, self);
  542. self.m_mapPoints.push(newPoint);
  543. },
  544.  
  545. /**
  546. Animate google maps to give position
  547. @method panToPoint
  548. @param {Number} lat
  549. @param {Number} lng
  550. **/
  551. panToPoint: function (lat, lng) {
  552. var self = this;
  553. if (!self.m_map)
  554. return;
  555. var center = new google.maps.LatLng(lat, lng);
  556. self.m_map.panTo(center);
  557. }
  558. });
  559.  
  560. return AddBlockLocationView;
  561. });
  562.  
  563.