localize.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. var STARTED = false;
  2. var LOADING = false;
  3. var PROCESSING = false;
  4. var LOCALIZE_SESSION_ID = null;
  5. var device = null;
  6. var map = null;
  7. var boxes = {};
  8. var ap_boxes = {};
  9. var true_position_features = []
  10. var est_position_features = []
  11. var layers = {};
  12. var boxStylesLookup = {};
  13. var lastBoxCount = 0;
  14. var toBeProcessed = []
  15. var BOX_OFFSET = 49
  16. var sma5_process = simple_moving_averager(5)
  17. var sma5_load = simple_moving_averager(5)
  18. var avg_timeing = 50
  19. var freeTime = 50
  20. var numvisible = 100
  21. POS_BOX_SIZE = 70
  22. var true_last_pos = [0, 0]
  23. var est_last_pos = [0, 0]
  24. function createAPFeature(x, y, rssi){
  25. var height = (100 + Math.round(rssi))
  26. var bounds = new OpenLayers.Bounds(x, y, x + 10, y + height * 6);
  27. var feature = new OpenLayers.Feature.Vector(bounds.toGeometry(), {x: x, y: y}, boxStylesLookup[height*3+1]);
  28. layers['ap_vlayer'].addFeatures(feature);
  29. return feature
  30. }
  31. function createAPFeatures(){
  32. $('span.apinfo').each(function(){
  33. var apinfo = $(this)
  34. var apid = apinfo.attr('apid')
  35. var boxname = 'ap_' + apid
  36. var x = parseInt(apinfo.attr('x'))
  37. var y = parseInt(apinfo.attr('y'))
  38. var feature = createAPFeature(x, y, -100)
  39. ap_boxes[boxname + '_topcube'] = feature
  40. var feature = createAPFeature(x+15, y, -100)
  41. ap_boxes[boxname + '_measured'] = feature
  42. })
  43. };
  44. function adaptAPFeatures(apdata){
  45. var old_features = []
  46. $.each(apdata, function(i, apinfo){
  47. var apid = apinfo[0]
  48. var ap_rssi = Math.max(apinfo[1], -100)
  49. var ap_rssi_measured = Math.max(apinfo[2], -100)
  50. var boxname = 'ap_' + apid
  51. $('span#api_' + apid).text(Math.round(ap_rssi) + '/' + Math.round(ap_rssi_measured))
  52. var feature = ap_boxes[boxname + '_topcube']
  53. old_features.push(feature);
  54. new_feature = createAPFeature(feature.data.x, feature.data.y, ap_rssi)
  55. ap_boxes[boxname + '_topcube'] = new_feature
  56. feature = ap_boxes[boxname + '_measured']
  57. old_features.push(feature);
  58. new_feature = createAPFeature(feature.data.x, feature.data.y, ap_rssi_measured)
  59. ap_boxes[boxname + '_measured'] = new_feature
  60. })
  61. layers['ap_vlayer'].destroyFeatures(old_features)
  62. };
  63. function adaptTopN(data){
  64. var maxcolor = 0
  65. var mincolor = 10000000
  66. var lonLat = new OpenLayers.LonLat(0, 0);
  67. $.each(data, function(i, loc){
  68. avgidx = loc[2]
  69. if (avgidx > maxcolor){
  70. maxcolor = avgidx
  71. };
  72. if (avgidx < mincolor){
  73. mincolor = avgidx
  74. };
  75. });
  76. var numcolors = parseInt($('span#rgbdata').attr('numcolors'))
  77. var color_ratio = (numcolors - 2) / (maxcolor - mincolor)
  78. var toBeAdded = [];
  79. $.each(data, function(i, loc){
  80. var boxname = 'b'+i
  81. x = loc[0]
  82. y = loc[1]
  83. //~ costs = loc[2]
  84. //~ idx = loc[3]
  85. //~ avgcosts = loc[4]
  86. avgidx = loc[2]
  87. var color = numcolors - parseInt((avgidx - mincolor) * color_ratio) - 2
  88. if (boxname in boxes){
  89. var box = boxes[boxname];
  90. lonLat.lon = x + BOX_OFFSET / 2
  91. lonLat.lat = y + BOX_OFFSET / 2
  92. box.feature.move(lonLat)
  93. //~ box.costs = costs
  94. layers['topn_vlayer'].drawFeature(box.feature, boxStylesLookup[color]);
  95. } else {
  96. var bounds = new OpenLayers.Bounds(x, y, x + BOX_OFFSET, y + BOX_OFFSET);
  97. var feature = new OpenLayers.Feature.Vector(bounds.toGeometry(), {id:boxname}, boxStylesLookup[color]);
  98. var box = {
  99. //~ costs : costs,
  100. feature : feature
  101. };
  102. boxes[boxname] = box
  103. toBeAdded.push(feature)
  104. };
  105. });
  106. // delete
  107. var features = []
  108. for (i=data.length; i < lastBoxCount; i=i+1){
  109. var boxname = 'b'+i;
  110. features.push(boxes[boxname].feature)
  111. delete boxes[boxname];
  112. }
  113. layers['topn_vlayer'].destroyFeatures(features)
  114. // add
  115. layers['topn_vlayer'].addFeatures(toBeAdded);
  116. lastBoxCount = data.length;
  117. }
  118. function drawPositionFeatures(position_features, pos, color, lastpos){
  119. var x = pos[0]
  120. var y = pos[1]
  121. //var z = pos[2]
  122. if (position_features.length > 0){
  123. var lastFeature = position_features[position_features.length-1]
  124. if ( Math.abs(lastpos[0] - x) < POS_BOX_SIZE &&
  125. Math.abs(lastpos[1] - y) < POS_BOX_SIZE) {
  126. return
  127. }
  128. };
  129. lastpos[0] = x
  130. lastpos[1] = y
  131. var bounds = new OpenLayers.Bounds(x, y, x + POS_BOX_SIZE, y + POS_BOX_SIZE);
  132. var style = {fillColor: color, strokeWidth: 0, strokeColor: color, 'fillOpacity': 0.8}
  133. var feature = new OpenLayers.Feature.Vector(bounds.toGeometry(), {}, style);
  134. layers['pos_vlayer'].addFeatures(feature);
  135. position_features.push(feature)
  136. var MAX_VISIBLE = 25
  137. if (position_features.length > MAX_VISIBLE){
  138. var f = position_features.shift()
  139. layers['pos_vlayer'].destroyFeatures(f)
  140. };
  141. $.each(position_features, function(i, f){
  142. style.fillOpacity = (i - 3 + (MAX_VISIBLE - position_features.length)) / MAX_VISIBLE
  143. layers['pos_vlayer'].drawFeature(f, style);
  144. });
  145. };
  146. function processData(){
  147. if (toBeProcessed.length == 0 || PROCESSING){
  148. setTimeout(processData, freeTime);
  149. return false
  150. }
  151. var start = new Date().getTime();
  152. $('span#clientqueuesize').text(toBeProcessed.length)
  153. PROCESSING = true;
  154. data = toBeProcessed.shift()
  155. $('span#top_z').text(data.frame.z)
  156. $('span#pos_hight').text(data.frame.hight.toFixed(1))
  157. if (layers['ap_vlayer'].getVisibility()){
  158. adaptAPFeatures(data.frame.aps)
  159. };
  160. if (layers['topn_vlayer'].getVisibility()){
  161. adaptTopN(data.frame.topn)
  162. };
  163. if (layers['pos_vlayer'].getVisibility()){
  164. drawPositionFeatures(true_position_features, data.frame.pos, 'white', true_last_pos)
  165. drawPositionFeatures(est_position_features, data.frame.topn[data.frame.topn.length-1], 'red', est_last_pos)
  166. };
  167. var end = new Date().getTime();
  168. avg_timeing = sma5_process(end - start)
  169. setTimeout(processData, freeTime);
  170. PROCESSING = false
  171. return true
  172. }
  173. function loadData(){
  174. if (LOADING){
  175. return
  176. };
  177. LOADING = true;
  178. var start_load = new Date().getTime();
  179. $.getJSON("/locinfo/" + device + '/' + LOCALIZE_SESSION_ID + "/hmm/" + numvisible + '/1', function(response) {
  180. $('span#queuesize').text(start_load)
  181. $('span#queuesize').text('queuesize: ' + response['meta']['queuesize'])
  182. if (response['data'].length > 0){
  183. //~ console.log('new data')
  184. } else {
  185. LOADING = false;
  186. return
  187. }
  188. //~ console.log(response['data'].length)
  189. toBeProcessed = []
  190. $.each(response['data'], function(i, data){
  191. toBeProcessed.push({'frame': data})
  192. });
  193. LOADING = false;
  194. var end_load = new Date().getTime();
  195. avg_load_time = sma5_load(end_load - start_load)
  196. var totalFrames = response['data'].length
  197. freeTime = 1.5 * (avg_load_time + 300) - avg_timeing * totalFrames
  198. if (freeTime > 30){
  199. freeTime = freeTime / totalFrames
  200. if (numvisible < 500){
  201. numvisible = parseInt(numvisible * 1.1)
  202. };
  203. } else if (freeTime < 0) {
  204. if (numvisible > 20){
  205. numvisible = parseInt(numvisible * 0.9)
  206. };
  207. freeTime = 10;
  208. }
  209. $('span#debug').text('visible:' + numvisible + ' delay:' + parseInt(freeTime) + 'ms')
  210. });
  211. }
  212. OpenLayers.Control.Click = OpenLayers.Class(OpenLayers.Control, {
  213. defaultHandlerOptions: {
  214. 'single': true,
  215. 'double': false,
  216. 'pixelTolerance': 0,
  217. 'stopSingle': false,
  218. 'stopDouble': false
  219. },
  220. initialize: function(options) {
  221. this.handlerOptions = OpenLayers.Util.extend(
  222. {}, this.defaultHandlerOptions
  223. );
  224. OpenLayers.Control.prototype.initialize.apply(
  225. this, arguments
  226. );
  227. this.handler = new OpenLayers.Handler.Click(
  228. this, {
  229. 'click': this.trigger
  230. }, this.handlerOptions
  231. );
  232. },
  233. trigger: function(e) {
  234. var lonlat = map.getLonLatFromViewPortPx(e.xy);
  235. $.get('/spawnSyntheticSignal/'+ device + '/' + lonlat.lon + '/' + lonlat.lat, function(response){
  236. console.log(response)
  237. })
  238. }
  239. });
  240. $(document).ready(function() {
  241. device = $('div#stationinfo span#name').text()
  242. $.each($('span#rgbdata').text().split(','), function(i, v){
  243. boxStylesLookup[i] = {fillColor: v, strokeWidth: 1, strokeColor: v};
  244. //~ $('body').append('<span style="background-color:' + v + '">&#160;</span>')
  245. });
  246. var map_div = $("div#map");
  247. areaWidth = 7808;
  248. areaHeight = 2432;
  249. imageDPI = 3.2512 // 16 * 8 pixel/meter
  250. OpenLayers.INCHES_PER_UNIT['pixels'] = 1 / imageDPI;
  251. var mapOptions = {
  252. controls: [],
  253. maxExtent: new OpenLayers.Bounds(0, 0, areaWidth, areaHeight),
  254. resolutions: [32, 16, 8, 4, 2, 1],
  255. numZoomLevels: 6,
  256. units: 'pixels',
  257. };
  258. //create openlayers-map on div#map
  259. map = new OpenLayers.Map('map', mapOptions);
  260. scale = new OpenLayers.Control.ScaleLine({maxWidth:100, topInUnits:'m'});
  261. map.addControl(scale);
  262. map.addControl(new OpenLayers.Control.Navigation());
  263. layers['eg_layer'] = new OpenLayers.Layer.TMS( "2D Cut EG", "/tiles/", {layername: 'eg', type:'jpg', transitionEffect:'resize', 'isBaseLayer':true})
  264. map.addLayer(layers['eg_layer']);
  265. layers['og1_layer'] = new OpenLayers.Layer.TMS( "2D Cut OG1", "/tiles/", {visibility: false, layername: 'og1', type:'jpg', transitionEffect:'resize', 'isBaseLayer':true})
  266. map.addLayer(layers['og1_layer']);
  267. layers['og2_layer'] = new OpenLayers.Layer.TMS( "2D Cut OG2", "/tiles/", {visibility: false, layername: 'og2', type:'jpg', transitionEffect:'resize', 'isBaseLayer':true})
  268. map.addLayer(layers['og2_layer']);
  269. currentZoomLevel = 2
  270. lonLat = new OpenLayers.LonLat(3500, 1000);
  271. map.setCenter(lonLat, currentZoomLevel, 1, 1);
  272. layers['topn_vlayer'] = new OpenLayers.Layer.Vector( "Top N", {visibility: false, 'isBaseLayer':false});
  273. map.addLayer(layers['topn_vlayer']);
  274. layers['ap_vlayer'] = new OpenLayers.Layer.Vector( "APs", {visibility: false, 'isBaseLayer':false});
  275. map.addLayer(layers['ap_vlayer']);
  276. createAPFeatures()
  277. layers['pos_vlayer'] = new OpenLayers.Layer.Vector( "Position", {visibility: false, 'isBaseLayer':false});
  278. map.addLayer(layers['pos_vlayer']);
  279. $('span.apid').each(function(i, e){
  280. var apid = $(e).attr('apid')
  281. layers['aplayer_' + apid] = new OpenLayers.Layer.TMS( "APLayer_" + apid, "/apdatatiles/",
  282. {visibility: false, layername: device + ',' + apid,
  283. type:'png', transitionEffect:'resize', 'isBaseLayer':false, 'opacity': 0.8})
  284. map.addLayer(layers['aplayer_' + apid]);
  285. });
  286. //~ switcher = new OpenLayers.Control.LayerSwitcher();
  287. //~ map.addControl(switcher);
  288. //~ switcher.maximizeControl();
  289. var click = new OpenLayers.Control.Click();
  290. map.addControl(click);
  291. //~ click.activate();
  292. //~ return
  293. $.timer(300, function(timer){
  294. if (STARTED && toBeProcessed.length <= 2){
  295. loadData()
  296. };
  297. });
  298. setTimeout(processData, 1000);
  299. //update scale after zooming
  300. scale.update();
  301. $('div#buttons div.baselayer').click(function(){
  302. $('div#buttons div.baselayer').css('background-color', '#EEE')
  303. $('div#buttons div.baselayer').each(function(i, e){
  304. layers[$(e).attr('layer')].setVisibility(false)
  305. });
  306. $(this).css('background-color', '#CFC')
  307. layers[$(this).attr('layer')].setVisibility(true)
  308. map.setBaseLayer(layers[$(this).attr('layer')]);
  309. });
  310. $('div#buttons div.layer').toggle(function(){
  311. $(this).css('background-color', '#CFC')
  312. layers[$(this).attr('layer')].setVisibility(true)
  313. }, function(){
  314. $(this).css('background-color', '#EEE')
  315. var l = layers[$(this).attr('layer')];
  316. l.setVisibility(false)
  317. if ($(this).attr('layer') == 'pos_vlayer'){
  318. $.each(true_position_features, function(i, f){
  319. l.destroyFeatures(f)
  320. });
  321. true_position_features = []
  322. $.each(est_position_features, function(i, f){
  323. l.destroyFeatures(f)
  324. });
  325. est_position_features = []
  326. };
  327. });
  328. $('div#buttons div#startstop').toggle(function(){
  329. STARTED = true;
  330. var b = $(this)
  331. b.css('background-color','#FFE426')
  332. b.text('Starting...')
  333. LOCALIZE_SESSION_ID = parseInt(Math.random() * 1000000)
  334. $('span#session_id').text(LOCALIZE_SESSION_ID)
  335. $.get('/startLocalizeSession/' + device + '/' + LOCALIZE_SESSION_ID, function(){
  336. b.css('background-color','#EE6644')
  337. b.text('Stop')
  338. })
  339. }, function(){
  340. STARTED = false;
  341. var b = $(this)
  342. b.css('background-color','#FFE426')
  343. b.text('Stopping...')
  344. $.get('/stopLocalizeSession/' + device + '/' + LOCALIZE_SESSION_ID, function(){
  345. b.text('Start')
  346. b.css('background-color','#25BB25')
  347. })
  348. });
  349. $('span.apdisable').click(function(){
  350. var apid = $(this).attr('apid');
  351. if ($(this).hasClass('inactive_ap')){
  352. $.get('/useAPforLocalizeDevice/' + device + '/' + apid + '/true');
  353. } else {
  354. $.get('/useAPforLocalizeDevice/' + device + '/' + apid + '/false')
  355. };
  356. $(this).toggleClass('inactive_ap')
  357. });
  358. $('span.apid').click(function(){
  359. var apid = $(this).attr('apid');
  360. if ($(this).hasClass('show_ap_data')){
  361. layers['aplayer_' + apid].setVisibility(false)
  362. } else {
  363. layers['aplayer_' + apid].setVisibility(true)
  364. };
  365. $(this).toggleClass('show_ap_data')
  366. });
  367. });