/******************************************************************** * Dynamic Aircraftlist for Radarcape ******************************************************************** * Guenter Koellner Embedded Development GmbH * * Am Rain 24 * 85256 Vierkirchen * Geschaeftsfuehrer Guenter Koellner * * http://www.modesbeast.com ********************************************************************/ var refresh_time = 1; var aircraftlist_body; var aircraftlist_header; var aircraftlist_row2clone; var cookie_sort = "aclist_sort"; var sort = { "key" : "hex", "asc" : true, "empty_on_top" : true }; var cookie_colselect = "aclist_colselect"; const category = { "A0":"A0: Unspecified powered aircraft", "A1":"A1: Light (< 15500 lbs)", "A2":"A2: Small (15500 to 75000 lbs)", "A3":"A3: Large (75000 to 300000 lbs)", "A4":"A4: High Vortex Large", "A5":"A5: Heavy (> 300000 lbs)", "A6":"A6: High Performance ( > 5 g acceleration and > 400 kts)", "A7":"A7: Rotorcraft", "B0":"B0: Unspecified unpowered aircraft or UAV or spacecraft", "B1":"B1: Glider/Sailplane", "B2":"B2: Lighter-than-Air", "B3":"B3: Parachutist/Skydiver", "B4":"B4: Ultralight/Hang Glider/Paraglider", "B5":"B5: Reserved", "B6":"B6: Unmanned Aerial Vehicle", "B7":"B7: Space/Trans-atmospheric Vehicle", "C0":"C0: Unspecified ground installation or vehicle", "C1":"C1: Surface Vehicle - Emergency Vehicle", "C2":"C2: Surface Vehicle - Service Vehicle", "C3":"C3: Fixed Ground or Tethered Obstruction", "F0":"F00: Flarm: Unknown", "F1":"F01: Flarm: Glider", "F2":"F02: Flarm: Tow Plane", "F3":"F03: Flarm: Helicopter,Rotorcraft", "F4":"F04: Flarm: Parachute", "F5":"F05: Flarm: Drop Plane", "F6":"F06: Flarm: Hang Glider", "F7":"F07: Flarm: Para Glider", "F8":"F08: Flarm: Powered Aircraft", "F9":"F09: Flarm: Jet Aircraft", "F10":"F10: Flarm: UFO", "F11":"F11: Flarm: Balloon", "F12":"F12: Flarm: Airship", "F13":"F13: Flarm: UAV", "F14":"F14: Flarm: Unused", "F15":"F15: Flarm: Static Object" } var category_title = ''; for( var key in category ) { category_title += category[key] + '\r\n'; } var aclist = { "reg": { "visible":true, "span":"Click on the link to show aircraft on planespotters.net", "title":"Registration", "align":"center"}, "hex": { "visible":true, "span":null, "title":"Mode-S", "align":"center"}, "fli": { "visible":true, "span":null, "title":"Flight", "align":"center"}, "orgh": { "visible":true, "span":null, "title":"Origin", "align":"center"}, "org": { "visible":true, "span":null, "title":"Origin
Name", "align":"center"}, "dsth": { "visible":true, "span":null, "title":"Destination", "align":"center"}, "dst": { "visible":true, "span":null, "title":"Destination
Name","align":"center"}, "trk": { "visible":true, "span":"True Track", "title":"Track", "align":"center"}, "hdgm": { "visible":true, "span":null, "title":"Magn.
Heading","align":"center"}, "hdgt": { "visible":true, "span":null, "title":"True
Heading", "align":"center"}, "alt": { "visible":true, "span":"Barometric Altitude [feet]", "title":"Altitude", "align":"center"}, "altg": { "visible":true, "span":"GNSS Elipsoidal Altitude [feet]", "title":"GNSS
Altitude","align":"center"}, "spd": { "visible":true, "span":"Ground Speed [knots]", "title":"Speed", "align":"center"}, "ias": { "visible":true, "span":"Indicated Air Speed", "title":" IAS ", "align":"center"}, "tas": { "visible":true, "span":"True Air Speed", "title":" TAS ", "align":"center"}, "vrt": { "visible":true, "span":"Vertical Rate [feet per minute]", "title":"Vertical
Rate","align":"center"}, "gda": { "visible":true, "span":"Aircraft on Ground or Airborne", "title":"GND/
AIR", "align":"center"}, "typ": { "visible":true, "span":"Aircraft Type", "title":"Type", "align":"center"}, "cat": { "visible":true, "span":category_title, "title":"Category", "align":"center"}, "opr": { "visible":true, "span":null, "title":"Operator", "align":"center"}, "cou": { "visible":true, "span":null, "title":"Country", "align":"center"}, "src": { "visible":true, "span":"Source of Position Information", "title":"Source", "align":"center"}, "squ": { "visible":true, "span":null, "title":"Squawk", "align":"center"}, "lat": { "visible":true, "span":"Click on Latitude to show aircraft in Openlayers map", "title":"Latitude", "align":"center"}, "lon": { "visible":true, "span":"Click on Longitude to show aircraft in Gmap", "title":"Longitude", "align":"center"}, "dis": { "visible":true, "span":"Distance from Receiver", "title":"Distance", "align":"center"}, "spi": { "visible":true, "span":null, "title":"Indicator", "align":"center"}, "alr": { "visible":true, "span":"0=no alert, 1=temporary (Squawk changed previous 18s) 2=Mode-S alert 3=permanent (Squawk 7500,7600,7700)","title":"Alert", "align":"center"}, "ape": { "visible":true, "span":null, "title":"Autopilot
engaged","align":"center"}, "tcm": { "visible":true, "span":"TCAS 0=not operational, 1: operational, 2: alert", "title":"TCAS", "align":"center"}, "qnhs": { "visible":true, "span":null, "title":"QNH
sel.", "align":"center"}, "alts": { "visible":true, "span":null, "title":"Altitude
sel.","align":"center"}, "hdgs": { "visible":true, "span":null, "title":"Heading
sel.", "align":"center"}, "dbm": { "visible":true, "span":"Signal Level [dBm]", "title":"Signal
Level", "align":"center"}, "tmp": { "visible":true, "span":null, "title":"Temp.
°C", "align":"center"}, "wsp": { "visible":true, "span":null, "title":"Wind
Speed", "align":"center"}, "wdi": { "visible":true, "span":null, "title":"Wind
Direction","align":"center"}, "tim": { "visible":true, "span":null, "title":"Last Signal", "align":"center"}, "mop": { "visible":true, "span":"null=no ADS-B received, 0=default for unconfirmed version","title":"MOPS
version","align":"center"}, "tru": { "visible":true, "span":"Number of Trustable DF-11/17/18 Messages", "title":"Trust", "align":"center"}, "pic": { "visible":true, "span":null, "title":"ASTERIX
PIC", "align":"center"} } function aircraftlistSetVisibleColumns() { var cells = aircraftlist_header.cells; for (var key in aclist) { cells.namedItem(key).style.display = aclist[key].visible ? 'table-cell' : 'none'; } } function createAircraftlist() { // create table // var table = document.createElement("TABLE"); table.setAttribute("class", "table table-striped table-condensed table-more-condensed table-bordered table-hover"); table.style.whiteSpace = "pre-line"; var div = document.getElementById("div_aircraftlist"); div.appendChild(table); // create table header // var header = table.createTHead(); aircraftlist_header = header.insertRow(-1); for (var key in aclist) { var cell = aircraftlist_header.insertCell(-1); var contents = '' + aclist[key].title + '
'; //contents += '
'; contents += '
'; if( aclist[key].span!=null ) { contents = '' + contents; } cell.innerHTML=contents; cell.id = key; cell.align = aclist[key].align; cell.style.display = aclist[key].visible ? 'table-cell' : 'none'; } // create table body and insert invisible row to clone // https://stackoverflow.com/questions/6481948/how-do-i-create-the-tbody-tag-in-a-table-with-pure-javascript aircraftlist_body = table.appendChild(document.createElement('tbody')); aircraftlist_row2clone = aircraftlist_body.insertRow(-1); for (var key in aclist) { var cell = aircraftlist_row2clone.insertCell(-1); cell.id = key; cell.style.display = 'none'; cell.align = aclist[key].align; } } function getCategoryLongtext(cat) { var retval = cat; if (category[cat]) retval = category[cat]; return retval; } function gda_longtext (gda) { switch (gda.toUpperCase()) { case 'A': return "Air"; case 'G': return "Ground"; case '?': return "Unk."; default: return '?'+gda+'?'; } } function src_longtext (src) { switch (src.toUpperCase()) { case 'A': return "ADS-B"; case 'M': return "MLAT"; case 'L': return "FLARM"; case 'O': return "OGN"; case 'F': return "FlAwa"; case '?': return null; case null: return null; default: return '?'+src+'?'; } } function get_date_time_string(unix_timestamp, nanoseconds) { // Create a new JavaScript Date object based on the timestamp // multiplied by 1000 so that the argument is in milliseconds, not seconds. var date = new Date(unix_timestamp * 1000); // Hours part from the timestamp var hours = date.getHours(); var minutes = "0" + date.getMinutes(); var seconds = "0" + date.getSeconds(); var formattedTime = date.toISOString(); formattedTime = formattedTime.replace("T", " "); var ns = "000000000" + nanoseconds; formattedTime = formattedTime.substr(0, 20) + ns.substr(-9); // formattedTime.substr(20) return formattedTime; } function updateStatistics() { getJSON(rcd_globals.fcgipath+"mapinfo.json", function(stat_data) { refresh_time = ( typeof stat_data["refreshaclist"]!=='undefined' ) ? stat_data["refreshaclist"] : refresh_time; var table = document.getElementById("statistic").tBodies[0]; var cells = table.rows[0].cells; var txt = ""; txt += 'Total Aircraft: ' + stat_data["dbsize"]; txt += ' ADS-B: ' + stat_data["num_adsb"]; txt += ' MLAT: ' + stat_data["num_mlat"]; txt += ' Flarm: ' + stat_data["num_flarm"]; txt += ' Active: ' + stat_data["watched"]; txt += ' ADS-B: ' + stat_data["num_active_adsb"]; txt += ' MLAT: ' + stat_data["num_active_mlat"]; txt += ' Flarm: ' + stat_data["num_active_flarm"]; cells.namedItem("statistic_text").innerHTML = txt; }); } function updateTable() { getJSON(rcd_globals.fcgipath+"aircraftlist.json", function(unsorted_data) { for ( var i = 0; i < unsorted_data.length; i++) { unsorted_data[i].tim = get_date_time_string(unsorted_data[i].uti, unsorted_data[i].ns); unsorted_data[i].orgh = resolveAirportById(unsorted_data[i].org).label; unsorted_data[i].dsth = resolveAirportById(unsorted_data[i].dst).label; unsorted_data[i].src = src_longtext(unsorted_data[i].src); var optional_field; for( optional_field of ['altg','spi','alr','ape','tcm','ias','tas','hdgm','hdgt','qnhs','alts','hdgs','altg','pic','mop'] ) { if( unsorted_data[i][optional_field]==null ) { unsorted_data[i][optional_field] = null; } } } var data = unsorted_data.sort(function(a, b) { var x = a[sort.key]; var y = b[sort.key]; if( x==y ) { return 0; } if( x==null || x==="" ) { return sort.empty_on_top==true ? -1 : 1; } if( y==null || y==="" ) { return sort.empty_on_top==false ? -1 : 1; } if( sort.asc ) { return (x < y) ? -1 : 1; } else { return (x > y) ? -1 : 1; } }); var rows_len = aircraftlist_body.rows.length - 1; // first is row to clone while( rows_len>data.length ) { aircraftlist_body.removeChild(aircraftlist_body.rows[rows_len--]); } for ( var i=0; i= rows_len) { var line = aircraftlist_body.rows[0].cloneNode(true); line.style = ""; // remove style="display:none;" aircraftlist_body.appendChild(line); } else { var line = aircraftlist_body.rows[1 + i]; } var cells = line.cells; // manipulate registration: link to planespotters if( data[i].reg==null ) { data[i].reg=""; } else if( data[i].reg.includes("state") ) { } else if( data[i].reg!="" ) { data[i].reg = "" + data[i].reg + ""; } // manipulate lat and lon to links into internal maps if (data[i].lat == null || data[i].lon == null) { data[i].lat = ""; data[i].lon = ""; } else { // fragment identifier / anchor data[i].lat = "" + data[i].lat.toFixed(5) + ""; data[i].lon = "" + data[i].lon.toFixed(5) + ""; } if( data[i].org ) { data[i].org = '' + data[i].org; } if( data[i].dst ) { data[i].dst = '' + data[i].dst; } // manipulate Ground/Air, categorie and data source, distance data[i].gda = data[i].gda==null ? "" : gda_longtext(data[i].gda); data[i].cat = data[i].cat==null ? "" : '' + data[i].cat + ''; data[i].dis = data[i].dis==null ? "" : data[i].dis.toFixed(1); ['gda','cat','src','reg','fli','hex','org','orgh','dst','dsth','trk','hdgm','hdgt','alt','altg','spd','ias','vrt','typ','opr','cou','squ','spi','alr','ape','tcm','lat','lon','tas','qnhs','alts','hdgs','dbm','tmp','tim','tru','mop','dis','wsp','wdi','pic'].forEach( function(key) { if( aclist[key].visible ) { cells.namedItem(key).style.display = 'table-cell'; cells.namedItem(key).innerHTML = data[i][key]; } else { cells.namedItem(key).style.display = 'none'; } } ); } }); } function FilterControl(controlDiv) { var controlUI = document.createElement('div'); controlUI.className = 'colselect-icon'; controlUI.title = 'Click to modify the column select'; controlDiv.appendChild(controlUI); // create a string that contains all IDs of the checkboxes var all_checkbox_ids = '' var first = true; for (var key in aclist) { all_checkbox_ids += (first? '' : ', ') + '#enable_' + key; first = false; } all_checkbox_ids += ', #empty_on_top, #empty_on_bottom'; controlUI.addEventListener( 'click', function() { if (document.getElementById('colselect-dialog') === null) { var colselectDialog = document.createElement('div'); colselectDialog.id = 'colselect-dialog'; function update_checkboxes() { for (var key in aclist) { var input_field_id = '#enable_' + key; $(input_field_id).prop('checked', aclist[key].visible); } } // create a table which contains checkboxes for all keys var select_table = '
' + '' + '' + ''; for (var key in aclist) { var non_breaked_title = aclist[key].title.replace("
", " "); select_table += '"; } select_table +='' + '' + '' + '
Clear All
Select All
' + non_breaked_title + "
Sort empty fields to top
Sort empty fields to bottom
'; colselectDialog.innerHTML = select_table; controlDiv.appendChild(colselectDialog); update_checkboxes(); function handleChange() { for (var key in aclist) { var input_field_id = "#enable_" + key; aclist[key].visible = $(input_field_id).prop("checked") || false; } sort.empty_on_top = $("#empty_on_top").prop("checked") || false; setCookie( cookie_sort, JSON.stringify(sort), 9999 ); colselect = {}; for (var key in aclist) { colselect[key] = aclist[key].visible; } setCookie(cookie_colselect, JSON.stringify(colselect), 9999); aircraftlistSetVisibleColumns(); } $(all_checkbox_ids).change(handleChange); function setAll() { for (var key in aclist) { aclist[key].visible = true; } update_checkboxes(); } function clearAll() { for (var key in aclist) { aclist[key].visible = false; } update_checkboxes(); } $("#set_all").change(setAll); $("#clear_all").change(clearAll); $("#colselect-dialog .close").click(function() { handleChange(); $("#colselect-dialog").hide(); }); $("#colselect-dialog .clear").click(function() { $(all_checkbox_ids).val(true); handleChange(); }); $("#colselect-apply").click(function() { handleChange(); $("#colselect-dialog").hide(); }); } else { $("#colselect-dialog").show(); } }); } $(document).ready(function() { console.log("dynamic_aircraftlist.js-->document ready"); // read cookies // ------------ var tmp = []; var cookie = getCookie(cookie_sort); if( cookie ) { $.extend( tmp, JSON.parse(cookie) ); } for (var key in tmp) { if( key in sort ) { sort[key] = tmp[key]; } } tmp = []; var cookie = getCookie(cookie_colselect); if( cookie ) { $.extend( tmp, JSON.parse(cookie) ); } for (var key in tmp) { if( key in aclist ) { aclist[key].visible = tmp[key]; } } loadAirports(); createAircraftlist(); // create filter box // ----------------- // https://stackoverflow.com/questions/18266231/display-a-small-image-at-the-top-right-corner var filterControlDiv = document.getElementById("colselect-button"); var filterControl = new FilterControl(filterControlDiv); // create event listeners // ---------------------- $(".arrow-box .arrow-down").click(function(evt) { sort.key = $(this).parent().attr("id"); sort.asc = false; updateTable(); setCookie( cookie_sort, JSON.stringify(sort), 9999 ); }); $(".arrow-box .arrow-up").click(function(evt) { sort.key = $(this).parent().attr("id"); sort.asc = true; updateTable(); setCookie( cookie_sort, JSON.stringify(sort), 9999 ); }); $('body').on('click', '.hasicon > .icon', function() { // console.log("Icon Clicked"); }); // execute // ------- function loop() { if( rcd_globals.initialized ) { updateTable(); updateStatistics(); } //else // console.log(rcd_globals); var delay = Math.max(1000, refresh_time*1000); setTimeout( loop, delay ); } loop(); });