diff --git a/public_html/gmap.html b/public_html/gmap.html index b9fff8d..54e2825 100644 --- a/public_html/gmap.html +++ b/public_html/gmap.html @@ -15,9 +15,10 @@ DUMP1090 - + +
diff --git a/public_html/planeObject.js b/public_html/planeObject.js index ea441f0..b60baba 100644 --- a/public_html/planeObject.js +++ b/public_html/planeObject.js @@ -75,8 +75,10 @@ function PlaneObject(icao) { // Appends data to the running track so we can get a visual tail on the plane // Only useful for a long running browser session. -PlaneObject.prototype.updateTrack = function() { +PlaneObject.prototype.updateTrack = function(estimate_time) { var here = this.position; + if (!here) + return; if (this.track_linesegs.length == 0) { // Brand new track @@ -98,7 +100,7 @@ PlaneObject.prototype.updateTrack = function() { var elapsed = (this.last_position_time - lastseg.head_update); var new_data = (here !== lastpos); - var est_track = (elapsed > 5); + var est_track = (elapsed > estimate_time); var ground_track = (this.altitude === "ground"); if (!new_data) @@ -256,7 +258,7 @@ PlaneObject.prototype.updateTick = function(receiver_timestamp) { } else { this.visible = true; if (this.position !== null) { - if (this.updateTrack()) { + if (this.updateTrack(5)) { this.updateLines(); this.updateMarker(true); } else { diff --git a/public_html/script.js b/public_html/script.js index 4e19b89..176c38a 100644 --- a/public_html/script.js +++ b/public_html/script.js @@ -41,6 +41,48 @@ var MessageCountHistory = []; var NBSP='\u00a0'; var DEGREES='\u00b0' +function processReceiverUpdate(data) { + // Loop through all the planes in the data packet + var now = data.now; + var acs = data.aircraft; + + // Detect stats reset + if (MessageCountHistory.length > 0 && MessageCountHistory[MessageCountHistory.length-1].messages > data.messages) { + MessageCountHistory = [{'time' : MessageCountHistory[MessageCountHistory.length-1].time, + 'messages' : 0}]; + } + + // Note the message count in the history + MessageCountHistory.push({ 'time' : now, 'messages' : data.messages}); + // .. and clean up any old values + if ((now - MessageCountHistory[0].time) > 30) + MessageCountHistory.shift(); + + for (var j=0; j < acs.length; j++) { + var ac = acs[j]; + var hex = ac.hex; + var plane = null; + + // Do we already have this plane object in Planes? + // If not make it. + + if (Planes[hex]) { + plane = Planes[hex]; + } else { + plane = new PlaneObject(hex); + plane.tr = PlaneRowTemplate.cloneNode(true); + plane.tr.cells[0].textContent = hex; // this won't change + plane.tr.addEventListener('click', selectPlaneByHex.bind(undefined,hex)); + + Planes[hex] = plane; + PlanesOrdered.push(plane); + } + + // Call the function update + plane.updateData(now, ac); + } +} + function fetchData() { if (FetchPending !== null && FetchPending.state() == 'pending') { // don't double up on fetches, let the last one resolve @@ -52,45 +94,9 @@ function fetchData() { cache: false, dataType: 'json' }); FetchPending.done(function(data) { - // Loop through all the planes in the data packet var now = data.now; - var acs = data.aircraft; - // Detect stats reset - if (MessageCountHistory.length > 0 && MessageCountHistory[MessageCountHistory.length-1].messages > data.messages) { - MessageCountHistory = [{'time' : MessageCountHistory[MessageCountHistory.length-1].time, - 'messages' : 0}]; - } - - // Note the message count in the history - MessageCountHistory.push({ 'time' : now, 'messages' : data.messages}); - // .. and clean up any old values - if ((now - MessageCountHistory[0].time) > 30) - MessageCountHistory.shift(); - - for (var j=0; j < acs.length; j++) { - var ac = acs[j]; - var hex = ac.hex; - var plane = null; - - // Do we already have this plane object in Planes? - // If not make it. - - if (Planes[hex]) { - plane = Planes[hex]; - } else { - plane = new PlaneObject(hex); - plane.tr = PlaneRowTemplate.cloneNode(true); - plane.tr.cells[0].textContent = hex; // this won't change - plane.tr.addEventListener('click', selectPlaneByHex.bind(undefined,hex)); - - Planes[hex] = plane; - PlanesOrdered.push(plane); - } - - // Call the function update - plane.updateData(now, ac); - } + processReceiverUpdate(data); // update timestamps, visibility, history track for all planes - not only those updated for (var i = 0; i < PlanesOrdered.length; ++i) { @@ -126,6 +132,7 @@ function fetchData() { }); } +var PositionHistorySize = 0; function initialize() { PlaneRowTemplate = document.getElementById("plane_row_template"); @@ -173,12 +180,102 @@ function initialize() { Dump1090Version = data.version; RefreshInterval = data.refresh; + PositionHistorySize = data.history; }) - .always(initialize_after_config); + .always(function() { + initialize_map(); + start_load_history(); + }); +} + +var CurrentHistoryFetch = null; +var PositionHistoryBuffer = [] +function start_load_history() { + if (PositionHistorySize > 0) { + console.log("Starting to load history"); + $("#loader").removeClass("hidden"); + load_history_item(0); + } else { + endLoadHistory(); + } +} + +function load_history_item(i) { + if (i >= PositionHistorySize) { + end_load_history(); + return; + } + + console.log("Loading history #" + i); + + $.ajax({ url: 'data/history_' + i + '.json', + timeout: 5000, + cache: false, + dataType: 'json' }) + + .done(function(data) { + PositionHistoryBuffer.push(data); + load_history_item(i+1); + }) + + .fail(function(jqxhr, status, error) { + // No more history + end_load_history(); + }); +} + +function end_load_history() { + $("#loader").addClass("hidden"); + + console.log("Done loading history"); + + if (PositionHistoryBuffer.length > 0) { + var now, last=0; + + // Sort history by timestamp + console.log("Sorting history"); + PositionHistoryBuffer.sort(function(x,y) { return (x.now - y.now); }); + + // Process history + for (var h = 0; h < PositionHistoryBuffer.length; ++h) { + now = PositionHistoryBuffer[h].now; + console.log("Applying history " + h + "/" + PositionHistoryBuffer.length + " at: " + now); + processReceiverUpdate(PositionHistoryBuffer[h]); + + // update track + console.log("Updating tracks at: " + now); + for (var i = 0; i < PlanesOrdered.length; ++i) { + var plane = PlanesOrdered[i]; + plane.updateTrack((now - last) + 1); + } + + last = now; + } + + // Final pass to update all planes to their latest state + console.log("Final history cleanup pass"); + for (var i = 0; i < PlanesOrdered.length; ++i) { + var plane = PlanesOrdered[i]; + plane.updateTick(now); + } + } + + PositionHistoryBuffer = null; + + console.log("Completing init"); + + refreshTableInfo(); + refreshSelected(); + reaper(); + + // Setup our timer to poll from the server. + window.setInterval(fetchData, RefreshInterval); + window.setInterval(reaper, 60000); + } // Initalizes the map and starts up our timers to call various functions -function initialize_after_config() { +function initialize_map() { // Load stored map settings if present CenterLat = Number(localStorage['CenterLat']) || DefaultCenterLat; CenterLon = Number(localStorage['CenterLon']) || DefaultCenterLon; @@ -329,15 +426,6 @@ function initialize_after_config() { } } } - - // These will run after page is complitely loaded - $(window).load(function() { - $('#dialog-modal').css('display', 'inline'); // Show hidden settings-windows content - }); - - // Setup our timer to poll from the server. - window.setInterval(fetchData, RefreshInterval); - window.setInterval(reaper, 60000); } // This looks for planes to reap out of the master Planes variable diff --git a/public_html/style.css b/public_html/style.css index d25688b..2b215b0 100644 --- a/public_html/style.css +++ b/public_html/style.css @@ -15,6 +15,9 @@ div#update_error { position: absolute; bottom: 25px; left: 25px; border: 2px sol background-color: #FFFFA3; opacity: 0.75; filter:alpha(opacity=75); padding: 5px; text-align: center; } +div#loader { z-index: 99; position: absolute; left: 0; top: 0; bottom: 0; right: 0; background: #000; opacity: 0.8; filter: alpha(opacity=80); } +#spinny { width: 128px; height: 128px; position: absolute; top: 50%; left: 50%; margin: -64px 0 0 -64px; } + #tableinfo, #sudo_buttons { font-size: x-small; font-family: monospace; } .vPosition { font-weight: bold; background-color: #d5ffd5; }