Lots more map work, mostly around switching from "construct a big HTML string"
to working directly with the DOM to update the table / selected plane info. Seems to speed things up (and deflicker them) a lot. Also stable sorts, allow disabling the clocks, draw ground tracks in a different color, put "last seen" info on the selected plane infobox, if position updates are infrequent then combine them into a single estimated line so that dash placement works properly, probably a bunch of other things..
This commit is contained in:
parent
e8a62293c2
commit
43d29389f2
|
@ -32,3 +32,6 @@ SiteCircles = true; // true or false (Only shown if SiteShow is true)
|
||||||
// In nautical miles or km (depending settings value 'Metric')
|
// In nautical miles or km (depending settings value 'Metric')
|
||||||
SiteCirclesDistances = new Array(100,150,200);
|
SiteCirclesDistances = new Array(100,150,200);
|
||||||
|
|
||||||
|
|
||||||
|
// You can disable the clocks if you want here:
|
||||||
|
ShowClocks = false;
|
||||||
|
|
|
@ -49,16 +49,116 @@
|
||||||
</tr></table>
|
</tr></table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="plane_detail"></div>
|
<div id="dump1090_infoblock">
|
||||||
|
<table width="100%">
|
||||||
|
<tr class="infoblock_heading">
|
||||||
|
<td>
|
||||||
|
<b>DUMP1090</b>
|
||||||
|
</td>
|
||||||
|
<td align="right">
|
||||||
|
<span id="dump1090_version"></span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="infoblock_body">
|
||||||
|
<td width="50%"> </td>
|
||||||
|
<td width="50%" align="right"><a href="https://github.com/mutability/dump1090" target="_blank">[GitHub]</a></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="infoblock_body dim">
|
||||||
|
<td>(no aircraft selected)</td>
|
||||||
|
<td> </td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="infoblock_body">
|
||||||
|
<td> </td>
|
||||||
|
<td> </td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="infoblock_body">
|
||||||
|
<td colspan="2">Tracked aircraft (total): <span id="dump1090_total_ac">n/a</span></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="infoblock_body">
|
||||||
|
<td colspan="2">Tracked aircraft (with positions): <span id="dump1090_total_ac_positions">n/a</span></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="selected_infoblock" class="hidden">
|
||||||
|
<table width="100%">
|
||||||
|
<tr class="infoblock_heading">
|
||||||
|
<td colspan="2">
|
||||||
|
<b> <span id="selected_callsign">n/a</span></b>
|
||||||
|
<span id="selected_emergency"></span>
|
||||||
|
<span id="selected_links">
|
||||||
|
<a id="selected_fr24_link" href="" target="_blank">[FR24]</a>
|
||||||
|
<a id="selected_flightstats_link" href="" target="_blank">[FlightStats]</a>
|
||||||
|
<a id="selected_flightaware_link" href="" target="_blank">[FlightAware]</a>
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="infoblock_body">
|
||||||
|
<td width="50%">Altitude: <span id="selected_altitude"></span></td>
|
||||||
|
<td width="50%">Squawk: <span id="selected_squawk"></span></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="infoblock_body">
|
||||||
|
<td>Speed: <span id="selected_speed">n/a</span></td>
|
||||||
|
<td>ICAO: <span id="selected_icao">n/a</span></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="infoblock_body">
|
||||||
|
<td>Track: <span id="selected_track">n/a</span></td>
|
||||||
|
<td>Last seen: <span id="selected_seen">n/a</span</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="infoblock_body">
|
||||||
|
<td colspan="2">Lat/Long: <span id="selected_position">n/a</span></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="infoblock_body">
|
||||||
|
<td colspan="2">Distance from Site: <span id="selected_sitedist">n/a</span></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
<div id="options"></div>
|
<div id="options"></div>
|
||||||
<div id="planes_table"></div>
|
<div id="planes_table">
|
||||||
|
<table id="tableinfo" width="100%">
|
||||||
|
<thead style="background-color: #BBBBBB; cursor: pointer;">
|
||||||
|
<td id="icao" onclick="sortByICAO();">ICAO</td>
|
||||||
|
<td id="flight" onclick="sortByFlight();">Flight</td>
|
||||||
|
<td id="squawk" onclick="sortBySquawk();" align="right">Squawk</td>
|
||||||
|
<td id="altitude" onclick="sortByAltitude();" align="right">Altitude</td>
|
||||||
|
<td id="speed" onclick="sortBySpeed();" align="right">Speed</td>
|
||||||
|
<td id="distance" onclick="sortByDistance();" align="right">Distance</td>
|
||||||
|
<td id="track" onclick="sortByTrack();" align="right">Track</td>
|
||||||
|
<td id="msgs" onclick="sortByMsgs();" align="right">Msgs</td>
|
||||||
|
<td id="seen" onclick="sortBySeen();" align="right">Age</td>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr id="plane_row_template" class="plane_table_row hidden">
|
||||||
|
<td>ICAO</td>
|
||||||
|
<td>FLIGHT</td>
|
||||||
|
<td align="right">SQUAWK</td>
|
||||||
|
<td align="right">ALTITUDE</td>
|
||||||
|
<td align="right">SPEED</td>
|
||||||
|
<td align="right">DISTANCE</td>
|
||||||
|
<td align="right">TRACK</td>
|
||||||
|
<td align="right">MSGS</td>
|
||||||
|
<td align="right">SEEN</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
<div id="plane_extension"></div>
|
<div id="plane_extension"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="SpecialSquawkWarning">
|
<div id="SpecialSquawkWarning" class="hidden">
|
||||||
<b>Squak 7x00 is reported and shown.</b><br>
|
<b>Squawk 7x00 is reported and shown.</b><br>
|
||||||
This is most likely an error in reciving or decoding.<br>
|
This is most likely an error in receiving or decoding.<br>
|
||||||
Please do not call the local authorities, they already know about it if it is valid squak.
|
Please do not call the local authorities, they already know about it if it is a valid squawk.
|
||||||
</div>
|
</div>
|
||||||
<div id="container_splitter"></div>
|
<div id="container_splitter"></div>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -19,7 +19,6 @@ var planeObject = {
|
||||||
// GMap Details
|
// GMap Details
|
||||||
marker : null,
|
marker : null,
|
||||||
markerColor : MarkerColor,
|
markerColor : MarkerColor,
|
||||||
lines : [],
|
|
||||||
|
|
||||||
tracklinesegs : [],
|
tracklinesegs : [],
|
||||||
last_position_time : null,
|
last_position_time : null,
|
||||||
|
@ -39,27 +38,71 @@ var planeObject = {
|
||||||
line : null,
|
line : null,
|
||||||
head_update : this.last_position_time,
|
head_update : this.last_position_time,
|
||||||
tail_update : this.last_position_time,
|
tail_update : this.last_position_time,
|
||||||
estimated : false };
|
estimated : false,
|
||||||
|
ground : (this.altitude === "ground")
|
||||||
|
};
|
||||||
this.tracklinesegs.push(newseg);
|
this.tracklinesegs.push(newseg);
|
||||||
} else {
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var lastseg = this.tracklinesegs[this.tracklinesegs.length - 1];
|
var lastseg = this.tracklinesegs[this.tracklinesegs.length - 1];
|
||||||
var lastpos = lastseg.track.getAt(lastseg.track.getLength() - 1);
|
var lastpos = lastseg.track.getAt(lastseg.track.getLength() - 1);
|
||||||
var elapsed = (this.last_position_time - lastseg.head_update);
|
var elapsed = (this.last_position_time - lastseg.head_update);
|
||||||
if (elapsed > 5) {
|
|
||||||
// >5s gap in data, put an estimated segment in
|
var new_data = (here !== lastpos);
|
||||||
//console.log(this.icao + " discontinuity seen: " + lastpos.lat() + "," + lastpos.lng() + " -> " + here.lat() + "," + here.lng());
|
var est_track = (elapsed > 5);
|
||||||
var estseg = { track : new google.maps.MVCArray([lastpos, here]),
|
var ground_track = (this.altitude === "ground");
|
||||||
|
|
||||||
|
if (!new_data)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (est_track) {
|
||||||
|
if (!lastseg.estimated) {
|
||||||
|
// >5s gap in data, create a new estimated segment
|
||||||
|
//console.log(this.icao + " switching to estimated");
|
||||||
|
this.tracklinesegs.push({ track : new google.maps.MVCArray([lastpos, here]),
|
||||||
line : null,
|
line : null,
|
||||||
estimated : true };
|
head_update : this.last_position_time,
|
||||||
var newseg = { track : new google.maps.MVCArray([here,here]),
|
estimated : true });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append to ongoing estimated line
|
||||||
|
//console.log(this.icao + " extending estimated (" + lastseg.track.getLength() + ")");
|
||||||
|
lastseg.track.push(here);
|
||||||
|
lastseg.head_update = this.last_position_time;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastseg.estimated) {
|
||||||
|
// We are back to good data.
|
||||||
|
//console.log(this.icao + " switching to good track");
|
||||||
|
this.tracklinesegs.push({ track : new google.maps.MVCArray([lastpos, here]),
|
||||||
line : null,
|
line : null,
|
||||||
head_update : this.last_position_time,
|
head_update : this.last_position_time,
|
||||||
tail_update : this.last_position_time,
|
tail_update : this.last_position_time,
|
||||||
estimated : false };
|
estimated : false,
|
||||||
this.tracklinesegs.push(estseg);
|
ground : (this.altitude === "ground") });
|
||||||
this.tracklinesegs.push(newseg);
|
return;
|
||||||
} else if (elapsed > 0) {
|
}
|
||||||
// New position data
|
|
||||||
|
if ( (lastseg.ground && this.altitude !== "ground") ||
|
||||||
|
(!lastseg.ground && this.altitude === "ground") ) {
|
||||||
|
console.log(this.icao + " ground state changed");
|
||||||
|
// Create a new segment as the ground state changed.
|
||||||
|
// assume the state changed halfway between the two points
|
||||||
|
var midpoint = google.maps.geometry.spherical.interpolate(lastpos,here,0.5);
|
||||||
|
lastseg.track.push(midpoint);
|
||||||
|
this.tracklinesegs.push({ track : new google.maps.MVCArray([midpoint,here,here]),
|
||||||
|
line : null,
|
||||||
|
head_update : this.last_position_time,
|
||||||
|
tail_update : this.last_position_time,
|
||||||
|
estimated : false,
|
||||||
|
ground : (this.altitude === "ground") });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add more data to the existing track.
|
||||||
// We only retain some historical points, at 5+ second intervals,
|
// We only retain some historical points, at 5+ second intervals,
|
||||||
// plus the most recent point
|
// plus the most recent point
|
||||||
if (this.last_position_time - lastseg.tail_update >= 5) {
|
if (this.last_position_time - lastseg.tail_update >= 5) {
|
||||||
|
@ -72,8 +115,6 @@ var planeObject = {
|
||||||
lastseg.track.setAt(lastseg.track.getLength()-1, here);
|
lastseg.track.setAt(lastseg.track.getLength()-1, here);
|
||||||
}
|
}
|
||||||
lastseg.head_update = this.last_position_time;
|
lastseg.head_update = this.last_position_time;
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// This is to remove the line from the screen if we deselect the plane
|
// This is to remove the line from the screen if we deselect the plane
|
||||||
|
@ -161,7 +202,7 @@ var planeObject = {
|
||||||
},
|
},
|
||||||
|
|
||||||
// TODO: Trigger actions of a selecting a plane
|
// TODO: Trigger actions of a selecting a plane
|
||||||
funcSelectPlane : function(selectedPlane){
|
selectPlane : function(){
|
||||||
selectPlaneByHex(this.icao);
|
selectPlaneByHex(this.icao);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -182,6 +223,7 @@ var planeObject = {
|
||||||
if (typeof data.lat !== "undefined") {
|
if (typeof data.lat !== "undefined") {
|
||||||
this.latitude = data.lat;
|
this.latitude = data.lat;
|
||||||
this.longitude = data.lon;
|
this.longitude = data.lon;
|
||||||
|
this.seen_pos = data.seen_pos;
|
||||||
this.last_position_time = receiver_now - data.seen_pos;
|
this.last_position_time = receiver_now - data.seen_pos;
|
||||||
}
|
}
|
||||||
if (typeof data.flight !== "undefined")
|
if (typeof data.flight !== "undefined")
|
||||||
|
@ -197,7 +239,7 @@ var planeObject = {
|
||||||
this.marker.setMap(null);
|
this.marker.setMap(null);
|
||||||
this.marker = null;
|
this.marker = null;
|
||||||
}
|
}
|
||||||
this.funcClearLines();
|
this.funcClearLine();
|
||||||
if (SelectedPlane == this.icao) {
|
if (SelectedPlane == this.icao) {
|
||||||
if (this.is_selected) {
|
if (this.is_selected) {
|
||||||
this.is_selected = false;
|
this.is_selected = false;
|
||||||
|
@ -216,7 +258,6 @@ var planeObject = {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.marker = this.funcUpdateMarker();
|
this.marker = this.funcUpdateMarker();
|
||||||
PlanesOnMap++;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -230,14 +271,14 @@ var planeObject = {
|
||||||
position: new google.maps.LatLng(this.latitude, this.longitude),
|
position: new google.maps.LatLng(this.latitude, this.longitude),
|
||||||
map: GoogleMap,
|
map: GoogleMap,
|
||||||
icon: this.funcGetIcon(),
|
icon: this.funcGetIcon(),
|
||||||
visable: true
|
visible: true
|
||||||
});
|
});
|
||||||
|
|
||||||
// This is so we can match icao address
|
// This is so we can match icao address
|
||||||
this.marker.icao = this.icao;
|
this.marker.icao = this.icao;
|
||||||
|
|
||||||
// Trap clicks for this marker.
|
// Trap clicks for this marker.
|
||||||
google.maps.event.addListener(this.marker, 'click', this.funcSelectPlane);
|
google.maps.event.addListener(this.marker, 'click', this.selectPlane);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setting the marker title
|
// Setting the marker title
|
||||||
|
@ -261,12 +302,31 @@ var planeObject = {
|
||||||
// console.log(" point " + j + " at " + seg.track.getAt(j).lat() + "," + seg.track.getAt(j).lng());
|
// console.log(" point " + j + " at " + seg.track.getAt(j).lat() + "," + seg.track.getAt(j).lng());
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
if (seg.estimated) {
|
||||||
|
var lineSymbol = {
|
||||||
|
path: 'M 0,-1 0,1',
|
||||||
|
strokeOpacity : 1,
|
||||||
|
strokeColor : '#804040',
|
||||||
|
strokeWeight : 2,
|
||||||
|
scale: 2
|
||||||
|
};
|
||||||
|
|
||||||
seg.line = new google.maps.Polyline({
|
seg.line = new google.maps.Polyline({
|
||||||
strokeColor: (seg.estimated ? '#804040' : '#000000'),
|
path: seg.track,
|
||||||
|
strokeOpacity: 0,
|
||||||
|
icons: [{
|
||||||
|
icon: lineSymbol,
|
||||||
|
offset: '0',
|
||||||
|
repeat: '10px' }],
|
||||||
|
map : GoogleMap });
|
||||||
|
} else {
|
||||||
|
seg.line = new google.maps.Polyline({
|
||||||
|
path: seg.track,
|
||||||
strokeOpacity: 1.0,
|
strokeOpacity: 1.0,
|
||||||
strokeWeight: (seg.estimated ? 2 : 3),
|
strokeColor: (seg.ground ? '#408040' : '#000000'),
|
||||||
map: GoogleMap,
|
strokeWeight: 3,
|
||||||
path: seg.track });
|
map: GoogleMap });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
// Define our global variables
|
// Define our global variables
|
||||||
var GoogleMap = null;
|
var GoogleMap = null;
|
||||||
var Planes = {};
|
var Planes = {};
|
||||||
var PlanesOnMap = 0;
|
var PlanesOrdered = [];
|
||||||
var PlanesOnTable = 0;
|
|
||||||
var PlanesToReap = 0;
|
|
||||||
var SelectedPlane = null;
|
var SelectedPlane = null;
|
||||||
var SpecialSquawk = false;
|
|
||||||
|
|
||||||
var sortColumn = 3;
|
var EmergencySquawks = {
|
||||||
var sortAscending = true;
|
'7500' : 'Aircraft Hijacking',
|
||||||
var sortNumeric = true;
|
'7600' : 'Radio Failure',
|
||||||
|
'7700' : 'General Emergency'
|
||||||
|
};
|
||||||
|
|
||||||
// Get current map settings
|
// Get current map settings
|
||||||
CenterLat = Number(localStorage['CenterLat']) || CONST_CENTERLAT;
|
CenterLat = Number(localStorage['CenterLat']) || CONST_CENTERLAT;
|
||||||
|
@ -19,39 +18,54 @@ ZoomLvl = Number(localStorage['ZoomLvl']) || CONST_ZOOMLVL;
|
||||||
Dump1090Version = "unknown version";
|
Dump1090Version = "unknown version";
|
||||||
RefreshInterval = 1000;
|
RefreshInterval = 1000;
|
||||||
|
|
||||||
|
PlaneRowTemplate = null;
|
||||||
|
|
||||||
|
TrackedAircraft = 0
|
||||||
|
TrackedPositions = 0
|
||||||
|
|
||||||
function fetchData() {
|
function fetchData() {
|
||||||
$.getJSON('data/aircraft.json', function(data) {
|
$.getJSON('data/aircraft.json', function(data) {
|
||||||
PlanesOnMap = 0;
|
|
||||||
SpecialSquawk = false;
|
|
||||||
|
|
||||||
// Loop through all the planes in the data packet
|
// Loop through all the planes in the data packet
|
||||||
var now = data.now;
|
var now = data.now;
|
||||||
var acs = data.aircraft;
|
var acs = data.aircraft;
|
||||||
for (var j=0; j < acs.length; j++) {
|
for (var j=0; j < acs.length; j++) {
|
||||||
var ac = acs[j];
|
var ac = acs[j];
|
||||||
|
var hex = ac.hex;
|
||||||
|
var plane = null;
|
||||||
|
|
||||||
// Do we already have this plane object in Planes?
|
// Do we already have this plane object in Planes?
|
||||||
// If not make it.
|
// If not make it.
|
||||||
if (Planes[ac.hex]) {
|
|
||||||
var plane = Planes[ac.hex];
|
|
||||||
} else {
|
|
||||||
var plane = jQuery.extend(true, {}, planeObject);
|
|
||||||
Planes[ac.hex] = plane;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set SpecialSquawk-value
|
if (Planes[hex]) {
|
||||||
if (ac.squawk == '7500' || ac.squawk == '7600' || ac.squawk == '7700') {
|
plane = Planes[hex];
|
||||||
SpecialSquawk = true;
|
} else {
|
||||||
|
plane = jQuery.extend(true, {}, planeObject);
|
||||||
|
|
||||||
|
plane.tr = PlaneRowTemplate.cloneNode(true);
|
||||||
|
plane.tr.cells[0].textContent = hex; // this won't change
|
||||||
|
plane.tr.addEventListener('click', $.proxy(plane.selectPlane, plane));
|
||||||
|
plane.sitedist = null;
|
||||||
|
|
||||||
|
Planes[hex] = plane;
|
||||||
|
PlanesOrdered.push(plane);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call the function update
|
// Call the function update
|
||||||
plane.funcUpdateData(now, ac);
|
plane.funcUpdateData(now, ac);
|
||||||
}
|
}
|
||||||
|
|
||||||
PlanesOnTable = acs.length;
|
refreshTableInfo();
|
||||||
|
refreshSelected();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function initialize() {
|
function initialize() {
|
||||||
|
PlaneRowTemplate = document.getElementById("plane_row_template");
|
||||||
|
|
||||||
|
if (!ShowClocks) {
|
||||||
|
$('#timestamps').addClass('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
// Get receiver metadata, reconfigure using it, then continue
|
// Get receiver metadata, reconfigure using it, then continue
|
||||||
// with initialization
|
// with initialization
|
||||||
$.getJSON('data/receiver.json')
|
$.getJSON('data/receiver.json')
|
||||||
|
@ -72,6 +86,18 @@ function initialize() {
|
||||||
|
|
||||||
// Initalizes the map and starts up our timers to call various functions
|
// Initalizes the map and starts up our timers to call various functions
|
||||||
function initialize_after_config() {
|
function initialize_after_config() {
|
||||||
|
// Set SitePosition, initialize sorting
|
||||||
|
|
||||||
|
if (SiteShow && (typeof SiteLat !== 'undefined') && (typeof SiteLon !== 'undefined')) {
|
||||||
|
SitePosition = new google.maps.LatLng(SiteLat, SiteLon);
|
||||||
|
sortByDistance();
|
||||||
|
} else {
|
||||||
|
SitePosition = null;
|
||||||
|
PlaneRowTemplate.cells[5].className = "hidden"; // hide distance column
|
||||||
|
document.getElementById("distance").className = "hidden"; // hide distance header
|
||||||
|
sortByAltitude();
|
||||||
|
}
|
||||||
|
|
||||||
// Make a list of all the available map IDs
|
// Make a list of all the available map IDs
|
||||||
var mapTypeIds = [];
|
var mapTypeIds = [];
|
||||||
for(var type in google.maps.MapTypeId) {
|
for(var type in google.maps.MapTypeId) {
|
||||||
|
@ -186,15 +212,14 @@ function initialize_after_config() {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add home marker if requested
|
// Add home marker if requested
|
||||||
if (SiteShow && (typeof SiteLat !== 'undefined' || typeof SiteLon !== 'undefined')) {
|
if (SitePosition) {
|
||||||
var siteMarker = new google.maps.LatLng(SiteLat, SiteLon);
|
|
||||||
var markerImage = new google.maps.MarkerImage(
|
var markerImage = new google.maps.MarkerImage(
|
||||||
'http://maps.google.com/mapfiles/kml/pal4/icon57.png',
|
'http://maps.google.com/mapfiles/kml/pal4/icon57.png',
|
||||||
new google.maps.Size(32, 32), // Image size
|
new google.maps.Size(32, 32), // Image size
|
||||||
new google.maps.Point(0, 0), // Origin point of image
|
new google.maps.Point(0, 0), // Origin point of image
|
||||||
new google.maps.Point(16, 16)); // Position where marker should point
|
new google.maps.Point(16, 16)); // Position where marker should point
|
||||||
var marker = new google.maps.Marker({
|
var marker = new google.maps.Marker({
|
||||||
position: siteMarker,
|
position: SitePosition,
|
||||||
map: GoogleMap,
|
map: GoogleMap,
|
||||||
icon: markerImage,
|
icon: markerImage,
|
||||||
title: 'My Radar Site',
|
title: 'My Radar Site',
|
||||||
|
@ -220,34 +245,33 @@ function initialize_after_config() {
|
||||||
extendedInitalize();
|
extendedInitalize();
|
||||||
|
|
||||||
// Setup our timer to poll from the server.
|
// Setup our timer to poll from the server.
|
||||||
window.setInterval(function() {
|
window.setInterval(fetchData, RefreshInterval);
|
||||||
fetchData();
|
window.setInterval(reaper, 60000);
|
||||||
refreshTableInfo();
|
|
||||||
refreshSelected();
|
|
||||||
reaper();
|
|
||||||
extendedPulse();
|
|
||||||
}, RefreshInterval);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This looks for planes to reap out of the master Planes variable
|
// This looks for planes to reap out of the master Planes variable
|
||||||
function reaper() {
|
function reaper() {
|
||||||
PlanesToReap = 0;
|
|
||||||
// When did the reaper start?
|
|
||||||
reaptime = new Date().getTime();
|
reaptime = new Date().getTime();
|
||||||
|
|
||||||
|
console.log("Reaping started..");
|
||||||
|
|
||||||
// Loop the planes
|
// Loop the planes
|
||||||
for (var reap in Planes) {
|
var newPlanes = [];
|
||||||
// Is this plane possibly reapable?
|
for (var i = 0; i < PlanesOrdered.length; ++i) {
|
||||||
if (Planes[reap].reapable == true) {
|
var plane = PlanesOrdered[i];
|
||||||
// Has it not been seen for 5 minutes?
|
if ((reaptime - plane.updated) > 300000) {
|
||||||
// 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.
|
// Reap it.
|
||||||
delete Planes[reap];
|
console.log("Reaped " + plane.icao);
|
||||||
}
|
delete Planes[plane.icao];
|
||||||
PlanesToReap++;
|
} else {
|
||||||
|
// Keep it.
|
||||||
|
newPlanes.push(plane);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
PlanesOrdered = newPlanes;
|
||||||
|
refreshTableInfo();
|
||||||
|
refreshSelected();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refresh the detail window about the plane
|
// Refresh the detail window about the plane
|
||||||
|
@ -257,313 +281,284 @@ function refreshSelected() {
|
||||||
selected = Planes[SelectedPlane];
|
selected = Planes[SelectedPlane];
|
||||||
}
|
}
|
||||||
|
|
||||||
var columns = 2;
|
if (!selected) {
|
||||||
var html = '';
|
$('#dump1090_infoblock').removeClass('hidden');
|
||||||
|
$('#dump1090_version').text(Dump1090Version);
|
||||||
|
$('#dump1090_total_ac').text(TrackedAircraft);
|
||||||
|
$('#dump1090_total_ac_positions').text(TrackedAircraftPositions);
|
||||||
|
$('#selected_infoblock').addClass('hidden');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (selected) {
|
$('#dump1090_infoblock').addClass('hidden');
|
||||||
html += '<table id="selectedinfo" width="100%">';
|
$('#selected_infoblock').removeClass('hidden');
|
||||||
|
|
||||||
|
if (selected.flight !== null && selected.flight !== "") {
|
||||||
|
$('#selected_callsign').text(selected.flight);
|
||||||
|
$('#selected_links').removeClass('hidden');
|
||||||
|
$('#selected_fr24_link').attr('href','http://fr24.com/'+selected.flight);
|
||||||
|
$('#selected_flightstats_link').attr('href','http://www.flightstats.com/go/FlightStatus/flightStatusByFlight.do?flightNumber='+selected.flight);
|
||||||
|
$('#selected_flightaware_link').attr('href','http://flightaware.com/live/flight/'+selected.flight);
|
||||||
} else {
|
} else {
|
||||||
html += '<table id="selectedinfo" class="dim" width="100%">';
|
$('#selected_callsign').text('n/a (' + selected.icao + ')');
|
||||||
|
$('#selected_links').addClass('hidden');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flight header line including squawk if needed
|
var emerg = document.getElementById('selected_emergency');
|
||||||
if (selected && selected.flight == "") {
|
if (selected.squawk in EmergencySquawks) {
|
||||||
html += '<tr><td colspan="' + columns + '" id="selectedinfotitle"><b>N/A (' +
|
emerg.className = 'squawk' + selected.squawk;
|
||||||
selected.icao + ')</b>';
|
emerg.textContent = '\u00a0Squawking: ' + EmergencySquawks[selected.squawk] + '\u00a0';
|
||||||
} else if (selected && selected.flight != "") {
|
|
||||||
html += '<tr><td colspan="' + columns + '" id="selectedinfotitle"><b>' +
|
|
||||||
selected.flight + '</b>';
|
|
||||||
} else {
|
} else {
|
||||||
html += '<tr><td colspan="' + columns + '" id="selectedinfotitle"><b>DUMP1090 ' + Dump1090Version + '</b> <a href="https://github.com/mutability/dump1090" target="_blank">[GitHub]</a>';
|
emerg.className = 'hidden';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selected && selected.squawk == 7500) { // Lets hope we never see this... Aircraft Hijacking
|
if (selected.altitude === null)
|
||||||
html += ' <span class="squawk7500"> Squawking: Aircraft Hijacking </span>';
|
$("#selected_altitude").text("n/a");
|
||||||
} else if (selected && selected.squawk == 7600) { // Radio Failure
|
else if (selected.altitude === "ground")
|
||||||
html += ' <span class="squawk7600"> Squawking: Radio Failure </span>';
|
$("#selected_altitude").text("on ground");
|
||||||
} else if (selected && selected.squawk == 7700) { // General Emergency
|
else if (Metric)
|
||||||
html += ' <span class="squawk7700"> Squawking: General Emergency </span>';
|
$("#selected_altitude").text(Math.round(selected.altitude / 3.2828) + ' m');
|
||||||
} else if (selected && selected.flight != '') {
|
else
|
||||||
html += ' <a href="http://fr24.com/'+selected.flight+'" target="_blank">[FR24]</a>';
|
$("#selected_altitude").text(Math.round(selected.altitude) + ' ft');
|
||||||
html += ' <a href="http://www.flightstats.com/go/FlightStatus/flightStatusByFlight.do?';
|
|
||||||
html += 'flightNumber='+selected.flight+'" target="_blank">[FlightStats]</a>';
|
|
||||||
html += ' <a href="http://flightaware.com/live/flight/'+selected.flight+'" target="_blank">[FlightAware]</a>';
|
|
||||||
}
|
|
||||||
html += '<td></tr>';
|
|
||||||
|
|
||||||
if (selected && selected.altitude !== null) {
|
if (selected.squawk === null || selected.squawk === '0000') {
|
||||||
if (selected.altitude === "ground")
|
$('#selected_squawk').text('n/a');
|
||||||
html += '<tr><td>Altitude: on ground</td>';
|
|
||||||
else if (Metric) {
|
|
||||||
html += '<tr><td>Altitude: ' + Math.round(selected.altitude / 3.2828) + ' m</td>';
|
|
||||||
} else {
|
} else {
|
||||||
html += '<tr><td>Altitude: ' + selected.altitude + ' ft</td>';
|
$('#selected_squawk').text(selected.squawk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (selected.speed === null) {
|
||||||
|
$('#selected_speed').text('n/a');
|
||||||
|
} else if (Metric) {
|
||||||
|
$('#selected_speed').text(Math.round(selected.speed * 1.852) + ' km/h');
|
||||||
} else {
|
} else {
|
||||||
html += '<tr><td>Altitude: n/a</td>';
|
$('#selected_speed').text(Math.round(selected.speed) + ' kt');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selected && selected.squawk != '0000') {
|
$('#selected_icao').text(selected.icao);
|
||||||
html += '<td>Squawk: ' + selected.squawk + '</td></tr>';
|
|
||||||
|
if (selected.track === null) {
|
||||||
|
$('#selected_track').text('n/a');
|
||||||
} else {
|
} else {
|
||||||
html += '<td>Squawk: n/a</td></tr>';
|
$('#selected_track').text(selected.track + '\u00b0' + ' (' + trackLongName(selected.track) + ')');
|
||||||
}
|
}
|
||||||
|
|
||||||
html += '<tr><td>Speed: '
|
if (selected.seen <= 1) {
|
||||||
if (selected) {
|
$('#selected_seen').text('now');
|
||||||
if (Metric) {
|
|
||||||
html += Math.round(selected.speed * 1.852) + ' km/h';
|
|
||||||
} else {
|
} else {
|
||||||
html += selected.speed + ' kt';
|
$('#selected_seen').text(selected.seen + 's ago');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (selected.latitude === null) {
|
||||||
|
$('#selected_position').text('n/a');
|
||||||
} else {
|
} else {
|
||||||
html += 'n/a';
|
if (selected.seen_pos > 1) {
|
||||||
}
|
$('#selected_position').text(selected.latitude + ', ' + selected.longitude + " (" + selected.seen_pos + "s ago)");
|
||||||
html += '</td>';
|
|
||||||
|
|
||||||
if (selected) {
|
|
||||||
html += '<td>ICAO (hex): ' + selected.icao + '</td></tr>';
|
|
||||||
} else {
|
} else {
|
||||||
html += '<td>ICAO (hex): n/a</td></tr>'; // Something is wrong if we are here
|
$('#selected_position').text(selected.latitude + ', ' + selected.longitude);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
html += '<tr><td>Track: '
|
if (selected.sitedist !== null) {
|
||||||
if (selected && selected.track !== null) {
|
var dist = selected.sitedist;
|
||||||
html += selected.track + '°' + ' (' + trackLongName(selected.track) +')';
|
|
||||||
} else {
|
|
||||||
html += 'n/a';
|
|
||||||
}
|
|
||||||
html += '</td><td> </td></tr>';
|
|
||||||
|
|
||||||
html += '<tr><td colspan="' + columns + '" align="center">Lat/Long: ';
|
|
||||||
if (selected && selected.latitude !== null) {
|
|
||||||
html += selected.latitude + ', ' + selected.longitude + '</td></tr>';
|
|
||||||
|
|
||||||
// Let's show some extra data if we have site coordinates
|
|
||||||
if (SiteShow) {
|
|
||||||
var siteLatLon = new google.maps.LatLng(SiteLat, SiteLon);
|
|
||||||
var planeLatLon = new google.maps.LatLng(selected.latitude, selected.longitude);
|
|
||||||
var dist = google.maps.geometry.spherical.computeDistanceBetween (siteLatLon, planeLatLon);
|
|
||||||
|
|
||||||
if (Metric) {
|
if (Metric) {
|
||||||
dist /= 1000;
|
dist /= 1000;
|
||||||
} else {
|
} else {
|
||||||
dist /= 1852;
|
dist /= 1852;
|
||||||
}
|
}
|
||||||
|
|
||||||
dist = (Math.round((dist)*10)/10).toFixed(1);
|
dist = (Math.round((dist)*10)/10).toFixed(1);
|
||||||
html += '<tr><td colspan="' + columns + '" align="center">Distance from Site: ' + dist +
|
|
||||||
(Metric ? ' km' : ' NM') + '</td></tr>';
|
|
||||||
} // End of SiteShow
|
|
||||||
} else {
|
|
||||||
if (SiteShow) {
|
|
||||||
html += '<tr><td colspan="' + columns + '" align="center">Distance from Site: n/a ' +
|
|
||||||
(Metric ? ' km' : ' NM') + '</td></tr>';
|
|
||||||
} else {
|
|
||||||
html += 'n/a</td></tr>';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
html += '</table>';
|
$('#selected_sitedist').text(dist + (Metric ? ' km' : ' NM'));
|
||||||
|
} else {
|
||||||
document.getElementById('plane_detail').innerHTML = html;
|
$('#selected_sitedist').text("n/a");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function trackShortName(track) {
|
function trackShortName(track) {
|
||||||
var trackIndex = Math.floor((track+22.5) / 45) % 8;
|
var trackIndex = Math.floor((360 + track % 360 + 22.5) / 45) % 8;
|
||||||
if (trackIndex < 0)
|
|
||||||
return "n/a";
|
|
||||||
return ["N","NE","E","SE","S","SW","W","NW"][trackIndex];
|
return ["N","NE","E","SE","S","SW","W","NW"][trackIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
function trackLongName(track) {
|
function trackLongName(track) {
|
||||||
var trackIndex = Math.floor((track+22.5) / 45);
|
var trackIndex = Math.floor((360 + track % 360 + 22.5) / 45) % 8;
|
||||||
if ((trackIndex < 0) || (trackIndex >= 8))
|
|
||||||
return "n/a";
|
|
||||||
return ["North","Northeast","East","Southeast","South","Southwest","West","Northwest"][trackIndex];
|
return ["North","Northeast","East","Southeast","South","Southwest","West","Northwest"][trackIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refeshes the larger table of all the planes
|
// Refeshes the larger table of all the planes
|
||||||
|
|
||||||
function refreshTableInfo() {
|
function format_altitude(alt) {
|
||||||
var html = '<table id="tableinfo" width="100%">';
|
if (alt === null)
|
||||||
html += '<thead style="background-color: #BBBBBB; cursor: pointer;">';
|
return "";
|
||||||
html += '<td id="icao" onclick="sortBy(\'icao\',false);">ICAO</td>';
|
else if (alt === "ground")
|
||||||
html += '<td id="flight" onclick="sortBy(\'flight\',false);">Flight</td>';
|
return "ground";
|
||||||
html += '<td id="squawk" onclick="sortBy(\'squawk\',false);" align="right">Squawk</td>';
|
else if (Metric)
|
||||||
html += '<td id="altitude" onclick="sortBy(\'altitude\',true);" align="right">Altitude</td>';
|
return Math.round(alt / 3.2828);
|
||||||
html += '<td id="speed" onclick="sortBy(\'speed\',true);" align="right">Speed</td>';
|
else
|
||||||
// Add distance column header to table if site coordinates are provided
|
return Math.round(alt);
|
||||||
if (SiteShow && (typeof SiteLat !== 'undefined' || typeof SiteLon !== 'undefined')) {
|
|
||||||
html += '<td id="distance" onclick="sortBy(\'distance\',true);" align="right">Distance</td>';
|
|
||||||
}
|
}
|
||||||
html += '<td id="track" onclick="sortBy(\'track\',true);" align="right">Track</td>';
|
|
||||||
html += '<td id="msgs" onclick="sortBy(\'msgs\',true);" align="right">Msgs</td>';
|
|
||||||
html += '<td id="seen" onclick="sortBy(\'seen\',true);" align="right">Seen</td></thead><tbody>';
|
|
||||||
|
|
||||||
for (var tablep in Planes) {
|
function format_speed(speed) {
|
||||||
var tableplane = Planes[tablep]
|
if (speed === null)
|
||||||
if (!tableplane.reapable) {
|
return "";
|
||||||
var specialStyle = "";
|
else if (Metric)
|
||||||
// Is this the plane we selected?
|
return Math.round(speed * 1.852);
|
||||||
if (tableplane.icao == SelectedPlane) {
|
else
|
||||||
specialStyle += " selected";
|
return Math.round(speed);
|
||||||
}
|
}
|
||||||
// Lets hope we never see this... Aircraft Hijacking
|
|
||||||
if (tableplane.squawk == 7500) {
|
function format_distance(dist) {
|
||||||
specialStyle += " squawk7500";
|
if (Metric) {
|
||||||
|
return (Math.round(dist/100) / 10).toFixed(1);
|
||||||
|
} else {
|
||||||
|
return (Math.round(dist/185.2) / 10).toFixed(1);
|
||||||
}
|
}
|
||||||
// Radio Failure
|
|
||||||
if (tableplane.squawk == 7600) {
|
|
||||||
specialStyle += " squawk7600";
|
|
||||||
}
|
|
||||||
// Emergancy
|
|
||||||
if (tableplane.squawk == 7700) {
|
|
||||||
specialStyle += " squawk7700";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function refreshTableInfo() {
|
||||||
|
var show_squawk_warning = false;
|
||||||
|
|
||||||
|
TrackedAircraft = 0
|
||||||
|
TrackedAircraftPositions = 0
|
||||||
|
|
||||||
|
for (var i = 0; i < PlanesOrdered.length; ++i) {
|
||||||
|
var tableplane = PlanesOrdered[i];
|
||||||
|
if (tableplane.reapable) {
|
||||||
|
tableplane.tr.className = "hidden";
|
||||||
|
} else {
|
||||||
|
TrackedAircraft++;
|
||||||
|
|
||||||
|
var classes = "plane_table_row";
|
||||||
|
|
||||||
if (tableplane.latitude !== null)
|
if (tableplane.latitude !== null)
|
||||||
html += '<tr class="plane_table_row vPosition' + specialStyle + '">';
|
classes += " vPosition";
|
||||||
else
|
if (tableplane.icao == SelectedPlane)
|
||||||
html += '<tr class="plane_table_row ' + specialStyle + '">';
|
classes += " selected";
|
||||||
|
|
||||||
html += '<td>' + tableplane.icao + '</td>';
|
if (tableplane.squawk in EmergencySquawks) {
|
||||||
|
classes += ' squawk' + tableplane.squawk;
|
||||||
|
show_squawk_warning = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (tableplane.flight !== null)
|
tableplane.tr.className = classes;
|
||||||
html += '<td>' + tableplane.flight + '</td>';
|
// ICAO doesn't change
|
||||||
else
|
tableplane.tr.cells[1].textContent = (tableplane.flight !== null ? tableplane.flight : "");
|
||||||
html += '<td></td>';
|
tableplane.tr.cells[2].textContent = (tableplane.squawk !== null ? tableplane.squawk : "");
|
||||||
|
tableplane.tr.cells[3].textContent = format_altitude(tableplane.altitude);
|
||||||
|
tableplane.tr.cells[4].textContent = format_speed(tableplane.speed);
|
||||||
|
|
||||||
if (tableplane.squawk !== null)
|
if (tableplane.latitude !== null)
|
||||||
html += '<td align="right">' + tableplane.squawk + '</td>';
|
++TrackedAircraftPositions;
|
||||||
else
|
|
||||||
html += '<td align="right"></td>';
|
|
||||||
|
|
||||||
if (tableplane.altitude === null)
|
|
||||||
html += '<td align="right"> </td>';
|
|
||||||
else if (tableplane.altitude === "ground")
|
|
||||||
html += '<td align="right">ground</td>';
|
|
||||||
else if (Metric)
|
|
||||||
html += '<td align="right">' + Math.round(tableplane.altitude / 3.2828) + '</td>';
|
|
||||||
else
|
|
||||||
html += '<td align="right">' + tableplane.altitude + '</td>';
|
|
||||||
|
|
||||||
if (tableplane.speed === null)
|
|
||||||
html += '<td align="right"> </td>';
|
|
||||||
else if (Metric)
|
|
||||||
html += '<td align="right">' + Math.round(tableplane.speed * 1.852) + '</td>';
|
|
||||||
else
|
|
||||||
html += '<td align="right">' + tableplane.speed + '</td>';
|
|
||||||
|
|
||||||
// Add distance column to table if site coordinates are provided
|
// Add distance column to table if site coordinates are provided
|
||||||
if (SiteShow && (typeof SiteLat !== 'undefined' || typeof SiteLon !== 'undefined')) {
|
if (SitePosition !== null && tableplane.latitude !== null) {
|
||||||
html += '<td align="right">';
|
|
||||||
if (tableplane.latitude !== null) {
|
|
||||||
var siteLatLon = new google.maps.LatLng(SiteLat, SiteLon);
|
|
||||||
var planeLatLon = new google.maps.LatLng(tableplane.latitude, tableplane.longitude);
|
var planeLatLon = new google.maps.LatLng(tableplane.latitude, tableplane.longitude);
|
||||||
var dist = google.maps.geometry.spherical.computeDistanceBetween (siteLatLon, planeLatLon);
|
var dist = google.maps.geometry.spherical.computeDistanceBetween (SitePosition, planeLatLon);
|
||||||
if (Metric) {
|
tableplane.tr.cells[5].textContent = format_distance(dist);
|
||||||
dist /= 1000;
|
tableplane.sitedist = dist;
|
||||||
} else {
|
} else {
|
||||||
dist /= 1852;
|
tableplane.tr.cells[5].textContent = "";
|
||||||
}
|
|
||||||
dist = (Math.round((dist)*10)/10).toFixed(1);
|
|
||||||
html += dist;
|
|
||||||
}
|
|
||||||
html += '</td>';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
html += '<td align="right">';
|
tableplane.tr.cells[6].textContent = (tableplane.track !== null ? tableplane.track : "");
|
||||||
if (tableplane.track !== null)
|
tableplane.tr.cells[7].textContent = tableplane.messages;
|
||||||
html += tableplane.track;
|
tableplane.tr.cells[8].textContent = tableplane.seen;
|
||||||
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;
|
if (show_squawk_warning) {
|
||||||
|
$("#SpecialSquawkWarning").removeClass('hidden');
|
||||||
if (SpecialSquawk) {
|
|
||||||
$('#SpecialSquawkWarning').css('display', 'inline');
|
|
||||||
} else {
|
} else {
|
||||||
$('#SpecialSquawkWarning').css('display', 'none');
|
$("#SpecialSquawkWarning").addClass('hidden');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Click event for table
|
|
||||||
$('#planes_table').find('tr').click( function(){
|
|
||||||
var hex = $(this).find('td:first').text();
|
|
||||||
if (hex != "ICAO") {
|
|
||||||
selectPlaneByHex(hex);
|
|
||||||
refreshTableInfo();
|
|
||||||
refreshSelected();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
resortTable();
|
resortTable();
|
||||||
}
|
}
|
||||||
|
|
||||||
function sortBy(colName,numeric) {
|
//
|
||||||
var header_cells = document.getElementById('tableinfo').tHead.rows[0].cells;
|
// ---- table sorting ----
|
||||||
for (var i = 0; i < header_cells.length; ++i) {
|
//
|
||||||
if (header_cells[i].id === colName) {
|
|
||||||
if (i == sortColumn)
|
function compareAlpha(xa,xo,ya,yo) {
|
||||||
|
if (xa === ya)
|
||||||
|
return xo - yo;
|
||||||
|
if (xa === null)
|
||||||
|
return 1;
|
||||||
|
if (ya === null)
|
||||||
|
return -1;
|
||||||
|
if (xa < ya)
|
||||||
|
return -1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function compareNumeric(xf,xo,yf,yo) {
|
||||||
|
if (xf === null) xf = 1e9;
|
||||||
|
if (yf === null) yf = 1e9;
|
||||||
|
|
||||||
|
if (Math.abs(xf - yf) < 1e-9)
|
||||||
|
return xo - yo;
|
||||||
|
|
||||||
|
return xf - yf;
|
||||||
|
}
|
||||||
|
|
||||||
|
function compareAltitude(xf,xo,yf,yo) {
|
||||||
|
if (xf === null) xf = 1e9;
|
||||||
|
else if (xf === "ground") xf = -1e9;
|
||||||
|
if (yf === null) yf = 1e9;
|
||||||
|
else if (yf === "ground") yf = -1e9;
|
||||||
|
|
||||||
|
if (Math.abs(xf - yf) < 1e-9)
|
||||||
|
return xo - yo;
|
||||||
|
|
||||||
|
return xf - yf;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sortByICAO() { sortBy('icao', function(x,y){return compareAlpha(x.icao, x.sort_pos, y.icao, y.sort_pos)}); }
|
||||||
|
function sortByFlight() { sortBy('flight', function(x,y){return compareAlpha(x.flight, x.sort_pos, y.flight, y.sort_pos)}); }
|
||||||
|
function sortBySquawk() { sortBy('squawk', function(x,y){return compareAlpha(x.squawk, x.sort_pos, y.squawk, y.sort_pos)}); }
|
||||||
|
function sortByAltitude() { sortBy('altitude',function(x,y){return compareAltitude(x.altitude, x.sort_pos, y.altitude, y.sort_pos)}); }
|
||||||
|
function sortBySpeed() { sortBy('speed', function(x,y){return compareNumeric(x.speed, x.sort_pos, y.speed, y.sort_pos)}); }
|
||||||
|
function sortByDistance() { sortBy('sitedist',function(x,y){return compareNumeric(x.sitedist, x.sort_pos, y.sitedist, y.sort_pos)}); }
|
||||||
|
function sortByTrack() { sortBy('track', function(x,y){return compareNumeric(x.track, x.sort_pos, y.track, y.sort_pos)}); }
|
||||||
|
function sortByMsgs() { sortBy('msgs', function(x,y){return compareNumeric(x.msgs, x.sort_pos, y.msgs, y.sort_pos)}); }
|
||||||
|
function sortBySeen() { sortBy('seen', function(x,y){return compareNumeric(x.seen, x.sort_pos, y.seen, y.sort_pos)}); }
|
||||||
|
|
||||||
|
sortId = '';
|
||||||
|
sortByFunc = null;
|
||||||
|
sortAscending = true;
|
||||||
|
|
||||||
|
function resortTable() {
|
||||||
|
// make it a stable sort
|
||||||
|
for (var i = 0; i < PlanesOrdered.length; ++i) {
|
||||||
|
PlanesOrdered[i].sort_pos = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
PlanesOrdered.sort(sortByFunc);
|
||||||
|
|
||||||
|
var tbody = document.getElementById('tableinfo').tBodies[0];
|
||||||
|
for (var i = 0; i < PlanesOrdered.length; ++i) {
|
||||||
|
tbody.appendChild(PlanesOrdered[i].tr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function sortBy(id,sortfunc) {
|
||||||
|
if (id === sortId) {
|
||||||
sortAscending = !sortAscending;
|
sortAscending = !sortAscending;
|
||||||
else {
|
} else {
|
||||||
sortColumn = i;
|
|
||||||
sortNumeric = numeric;
|
|
||||||
sortAscending = true;
|
sortAscending = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sortAscending)
|
||||||
|
sortByFunc = sortfunc;
|
||||||
|
else
|
||||||
|
sortByFunc = function(x,y){return sortfunc(y,x);}
|
||||||
|
|
||||||
|
sortId = id;
|
||||||
resortTable();
|
resortTable();
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
console.warn("column not found: " + colName);
|
|
||||||
}
|
|
||||||
|
|
||||||
function resortTable() {
|
|
||||||
sortTable('tableinfo', sortColumn, sortAscending, sortNumeric);
|
|
||||||
}
|
|
||||||
|
|
||||||
function sortTable(tableId, col, asc, numeric) {
|
|
||||||
//retrieve passed table element
|
|
||||||
var oTbl=document.getElementById(tableId).tBodies[0];
|
|
||||||
var aStore=[];
|
|
||||||
|
|
||||||
//loop through the rows, storing each one inro aStore
|
|
||||||
for (var i=0; i < oTbl.rows.length; ++i){
|
|
||||||
var oRow=oTbl.rows[i];
|
|
||||||
var sortKey;
|
|
||||||
if (numeric) {
|
|
||||||
sortKey = parseFloat(oRow.cells[col].textContent||oRow.cells[col].innerText);
|
|
||||||
if (isNaN(sortKey)) {
|
|
||||||
sortKey = -999999;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sortKey = String(oRow.cells[col].textContent||oRow.cells[col].innerText);
|
|
||||||
}
|
|
||||||
aStore.push([sortKey,oRow]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (numeric) { //numerical sort
|
|
||||||
aStore.sort(function(x,y){ return sortAscending ? x[0]-y[0] : y[0]-x[0]; });
|
|
||||||
} else { //alpha sort
|
|
||||||
aStore.sort();
|
|
||||||
if (!sortAscending) {
|
|
||||||
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]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectPlaneByHex(hex) {
|
function selectPlaneByHex(hex) {
|
||||||
|
//console.log("select: " + hex);
|
||||||
// If SelectedPlane has something in it, clear out the selected
|
// If SelectedPlane has something in it, clear out the selected
|
||||||
if (SelectedPlane != null) {
|
if (SelectedPlane != null) {
|
||||||
Planes[SelectedPlane].is_selected = false;
|
Planes[SelectedPlane].is_selected = false;
|
||||||
|
@ -573,6 +568,7 @@ function selectPlaneByHex(hex) {
|
||||||
if (Planes[SelectedPlane].marker) {
|
if (Planes[SelectedPlane].marker) {
|
||||||
Planes[SelectedPlane].marker.setIcon(Planes[SelectedPlane].funcGetIcon());
|
Planes[SelectedPlane].marker.setIcon(Planes[SelectedPlane].funcGetIcon());
|
||||||
}
|
}
|
||||||
|
Planes[SelectedPlane].tr.classList.remove("selected");
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we are clicking the same plane, we are deselected it.
|
// If we are clicking the same plane, we are deselected it.
|
||||||
|
@ -585,11 +581,12 @@ function selectPlaneByHex(hex) {
|
||||||
Planes[SelectedPlane].funcUpdateLines();
|
Planes[SelectedPlane].funcUpdateLines();
|
||||||
Planes[SelectedPlane].marker.setIcon(Planes[SelectedPlane].funcGetIcon());
|
Planes[SelectedPlane].marker.setIcon(Planes[SelectedPlane].funcGetIcon());
|
||||||
}
|
}
|
||||||
|
Planes[SelectedPlane].tr.classList.add("selected");
|
||||||
} else {
|
} else {
|
||||||
SelectedPlane = null;
|
SelectedPlane = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
refreshSelected();
|
refreshSelected();
|
||||||
refreshTableInfo();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetMap() {
|
function resetMap() {
|
||||||
|
|
|
@ -9,7 +9,7 @@ div#sidebar_container { float: left; width: 410px; margin-left: -410px; height:
|
||||||
|
|
||||||
div#SpecialSquawkWarning { position: absolute; bottom: 25px; right: 430px; border: 2px solid red;
|
div#SpecialSquawkWarning { position: absolute; bottom: 25px; right: 430px; border: 2px solid red;
|
||||||
background-color: #FFFFA3; opacity: 0.75; filter:alpha(opacity=75); padding: 5px;
|
background-color: #FFFFA3; opacity: 0.75; filter:alpha(opacity=75); padding: 5px;
|
||||||
display: none; text-align: center; }
|
text-align: center; }
|
||||||
|
|
||||||
table#optionsTabs { width: 100%; font-size: small; font-family: monospace; background-color: #ddd;
|
table#optionsTabs { width: 100%; font-size: small; font-family: monospace; background-color: #ddd;
|
||||||
border: 1px; border-color: #000000;}
|
border: 1px; border-color: #000000;}
|
||||||
|
@ -22,11 +22,13 @@ table#optionsTabs { width: 100%; font-size: small; font-family: monospace; backg
|
||||||
.squawk7700 { font-weight: bold; background-color: #ffff00; }
|
.squawk7700 { font-weight: bold; background-color: #ffff00; }
|
||||||
.selected { background-color: #dddddd; }
|
.selected { background-color: #dddddd; }
|
||||||
.plane_table_row { cursor: pointer; }
|
.plane_table_row { cursor: pointer; }
|
||||||
|
.hidden { display: none; }
|
||||||
|
|
||||||
#selectedinfotitle { font-size: larger; }
|
.infoblock_heading { font-size: larger; }
|
||||||
#selectedinfo { font-size: small; }
|
.infoblock_heading a { text-decoration: none; color: blue; font-size: x-small;}
|
||||||
#selectedinfo a { text-decoration: none; color: blue; font-size: x-small;}
|
.infoblock_body { font-size: small; }
|
||||||
#selectedinfo.dim { opacity: 0.3; filter:alpha(opacity=30); /* For IE8 and earlier */ }
|
|
||||||
|
.dim { opacity: 0.3; filter:alpha(opacity=30); /* For IE8 and earlier */ }
|
||||||
|
|
||||||
.pointer { cursor: pointer; }
|
.pointer { cursor: pointer; }
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue