dump1090/public_html/script.js
terribl 11d69cb54b Tweaks and Fixes
Tweaked selected planes display so it won't push plane-table around. Added
link to FlightStats service and speed to selected plane table.

	modified:   public_html/script.js
	modified:   public_html/style.css
2013-05-26 15:19:38 +03:00

478 lines
14 KiB
JavaScript

// Define our global variables
var GoogleMap = null;
var Planes = {};
var PlanesOnMap = 0;
var PlanesOnTable = 0;
var PlanesToReap = 0;
var SelectedPlane = null;
var iSortCol=-1;
var bSortASC=true;
var bDefaultSortASC=true;
var iDefaultSortCol=3;
// Get current map settings
CenterLat = Number(localStorage['CenterLat']) || CONST_CENTERLAT;
CenterLon = Number(localStorage['CenterLon']) || CONST_CENTERLON;
ZoomLvl = Number(localStorage['ZoomLvl']) || CONST_ZOOMLVL;
function fetchData() {
$.getJSON('/dump1090/data.json', function(data) {
PlanesOnMap = 0
// Loop through all the planes in the data packet
for (var j=0; j < data.length; j++) {
// Do we already have this plane object in Planes?
// If not make it.
if (Planes[data[j].hex]) {
var plane = Planes[data[j].hex];
} else {
var plane = jQuery.extend(true, {}, planeObject);
}
// Call the function update
plane.funcUpdateData(data[j]);
// Copy the plane into Planes
Planes[plane.icao] = plane;
}
PlanesOnTable = data.length;
/* For special squawk tests */
//Planes['867840'].squawk = '7700';
});
}
// Initalizes the map and starts up our timers to call various functions
function initialize() {
// Make a list of all the available map IDs
var mapTypeIds = [];
for(var type in google.maps.MapTypeId) {
mapTypeIds.push(google.maps.MapTypeId[type]);
}
// Push OSM on to the end
mapTypeIds.push("OSM");
mapTypeIds.push("dark_map");
// Styled Map to outline airports and highways
var styles = [
{
"featureType": "administrative",
"stylers": [
{ "visibility": "off" }
]
},{
"featureType": "landscape",
"stylers": [
{ "visibility": "off" }
]
},{
"featureType": "poi",
"stylers": [
{ "visibility": "off" }
]
},{
"featureType": "road",
"stylers": [
{ "visibility": "off" }
]
},{
"featureType": "transit",
"stylers": [
{ "visibility": "off" }
]
},{
"featureType": "landscape",
"stylers": [
{ "visibility": "on" },
{ "weight": 8 },
{ "color": "#000000" }
]
},{
"featureType": "water",
"stylers": [
{ "lightness": -74 }
]
},{
"featureType": "transit.station.airport",
"stylers": [
{ "visibility": "on" },
{ "weight": 8 },
{ "invert_lightness": true },
{ "lightness": 27 }
]
},{
"featureType": "road.highway",
"stylers": [
{ "visibility": "simplified" },
{ "invert_lightness": true },
{ "gamma": 0.3 }
]
},{
"featureType": "road",
"elementType": "labels",
"stylers": [
{ "visibility": "off" }
]
}
]
// Add our styled map
var styledMap = new google.maps.StyledMapType(styles, {name: "Dark Map"});
// Define the Google Map
var mapOptions = {
center: new google.maps.LatLng(CenterLat, CenterLon),
zoom: ZoomLvl,
mapTypeId: google.maps.MapTypeId.ROADMAP,
mapTypeControlOptions: {
mapTypeIds: mapTypeIds,
}
};
GoogleMap = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
//Define OSM map type pointing at the OpenStreetMap tile server
GoogleMap.mapTypes.set("OSM", new google.maps.ImageMapType({
getTileUrl: function(coord, zoom) {
return "http://tile.openstreetmap.org/" + zoom + "/" + coord.x + "/" + coord.y + ".png";
},
tileSize: new google.maps.Size(256, 256),
name: "OpenStreetMap",
maxZoom: 18
}));
GoogleMap.mapTypes.set("dark_map", styledMap);
// Did our crafty user need some setup?
extendedInitalize();
// Setup our timer to poll from the server.
window.setInterval(function() {
fetchData();
refreshTableInfo();
refreshSelected();
reaper();
extendedPulse();
}, 1000);
}
// This looks for planes to reap out of the master Planes variable
function reaper() {
PlanesToReap = 0;
// When did the reaper start?
reaptime = new Date().getTime();
// Loop the planes
for (var reap in Planes) {
// Is this plane possibly reapable?
if (Planes[reap].reapable == true) {
// Has it not been seen for 5 minutes?
// This way we still have it if it returns before then
// Due to loss of signal or other reasons
if ((reaptime - Planes[reap].updated) > 300000) {
// Reap it.
delete Planes[reap];
}
PlanesToReap++;
}
};
}
// Refresh the detail window about the plane
function refreshSelected() {
var selected = false;
if (typeof SelectedPlane !== 'undefined' && SelectedPlane != "ICAO" && SelectedPlane != null) {
selected = Planes[SelectedPlane];
}
var columns = 2;
var html = '';
if (selected) {
html += '<table id="selectedinfo" width="100%">';
} else {
html += '<table id="selectedinfo" class="dim" width="100%">';
}
// Flight header line including squawk if needed
if (selected && selected.flight == "") {
html += '<tr><td colspan="' + columns + '" id="selectedinfotitle"><b>N/A (' + selected.icao + ')</b>';
} else if (selected && selected.flight != "") {
html += '<tr><td colspan="' + columns + '" id="selectedinfotitle"><b>' + selected.flight + '</b>';
} else {
html += '<tr><td colspan="' + columns + '" id="selectedinfotitle"><b>DUMP1090</b>';
}
if (selected && selected.squawk == 7500) { // Lets hope we never see this... Aircraft Hijacking
html += '&nbsp;<span class="squawk7500">&nbsp;Squawking: Aircraft Hijacking&nbsp;</span>';
} else if (selected && selected.squawk == 7600) { // Radio Failure
html += '&nbsp;<span class="squawk7600">&nbsp;Squawking: Radio Failure&nbsp;</span>';
} else if (selected && selected.squawk == 7700) { // General Emergency
html += '&nbsp;<span class="squawk7700">&nbsp;Squawking: General Emergency&nbsp;</span>';
} else if (selected && selected.flight != '') {
html += '&nbsp;<a href="http://www.flightstats.com/go/FlightStatus/flightStatusByFlight.do?';
html += 'flightNumber='+selected.flight+'" target="_blank">[FlightStats]</a>';
}
html += '<td></tr>';
if (selected) {
html += '<tr><td>Altitude: ' + selected.altitude + '</td>';
} else {
html += '<tr><td>Altitude: n/a</td>';
}
if (selected && selected.squawk != '0000') {
html += '<td>Squawk: ' + selected.squawk + '</td></tr>';
} else {
html += '<td>Squawk: n/a</td></tr>';
}
html += '<tr><td>Speed: '
if (selected) {
html += selected.speed + '&nbsp;kt';
} else {
html += 'n/a';
}
html += '</td>';
if (selected) {
html += '<td>ICAO (hex): ' + selected.icao + '</td></tr>';
} else {
html += '<td>ICAO (hex): n/a</td></tr>'; // Something is wrong if we are here
}
html += '<tr><td>Track: '
if (selected && selected.vTrack) {
html += selected.track + ' (' + normalizeTrack(selected.track, selected.vTrack)[1] +')';
} else {
html += 'n/a';
}
html += '</td><td>&nbsp;</td></tr>';
html += '<tr><td colspan="' + columns + '" align="center">Lat/Long: ';
if (selected && selected.vPosition) {
html += selected.latitude + ', ' + selected.longitude;
} else {
html += 'n/a';
}
html += '</td></tr>';
html += '</table>';
document.getElementById('plane_detail').innerHTML = html;
}
// Right now we have no means to validate the speed is good
// Want to return (n/a) when we dont have it
// TODO: Edit C code to add a valid speed flag
// TODO: Edit js code to use said flag
function normalizeSpeed(speed, valid) {
return speed
}
// Returns back a long string, short string, and the track if we have a vaild track path
function normalizeTrack(track, valid){
x = []
if ((track > -1) && (track < 22.5)) {
x = ["North", "N", track]
}
if ((track > 22.5) && (track < 67.5)) {
x = ["North East", "NE", track]
}
if ((track > 67.5) && (track < 112.5)) {
x = ["East", "E", track]
}
if ((track > 112.5) && (track < 157.5)) {
x = ["South East", "SE", track]
}
if ((track > 157.5) && (track < 202.5)) {
x = ["South", "S", track]
}
if ((track > 202.5) && (track < 247.5)) {
x = ["South West", "SW", track]
}
if ((track > 247.5) && (track < 292.5)) {
x = ["West", "W", track]
}
if ((track > 292.5) && (track < 337.5)) {
x = ["North West", "NW", track]
}
if ((track > 337.5) && (track < 361)) {
x = ["North", "N", track]
}
if (!valid) {
x = [" ", "n/a", ""]
}
return x
}
// Refeshes the larger table of all the planes
function refreshTableInfo() {
var html = '<table id="tableinfo" width="100%">';
html += '<thead style="background-color: #BBBBBB; cursor: pointer;">';
html += '<td onclick="setASC_DESC(\'0\');sortTable(\'tableinfo\',\'0\');">ICAO</td>';
html += '<td onclick="setASC_DESC(\'1\');sortTable(\'tableinfo\',\'1\');">Flight</td>';
html += '<td onclick="setASC_DESC(\'2\');sortTable(\'tableinfo\',\'2\');" align="right">Squawk</td>';
html += '<td onclick="setASC_DESC(\'3\');sortTable(\'tableinfo\',\'3\');" align="right">Altitude</td>';
html += '<td onclick="setASC_DESC(\'4\');sortTable(\'tableinfo\',\'4\');" align="right">Speed</td>';
html += '<td onclick="setASC_DESC(\'5\');sortTable(\'tableinfo\',\'5\');" align="right">Track</td>';
html += '<td onclick="setASC_DESC(\'6\');sortTable(\'tableinfo\',\'6\');" align="right">Msgs</td>';
html += '<td onclick="setASC_DESC(\'7\');sortTable(\'tableinfo\',\'7\');" align="right">Seen</td></thead><tbody>';
for (var tablep in Planes) {
var tableplane = Planes[tablep]
if (!tableplane.reapable) {
var specialStyle = "";
// Is this the plane we selected?
if (tableplane.icao == SelectedPlane) {
specialStyle += " selected";
}
// Lets hope we never see this... Aircraft Hijacking
if (tableplane.squawk == 7500) {
specialStyle += " squawk7500";
}
// Radio Failure
if (tableplane.squawk == 7600) {
specialStyle += " squawk7600";
}
// Emergancy
if (tableplane.squawk == 7700) {
specialStyle += " squawk7700";
}
if (tableplane.vPosition == true) {
html += '<tr class="plane_table_row vPosition' + specialStyle + '">';
} else {
html += '<tr class="plane_table_row ' + specialStyle + '">';
}
html += '<td>' + tableplane.icao + '</td>';
html += '<td>' + tableplane.flight + '</td>';
if (tableplane.squawk != '0000' ) {
html += '<td align="right">' + tableplane.squawk + '</td>';
} else {
html += '<td align="right">&nbsp;</td>';
}
html += '<td align="right">' + tableplane.altitude + '</td>';
html += '<td align="right">' + tableplane.speed + '</td>';
html += '<td align="right">';
if (tableplane.vTrack) {
html += normalizeTrack(tableplane.track, tableplane.vTrack)[2];
html += ' (' + normalizeTrack(tableplane.track, tableplane.vTrack)[1] + ')';
} else {
html += '&nbsp;';
}
html += '</td>';
html += '<td align="right">' + tableplane.messages + '</td>';
html += '<td align="right">' + tableplane.seen + '</td>';
html += '</tr>';
}
}
html += '</tbody></table>';
document.getElementById('planes_table').innerHTML = html;
// Click event for table
$('#planes_table').find('tr').click( function(){
var hex = $(this).find('td:first').text();
if (hex != "ICAO") {
selectPlaneByHex(hex);
refreshTableInfo();
refreshSelected();
}
});
sortTable("tableinfo");
}
// Credit goes to a co-worker that needed a similar functions for something else
// we get a copy of it free ;)
function setASC_DESC(iCol) {
if(iSortCol==iCol) {
bSortASC=!bSortASC;
} else {
bSortASC=bDefaultSortASC;
}
}
function sortTable(szTableID,iCol) {
//if iCol was not provided, and iSortCol is not set, assign default value
if (typeof iCol==='undefined'){
if(iSortCol!=-1){
var iCol=iSortCol;
} else {
var iCol=iDefaultSortCol;
}
}
//retrieve passed table element
var oTbl=document.getElementById(szTableID).tBodies[0];
var aStore=[];
//If supplied col # is greater than the actual number of cols, set sel col = to last col
if (typeof oTbl.rows[0] !== 'undefined' && oTbl.rows[0].cells.length <= iCol) {
iCol=(oTbl.rows[0].cells.length-1);
}
//store the col #
iSortCol=iCol;
//determine if we are delaing with numerical, or alphanumeric content
var bNumeric = false;
if ((typeof oTbl.rows[0] !== 'undefined') &&
(!isNaN(parseFloat(oTbl.rows[0].cells[iSortCol].textContent ||
oTbl.rows[0].cells[iSortCol].innerText)))) {
bNumeric = true;
}
//loop through the rows, storing each one inro aStore
for (var i=0,iLen=oTbl.rows.length;i<iLen;i++){
var oRow=oTbl.rows[i];
vColData=bNumeric?parseFloat(oRow.cells[iSortCol].textContent||oRow.cells[iSortCol].innerText):String(oRow.cells[iSortCol].textContent||oRow.cells[iSortCol].innerText);
aStore.push([vColData,oRow]);
}
//sort aStore ASC/DESC based on value of bSortASC
if (bNumeric) { //numerical sort
aStore.sort(function(x,y){return bSortASC?x[0]-y[0]:y[0]-x[0];});
} else { //alpha sort
aStore.sort();
if(!bSortASC) {
aStore.reverse();
}
}
//rewrite the table rows to the passed table element
for(var i=0,iLen=aStore.length;i<iLen;i++){
oTbl.appendChild(aStore[i][1]);
}
aStore=null;
}
function selectPlaneByHex(hex) {
// If SelectedPlane has something in it, clear out the selected
if (SelectedPlane != null) {
Planes[SelectedPlane].is_selected = false;
Planes[SelectedPlane].funcClearLine();
Planes[SelectedPlane].markerColor = MarkerColor;
// If the selected has a marker, make it not stand out
if (Planes[SelectedPlane].marker) {
Planes[SelectedPlane].marker.setIcon(Planes[SelectedPlane].funcGetIcon());
}
}
// If we are clicking the same plane, we are deselected it.
if (String(SelectedPlane) != String(hex)) {
// Assign the new selected
SelectedPlane = hex;
Planes[SelectedPlane].is_selected = true;
// If the selected has a marker, make it stand out
if (Planes[SelectedPlane].marker) {
Planes[SelectedPlane].funcUpdateLines();
Planes[SelectedPlane].marker.setIcon(Planes[SelectedPlane].funcGetIcon());
}
} else {
SelectedPlane = null;
}
}