Make PlaneObject a class.
Rearrange internal storage of positions. Maintain sitedist within PlaneObject, not externally. Clean up speed/dist/etc formatting. Show both metric & imperial values in the plane detail infobox.
This commit is contained in:
parent
58e5485c2a
commit
29509d9633
|
@ -117,7 +117,7 @@
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr class="infoblock_body">
|
<tr class="infoblock_body">
|
||||||
<td colspan="2">Lat/Long: <span id="selected_position">n/a</span></td>
|
<td colspan="2">Position: <span id="selected_position">n/a</span></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr class="infoblock_body">
|
<tr class="infoblock_body">
|
||||||
|
|
|
@ -28,333 +28,329 @@ var PlaneSvg = "M 0,0 " +
|
||||||
"-2.858644 -0.145909,-5.208974 -0.209316,-5.222958 -0.06341,-0.01399 -0.974464," +
|
"-2.858644 -0.145909,-5.208974 -0.209316,-5.222958 -0.06341,-0.01399 -0.974464," +
|
||||||
"-0.0493 -2.024551,-0.07845 L 23.247235,38.61921 18.831373,39.8906 C 4.9432155," +
|
"-0.0493 -2.024551,-0.07845 L 23.247235,38.61921 18.831373,39.8906 C 4.9432155," +
|
||||||
"43.88916 4.2929558,44.057819 3.4954426,43.86823 2.7487826,43.690732 2.2007966," +
|
"43.88916 4.2929558,44.057819 3.4954426,43.86823 2.7487826,43.690732 2.2007966," +
|
||||||
"42.916622 1.9565564,41.694305 z"
|
"42.916622 1.9565564,41.694305 z";
|
||||||
|
|
||||||
|
function PlaneObject(icao) {
|
||||||
var planeObject = {
|
|
||||||
// Basic location information
|
|
||||||
altitude : null,
|
|
||||||
speed : null,
|
|
||||||
track : null,
|
|
||||||
latitude : null,
|
|
||||||
longitude : null,
|
|
||||||
|
|
||||||
// Info about the plane
|
// Info about the plane
|
||||||
flight : null,
|
this.icao = icao;
|
||||||
squawk : null,
|
this.flight = null;
|
||||||
icao : null,
|
this.squawk = null;
|
||||||
is_selected : false,
|
this.selected = false;
|
||||||
|
|
||||||
|
// Basic location information
|
||||||
|
this.altitude = null;
|
||||||
|
this.speed = null;
|
||||||
|
this.track = null;
|
||||||
|
this.position = null;
|
||||||
|
this.sitedist = null;
|
||||||
|
|
||||||
// Data packet numbers
|
// Data packet numbers
|
||||||
messages : null,
|
this.messages = null;
|
||||||
|
|
||||||
// Track history as a series of line segments
|
// Track history as a series of line segments
|
||||||
track_linesegs : [],
|
this.track_linesegs = [];
|
||||||
|
this.history_size = 0;
|
||||||
|
|
||||||
// When was this last updated (receiver timestamp)
|
// When was this last updated (receiver timestamp)
|
||||||
last_message_time : null,
|
this.last_message_time = null;
|
||||||
last_position_time : null,
|
this.last_position_time = null;
|
||||||
|
|
||||||
// When was this last updated (seconds before last update)
|
// When was this last updated (seconds before last update)
|
||||||
seen : null,
|
this.seen = null;
|
||||||
seen_pos : null,
|
this.seen_pos = null;
|
||||||
|
|
||||||
history_size : 0,
|
// Display info
|
||||||
visible : true,
|
this.visible = true;
|
||||||
|
this.marker = null;
|
||||||
|
this.icon = { strokeWeight: 1,
|
||||||
|
path: PlaneSvg,
|
||||||
|
scale: 0.4,
|
||||||
|
fillColor: MarkerColor,
|
||||||
|
fillOpacity: 0.9,
|
||||||
|
anchor: new google.maps.Point(32, 32), // Set anchor to middle of plane.
|
||||||
|
rotation: 0 };
|
||||||
|
}
|
||||||
|
|
||||||
// GMap Details
|
// Appends data to the running track so we can get a visual tail on the plane
|
||||||
marker : null,
|
// Only useful for a long running browser session.
|
||||||
icon : {
|
PlaneObject.prototype.updateTrack = function() {
|
||||||
strokeWeight: 1,
|
var here = this.position;
|
||||||
path: PlaneSvg,
|
|
||||||
scale: 0.4,
|
|
||||||
fillColor: MarkerColor,
|
|
||||||
fillOpacity: 0.9,
|
|
||||||
anchor: new google.maps.Point(32, 32), // Set anchor to middle of plane.
|
|
||||||
rotation: 0
|
|
||||||
},
|
|
||||||
|
|
||||||
// Appends data to the running track so we can get a visual tail on the plane
|
if (this.track_linesegs.length == 0) {
|
||||||
// Only useful for a long running browser session.
|
// Brand new track
|
||||||
updateTrack : function() {
|
//console.log(this.icao + " new track");
|
||||||
var here = new google.maps.LatLng(this.latitude, this.longitude);
|
var newseg = { track : new google.maps.MVCArray([here,here]),
|
||||||
if (this.track_linesegs.length == 0) {
|
line : null,
|
||||||
// Brand new track
|
head_update : this.last_position_time,
|
||||||
//console.log(this.icao + " new track");
|
tail_update : this.last_position_time,
|
||||||
var newseg = { track : new google.maps.MVCArray([here,here]),
|
estimated : false,
|
||||||
line : null,
|
ground : (this.altitude === "ground")
|
||||||
head_update : this.last_position_time,
|
};
|
||||||
tail_update : this.last_position_time,
|
this.track_linesegs.push(newseg);
|
||||||
estimated : false,
|
this.history_size += 2;
|
||||||
ground : (this.altitude === "ground")
|
return;
|
||||||
};
|
}
|
||||||
this.track_linesegs.push(newseg);
|
|
||||||
this.history_size += 2;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var lastseg = this.track_linesegs[this.track_linesegs.length - 1];
|
|
||||||
var lastpos = lastseg.track.getAt(lastseg.track.getLength() - 1);
|
|
||||||
var elapsed = (this.last_position_time - lastseg.head_update);
|
|
||||||
|
|
||||||
var new_data = (here !== lastpos);
|
|
||||||
var est_track = (elapsed > 5);
|
|
||||||
var ground_track = (this.altitude === "ground");
|
|
||||||
|
|
||||||
if (!new_data)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (est_track) {
|
|
||||||
if (!lastseg.estimated) {
|
|
||||||
// >5s gap in data, create a new estimated segment
|
|
||||||
//console.log(this.icao + " switching to estimated");
|
|
||||||
this.track_linesegs.push({ track : new google.maps.MVCArray([lastpos, here]),
|
|
||||||
line : null,
|
|
||||||
head_update : this.last_position_time,
|
|
||||||
estimated : true });
|
|
||||||
this.history_size += 2;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
this.history_size++;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lastseg.estimated) {
|
|
||||||
// We are back to good data.
|
|
||||||
//console.log(this.icao + " switching to good track");
|
|
||||||
this.track_linesegs.push({ track : new google.maps.MVCArray([lastpos, here]),
|
|
||||||
line : null,
|
|
||||||
head_update : this.last_position_time,
|
|
||||||
tail_update : this.last_position_time,
|
|
||||||
estimated : false,
|
|
||||||
ground : (this.altitude === "ground") });
|
|
||||||
this.history_size += 2;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
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.track_linesegs.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") });
|
|
||||||
this.history_size += 4;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add more data to the existing track.
|
|
||||||
// We only retain some historical points, at 5+ second intervals,
|
|
||||||
// plus the most recent point
|
|
||||||
if (this.last_position_time - lastseg.tail_update >= 5) {
|
|
||||||
// enough time has elapsed; retain the last point and add a new one
|
|
||||||
//console.log(this.icao + " retain last point");
|
|
||||||
lastseg.track.push(here);
|
|
||||||
lastseg.tail_update = lastseg.head_update;
|
|
||||||
this.history_size ++;
|
|
||||||
} else {
|
|
||||||
// replace the last point with the current position
|
|
||||||
lastseg.track.setAt(lastseg.track.getLength()-1, here);
|
|
||||||
}
|
|
||||||
lastseg.head_update = this.last_position_time;
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
|
|
||||||
// This is to remove the line from the screen if we deselect the plane
|
|
||||||
clearLines : function() {
|
|
||||||
for (var i = 0; i < this.track_linesegs.length; ++i) {
|
|
||||||
var seg = this.track_linesegs[i];
|
|
||||||
if (seg.line !== null) {
|
|
||||||
seg.line.setMap(null);
|
|
||||||
seg.line = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
updateIcon : function() {
|
|
||||||
var col = MarkerColor;
|
|
||||||
|
|
||||||
// If this marker is selected we should make it lighter than the rest.
|
|
||||||
if (this.is_selected)
|
|
||||||
col = SelectedColor;
|
|
||||||
|
|
||||||
// If we have not seen a recent update, change color
|
|
||||||
if (this.seen > 15)
|
|
||||||
col = StaleColor;
|
|
||||||
|
|
||||||
// If the squawk code is one of the international emergency codes,
|
|
||||||
// match the info window alert color.
|
|
||||||
if (this.squawk in SpecialSquawks)
|
|
||||||
col = SpecialSquawks[this.squawk].markerColor;
|
|
||||||
|
|
||||||
var weight = this.is_selected ? 2 : 1;
|
|
||||||
var rotation = (this.track === null ? 0 : this.track);
|
|
||||||
|
|
||||||
if (col === this.icon.fillColor && weight === this.icon.strokeWeight && rotation === this.icon.rotation)
|
|
||||||
return false; // no changes
|
|
||||||
|
|
||||||
this.icon.fillColor = col;
|
|
||||||
this.icon.strokeWeight = weight;
|
|
||||||
this.icon.rotation = rotation;
|
|
||||||
if (this.marker)
|
|
||||||
this.marker.setIcon(this.icon);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
|
|
||||||
// TODO: Trigger actions of a selecting a plane
|
|
||||||
selectPlane : function(){
|
|
||||||
selectPlaneByHex(this.icao);
|
|
||||||
},
|
|
||||||
|
|
||||||
// Update our data
|
|
||||||
updateData : function(receiver_timestamp, data){
|
|
||||||
// Update all of our data
|
|
||||||
this.icao = data.hex;
|
|
||||||
this.messages = data.messages;
|
|
||||||
this.last_message_time = receiver_timestamp - data.seen;
|
|
||||||
|
|
||||||
if (typeof data.altitude !== "undefined")
|
|
||||||
this.altitude = data.altitude;
|
|
||||||
if (typeof data.speed !== "undefined")
|
|
||||||
this.speed = data.speed;
|
|
||||||
if (typeof data.track !== "undefined")
|
|
||||||
this.track = data.track;
|
|
||||||
if (typeof data.lat !== "undefined") {
|
|
||||||
this.latitude = data.lat;
|
|
||||||
this.longitude = data.lon;
|
|
||||||
this.last_position_time = receiver_timestamp - data.seen_pos;
|
|
||||||
}
|
|
||||||
if (typeof data.flight !== "undefined")
|
|
||||||
this.flight = data.flight;
|
|
||||||
if (typeof data.squawk !== "undefined")
|
|
||||||
this.squawk = data.squawk;
|
|
||||||
},
|
|
||||||
|
|
||||||
updateTick : function(receiver_timestamp) {
|
|
||||||
// recompute seen and seen_pos
|
|
||||||
this.seen = receiver_timestamp - this.last_message_time;
|
|
||||||
this.seen_pos = (this.last_position_time === null ? null : receiver_timestamp - this.last_position_time);
|
|
||||||
|
|
||||||
// If no packet in over 58 seconds, clear the plane.
|
|
||||||
if (this.seen > 58) {
|
|
||||||
if (this.visible) {
|
|
||||||
//console.log("hiding " + this.icao);
|
|
||||||
this.clearMarker();
|
|
||||||
this.visible = false;
|
|
||||||
if (SelectedPlane == this.icao)
|
|
||||||
selectPlaneByHex(null);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.visible = true;
|
|
||||||
if (this.latitude !== null) {
|
|
||||||
if (this.updateTrack()) {
|
|
||||||
this.updateLines();
|
|
||||||
this.updateMarker(true);
|
|
||||||
} else {
|
|
||||||
this.updateMarker(false); // didn't move
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
clearMarker: function() {
|
|
||||||
if (this.marker) {
|
|
||||||
this.marker.setMap(null);
|
|
||||||
this.marker = null;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// Update our marker on the map
|
|
||||||
updateMarker: function(moved) {
|
|
||||||
if (!this.visible) {
|
|
||||||
this.clearMarker();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.marker) {
|
|
||||||
if (moved)
|
|
||||||
this.marker.setPosition(new google.maps.LatLng(this.latitude, this.longitude));
|
|
||||||
this.updateIcon();
|
|
||||||
} else {
|
|
||||||
this.updateIcon();
|
|
||||||
this.marker = new google.maps.Marker({
|
|
||||||
position: new google.maps.LatLng(this.latitude, this.longitude),
|
|
||||||
map: GoogleMap,
|
|
||||||
icon: this.icon,
|
|
||||||
visible: true
|
|
||||||
});
|
|
||||||
|
|
||||||
// This is so we can match icao address
|
|
||||||
this.marker.icao = this.icao;
|
|
||||||
|
|
||||||
// Trap clicks for this marker.
|
|
||||||
google.maps.event.addListener(this.marker, 'click', this.selectPlane);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setting the marker title
|
|
||||||
if (this.flight === null || this.flight.length == 0) {
|
|
||||||
this.marker.setTitle(this.hex);
|
|
||||||
} else {
|
|
||||||
this.marker.setTitle(this.flight+' ('+this.icao+')');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// Update our planes tail line,
|
var lastseg = this.track_linesegs[this.track_linesegs.length - 1];
|
||||||
updateLines: function() {
|
var lastpos = lastseg.track.getAt(lastseg.track.getLength() - 1);
|
||||||
if (!this.is_selected)
|
var elapsed = (this.last_position_time - lastseg.head_update);
|
||||||
return;
|
|
||||||
|
var new_data = (here !== lastpos);
|
||||||
for (var i = 0; i < this.track_linesegs.length; ++i) {
|
var est_track = (elapsed > 5);
|
||||||
var seg = this.track_linesegs[i];
|
var ground_track = (this.altitude === "ground");
|
||||||
if (seg.line === null) {
|
|
||||||
// console.log("create line for seg " + i + " with " + seg.track.getLength() + " points" + (seg.estimated ? " (estimated)" : ""));
|
if (!new_data)
|
||||||
// for (var j = 0; j < seg.track.getLength(); j++) {
|
return false;
|
||||||
// console.log(" point " + j + " at " + seg.track.getAt(j).lat() + "," + seg.track.getAt(j).lng());
|
|
||||||
// }
|
if (est_track) {
|
||||||
|
if (!lastseg.estimated) {
|
||||||
if (seg.estimated) {
|
// >5s gap in data, create a new estimated segment
|
||||||
var lineSymbol = {
|
//console.log(this.icao + " switching to estimated");
|
||||||
path: 'M 0,-1 0,1',
|
this.track_linesegs.push({ track : new google.maps.MVCArray([lastpos, here]),
|
||||||
strokeOpacity : 1,
|
line : null,
|
||||||
strokeColor : '#804040',
|
head_update : this.last_position_time,
|
||||||
strokeWeight : 2,
|
estimated : true });
|
||||||
scale: 2
|
this.history_size += 2;
|
||||||
};
|
return true;
|
||||||
|
|
||||||
seg.line = new google.maps.Polyline({
|
|
||||||
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,
|
|
||||||
strokeColor: (seg.ground ? '#408040' : '#000000'),
|
|
||||||
strokeWeight: 3,
|
|
||||||
map: GoogleMap });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
// 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;
|
||||||
|
this.history_size++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastseg.estimated) {
|
||||||
|
// We are back to good data.
|
||||||
|
//console.log(this.icao + " switching to good track");
|
||||||
|
this.track_linesegs.push({ track : new google.maps.MVCArray([lastpos, here]),
|
||||||
|
line : null,
|
||||||
|
head_update : this.last_position_time,
|
||||||
|
tail_update : this.last_position_time,
|
||||||
|
estimated : false,
|
||||||
|
ground : (this.altitude === "ground") });
|
||||||
|
this.history_size += 2;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
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.track_linesegs.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") });
|
||||||
|
this.history_size += 4;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add more data to the existing track.
|
||||||
|
// We only retain some historical points, at 5+ second intervals,
|
||||||
|
// plus the most recent point
|
||||||
|
if (this.last_position_time - lastseg.tail_update >= 5) {
|
||||||
|
// enough time has elapsed; retain the last point and add a new one
|
||||||
|
//console.log(this.icao + " retain last point");
|
||||||
|
lastseg.track.push(here);
|
||||||
|
lastseg.tail_update = lastseg.head_update;
|
||||||
|
this.history_size ++;
|
||||||
|
} else {
|
||||||
|
// replace the last point with the current position
|
||||||
|
lastseg.track.setAt(lastseg.track.getLength()-1, here);
|
||||||
|
}
|
||||||
|
lastseg.head_update = this.last_position_time;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
destroy : function() {
|
// This is to remove the line from the screen if we deselect the plane
|
||||||
this.clearLines();
|
PlaneObject.prototype.clearLines = function() {
|
||||||
this.clearMarker();
|
for (var i = 0; i < this.track_linesegs.length; ++i) {
|
||||||
|
var seg = this.track_linesegs[i];
|
||||||
|
if (seg.line !== null) {
|
||||||
|
seg.line.setMap(null);
|
||||||
|
seg.line = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
PlaneObject.prototype.updateIcon = function() {
|
||||||
|
var col = MarkerColor;
|
||||||
|
|
||||||
|
// If this marker is selected we should make it lighter than the rest.
|
||||||
|
if (this.is_selected)
|
||||||
|
col = SelectedColor;
|
||||||
|
|
||||||
|
// If we have not seen a recent update, change color
|
||||||
|
if (this.seen > 15)
|
||||||
|
col = StaleColor;
|
||||||
|
|
||||||
|
// If the squawk code is one of the international emergency codes,
|
||||||
|
// match the info window alert color.
|
||||||
|
if (this.squawk in SpecialSquawks)
|
||||||
|
col = SpecialSquawks[this.squawk].markerColor;
|
||||||
|
|
||||||
|
var weight = this.is_selected ? 2 : 1;
|
||||||
|
var rotation = (this.track === null ? 0 : this.track);
|
||||||
|
|
||||||
|
if (col === this.icon.fillColor && weight === this.icon.strokeWeight && rotation === this.icon.rotation)
|
||||||
|
return false; // no changes
|
||||||
|
|
||||||
|
this.icon.fillColor = col;
|
||||||
|
this.icon.strokeWeight = weight;
|
||||||
|
this.icon.rotation = rotation;
|
||||||
|
if (this.marker)
|
||||||
|
this.marker.setIcon(this.icon);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update our data
|
||||||
|
PlaneObject.prototype.updateData = function(receiver_timestamp, data) {
|
||||||
|
// Update all of our data
|
||||||
|
this.icao = data.hex;
|
||||||
|
this.messages = data.messages;
|
||||||
|
this.last_message_time = receiver_timestamp - data.seen;
|
||||||
|
|
||||||
|
if (typeof data.altitude !== "undefined")
|
||||||
|
this.altitude = data.altitude;
|
||||||
|
if (typeof data.speed !== "undefined")
|
||||||
|
this.speed = data.speed;
|
||||||
|
if (typeof data.track !== "undefined")
|
||||||
|
this.track = data.track;
|
||||||
|
if (typeof data.lat !== "undefined") {
|
||||||
|
this.position = new google.maps.LatLng(data.lat, data.lon);
|
||||||
|
this.last_position_time = receiver_timestamp - data.seen_pos;
|
||||||
|
|
||||||
|
if (SitePosition !== null) {
|
||||||
|
this.sitedist = google.maps.geometry.spherical.computeDistanceBetween (SitePosition, this.position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (typeof data.flight !== "undefined")
|
||||||
|
this.flight = data.flight;
|
||||||
|
if (typeof data.squawk !== "undefined")
|
||||||
|
this.squawk = data.squawk;
|
||||||
|
};
|
||||||
|
|
||||||
|
PlaneObject.prototype.updateTick = function(receiver_timestamp) {
|
||||||
|
// recompute seen and seen_pos
|
||||||
|
this.seen = receiver_timestamp - this.last_message_time;
|
||||||
|
this.seen_pos = (this.last_position_time === null ? null : receiver_timestamp - this.last_position_time);
|
||||||
|
|
||||||
|
// If no packet in over 58 seconds, clear the plane.
|
||||||
|
if (this.seen > 58) {
|
||||||
|
if (this.visible) {
|
||||||
|
//console.log("hiding " + this.icao);
|
||||||
|
this.clearMarker();
|
||||||
|
this.visible = false;
|
||||||
|
if (SelectedPlane == this.icao)
|
||||||
|
selectPlaneByHex(null);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.visible = true;
|
||||||
|
if (this.position !== null) {
|
||||||
|
if (this.updateTrack()) {
|
||||||
|
this.updateLines();
|
||||||
|
this.updateMarker(true);
|
||||||
|
} else {
|
||||||
|
this.updateMarker(false); // didn't move
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
PlaneObject.prototype.clearMarker = function() {
|
||||||
|
if (this.marker) {
|
||||||
|
this.marker.setMap(null);
|
||||||
|
google.maps.event.clearListeners(this.marker, 'click');
|
||||||
|
this.marker = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update our marker on the map
|
||||||
|
PlaneObject.prototype.updateMarker = function(moved) {
|
||||||
|
if (!this.visible) {
|
||||||
|
this.clearMarker();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.marker) {
|
||||||
|
if (moved)
|
||||||
|
this.marker.setPosition(this.position);
|
||||||
|
this.updateIcon();
|
||||||
|
} else {
|
||||||
|
this.updateIcon();
|
||||||
|
this.marker = new google.maps.Marker({
|
||||||
|
position: this.position,
|
||||||
|
map: GoogleMap,
|
||||||
|
icon: this.icon,
|
||||||
|
visible: true
|
||||||
|
});
|
||||||
|
|
||||||
|
// This is so we can match icao address
|
||||||
|
this.marker.icao = this.icao;
|
||||||
|
|
||||||
|
// Trap clicks for this marker.
|
||||||
|
google.maps.event.addListener(this.marker, 'click', selectPlaneByHex.bind(undefined,this.icao));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setting the marker title
|
||||||
|
if (this.flight === null || this.flight.length == 0) {
|
||||||
|
this.marker.setTitle(this.hex);
|
||||||
|
} else {
|
||||||
|
this.marker.setTitle(this.flight+' ('+this.icao+')');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update our planes tail line,
|
||||||
|
PlaneObject.prototype.updateLines = function() {
|
||||||
|
if (!this.is_selected)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (var i = 0; i < this.track_linesegs.length; ++i) {
|
||||||
|
var seg = this.track_linesegs[i];
|
||||||
|
if (seg.line === null) {
|
||||||
|
// console.log("create line for seg " + i + " with " + seg.track.getLength() + " points" + (seg.estimated ? " (estimated)" : ""));
|
||||||
|
// for (var j = 0; j < seg.track.getLength(); j++) {
|
||||||
|
// 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({
|
||||||
|
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,
|
||||||
|
strokeColor: (seg.ground ? '#408040' : '#000000'),
|
||||||
|
strokeWeight: 3,
|
||||||
|
map: GoogleMap });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
PlaneObject.prototype.destroy = function() {
|
||||||
|
this.clearLines();
|
||||||
|
this.clearMarker();
|
||||||
|
};
|
||||||
|
|
|
@ -39,12 +39,10 @@ function fetchData() {
|
||||||
if (Planes[hex]) {
|
if (Planes[hex]) {
|
||||||
plane = Planes[hex];
|
plane = Planes[hex];
|
||||||
} else {
|
} else {
|
||||||
plane = jQuery.extend(true, {}, planeObject);
|
plane = new PlaneObject(hex);
|
||||||
|
|
||||||
plane.tr = PlaneRowTemplate.cloneNode(true);
|
plane.tr = PlaneRowTemplate.cloneNode(true);
|
||||||
plane.tr.cells[0].textContent = hex; // this won't change
|
plane.tr.cells[0].textContent = hex; // this won't change
|
||||||
plane.tr.addEventListener('click', $.proxy(plane.selectPlane, plane));
|
plane.tr.addEventListener('click', selectPlaneByHex.bind(undefined,hex));
|
||||||
plane.sitedist = null;
|
|
||||||
|
|
||||||
Planes[hex] = plane;
|
Planes[hex] = plane;
|
||||||
PlanesOrdered.push(plane);
|
PlanesOrdered.push(plane);
|
||||||
|
@ -282,6 +280,98 @@ function reaper() {
|
||||||
refreshSelected();
|
refreshSelected();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// formatting helpers
|
||||||
|
//
|
||||||
|
|
||||||
|
var TrackDirections = ["North","Northeast","East","Southeast","South","Southwest","West","Northwest"];
|
||||||
|
|
||||||
|
// track in degrees (0..359)
|
||||||
|
function format_track_brief(track) {
|
||||||
|
return Math.round(track);
|
||||||
|
}
|
||||||
|
|
||||||
|
// track in degrees (0..359)
|
||||||
|
function format_track_long(track) {
|
||||||
|
var trackDir = Math.floor((360 + track % 360 + 22.5) / 45) % 8;
|
||||||
|
return Math.round(track) + "\u00b0 (" + TrackDirections[trackDir] + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
// alt in ft
|
||||||
|
function format_altitude_brief(alt) {
|
||||||
|
if (alt === null)
|
||||||
|
return "";
|
||||||
|
if (alt === "ground")
|
||||||
|
return "ground";
|
||||||
|
|
||||||
|
if (Metric)
|
||||||
|
return Math.round(alt / 3.2828);
|
||||||
|
else
|
||||||
|
return Math.round(alt);
|
||||||
|
}
|
||||||
|
|
||||||
|
// alt in ft
|
||||||
|
function format_altitude_long(alt) {
|
||||||
|
if (alt === null)
|
||||||
|
return "n/a";
|
||||||
|
if (alt === "ground")
|
||||||
|
return "on ground";
|
||||||
|
|
||||||
|
if (Metric)
|
||||||
|
return Math.round(alt / 3.2828) + " m / " + Math.round(alt) + " ft";
|
||||||
|
else
|
||||||
|
return Math.round(alt) + " ft / " + Math.round(alt / 3.2828) + " m";
|
||||||
|
}
|
||||||
|
|
||||||
|
// speed in kts
|
||||||
|
function format_speed_brief(speed) {
|
||||||
|
if (speed === null)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
if (Metric)
|
||||||
|
return Math.round(speed * 1.852);
|
||||||
|
else
|
||||||
|
return Math.round(speed);
|
||||||
|
}
|
||||||
|
|
||||||
|
// speed in kts
|
||||||
|
function format_speed_long(speed) {
|
||||||
|
if (speed === null)
|
||||||
|
return "n/a";
|
||||||
|
|
||||||
|
if (Metric)
|
||||||
|
return Math.round(speed * 1.852) + " km/h / " + Math.round(speed) + " kt";
|
||||||
|
else
|
||||||
|
return Math.round(speed) + " kt / " + Math.round(speed * 1.852) + " km/h";
|
||||||
|
}
|
||||||
|
|
||||||
|
// dist in metres
|
||||||
|
function format_distance_brief(dist) {
|
||||||
|
if (dist === null)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
if (Metric)
|
||||||
|
return (dist/1000).toFixed(1);
|
||||||
|
else
|
||||||
|
return (dist/1852).toFixed(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// dist in metres
|
||||||
|
function format_distance_long(dist) {
|
||||||
|
if (dist === null)
|
||||||
|
return "n/a";
|
||||||
|
|
||||||
|
if (Metric)
|
||||||
|
return (dist/1000).toFixed(1) + " km / " + (dist/1852).toFixed(1) + " NM";
|
||||||
|
else
|
||||||
|
return (dist/1852).toFixed(1) + " NM / " + (dist/1000).toFixed(1) + " km";
|
||||||
|
}
|
||||||
|
|
||||||
|
// p as a LatLng
|
||||||
|
function format_latlng(p) {
|
||||||
|
return p.lat().toFixed(5) + "\u00b0, " + p.lng().toFixed(5) + "\u00b0";
|
||||||
|
}
|
||||||
|
|
||||||
// Refresh the detail window about the plane
|
// Refresh the detail window about the plane
|
||||||
function refreshSelected() {
|
function refreshSelected() {
|
||||||
var selected = false;
|
var selected = false;
|
||||||
|
@ -321,14 +411,7 @@ function refreshSelected() {
|
||||||
emerg.className = 'hidden';
|
emerg.className = 'hidden';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selected.altitude === null)
|
$("#selected_altitude").text(format_altitude_long(selected.altitude));
|
||||||
$("#selected_altitude").text("n/a");
|
|
||||||
else if (selected.altitude === "ground")
|
|
||||||
$("#selected_altitude").text("on ground");
|
|
||||||
else if (Metric)
|
|
||||||
$("#selected_altitude").text(Math.round(selected.altitude / 3.2828) + ' m');
|
|
||||||
else
|
|
||||||
$("#selected_altitude").text(Math.round(selected.altitude) + ' ft');
|
|
||||||
|
|
||||||
if (selected.squawk === null || selected.squawk === '0000') {
|
if (selected.squawk === null || selected.squawk === '0000') {
|
||||||
$('#selected_squawk').text('n/a');
|
$('#selected_squawk').text('n/a');
|
||||||
|
@ -336,21 +419,9 @@ function refreshSelected() {
|
||||||
$('#selected_squawk').text(selected.squawk);
|
$('#selected_squawk').text(selected.squawk);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selected.speed === null) {
|
$('#selected_speed').text(format_speed_long(selected.speed));
|
||||||
$('#selected_speed').text('n/a');
|
|
||||||
} else if (Metric) {
|
|
||||||
$('#selected_speed').text(Math.round(selected.speed * 1.852) + ' km/h');
|
|
||||||
} else {
|
|
||||||
$('#selected_speed').text(Math.round(selected.speed) + ' kt');
|
|
||||||
}
|
|
||||||
|
|
||||||
$('#selected_icao').text(selected.icao);
|
$('#selected_icao').text(selected.icao);
|
||||||
|
$('#selected_track').text(format_track_long(selected.track));
|
||||||
if (selected.track === null) {
|
|
||||||
$('#selected_track').text('n/a');
|
|
||||||
} else {
|
|
||||||
$('#selected_track').text(selected.track + '\u00b0' + ' (' + trackLongName(selected.track) + ')');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (selected.seen <= 1) {
|
if (selected.seen <= 1) {
|
||||||
$('#selected_seen').text('now');
|
$('#selected_seen').text('now');
|
||||||
|
@ -358,72 +429,20 @@ function refreshSelected() {
|
||||||
$('#selected_seen').text(selected.seen + 's ago');
|
$('#selected_seen').text(selected.seen + 's ago');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selected.latitude === null) {
|
if (selected.position === null) {
|
||||||
$('#selected_position').text('n/a');
|
$('#selected_position').text('n/a');
|
||||||
} else {
|
} else {
|
||||||
if (selected.seen_pos > 1) {
|
if (selected.seen_pos > 1) {
|
||||||
$('#selected_position').text(selected.latitude + ', ' + selected.longitude + " (" + selected.seen_pos + "s ago)");
|
$('#selected_position').text(format_latlng(selected.position) + " (" + selected.seen_pos + "s ago)");
|
||||||
} else {
|
} else {
|
||||||
$('#selected_position').text(selected.latitude + ', ' + selected.longitude);
|
$('#selected_position').text(format_latlng(selected.position));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selected.sitedist !== null) {
|
$('#selected_sitedist').text(format_distance_long(selected.sitedist));
|
||||||
var dist = selected.sitedist;
|
|
||||||
if (Metric) {
|
|
||||||
dist /= 1000;
|
|
||||||
} else {
|
|
||||||
dist /= 1852;
|
|
||||||
}
|
|
||||||
|
|
||||||
dist = (Math.round((dist)*10)/10).toFixed(1);
|
|
||||||
|
|
||||||
$('#selected_sitedist').text(dist + (Metric ? ' km' : ' NM'));
|
|
||||||
} else {
|
|
||||||
$('#selected_sitedist').text("n/a");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function trackShortName(track) {
|
|
||||||
var trackIndex = Math.floor((360 + track % 360 + 22.5) / 45) % 8;
|
|
||||||
return ["N","NE","E","SE","S","SW","W","NW"][trackIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
function trackLongName(track) {
|
|
||||||
var trackIndex = Math.floor((360 + track % 360 + 22.5) / 45) % 8;
|
|
||||||
return ["North","Northeast","East","Southeast","South","Southwest","West","Northwest"][trackIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refeshes the larger table of all the planes
|
|
||||||
|
|
||||||
function format_altitude(alt) {
|
|
||||||
if (alt === null)
|
|
||||||
return "";
|
|
||||||
else if (alt === "ground")
|
|
||||||
return "ground";
|
|
||||||
else if (Metric)
|
|
||||||
return Math.round(alt / 3.2828);
|
|
||||||
else
|
|
||||||
return Math.round(alt);
|
|
||||||
}
|
|
||||||
|
|
||||||
function format_speed(speed) {
|
|
||||||
if (speed === null)
|
|
||||||
return "";
|
|
||||||
else if (Metric)
|
|
||||||
return Math.round(speed * 1.852);
|
|
||||||
else
|
|
||||||
return Math.round(speed);
|
|
||||||
}
|
|
||||||
|
|
||||||
function format_distance(dist) {
|
|
||||||
if (Metric) {
|
|
||||||
return (Math.round(dist/100) / 10).toFixed(1);
|
|
||||||
} else {
|
|
||||||
return (Math.round(dist/185.2) / 10).toFixed(1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Refreshes the larger table of all the planes
|
||||||
function refreshTableInfo() {
|
function refreshTableInfo() {
|
||||||
var show_squawk_warning = false;
|
var show_squawk_warning = false;
|
||||||
|
|
||||||
|
@ -440,7 +459,7 @@ function refreshTableInfo() {
|
||||||
TrackedAircraft++;
|
TrackedAircraft++;
|
||||||
var classes = "plane_table_row";
|
var classes = "plane_table_row";
|
||||||
|
|
||||||
if (tableplane.latitude !== null)
|
if (tableplane.position !== null)
|
||||||
classes += " vPosition";
|
classes += " vPosition";
|
||||||
if (tableplane.icao == SelectedPlane)
|
if (tableplane.icao == SelectedPlane)
|
||||||
classes += " selected";
|
classes += " selected";
|
||||||
|
@ -453,23 +472,14 @@ function refreshTableInfo() {
|
||||||
// ICAO doesn't change
|
// ICAO doesn't change
|
||||||
tableplane.tr.cells[1].textContent = (tableplane.flight !== null ? tableplane.flight : "");
|
tableplane.tr.cells[1].textContent = (tableplane.flight !== null ? tableplane.flight : "");
|
||||||
tableplane.tr.cells[2].textContent = (tableplane.squawk !== null ? tableplane.squawk : "");
|
tableplane.tr.cells[2].textContent = (tableplane.squawk !== null ? tableplane.squawk : "");
|
||||||
tableplane.tr.cells[3].textContent = format_altitude(tableplane.altitude);
|
tableplane.tr.cells[3].textContent = format_altitude_brief(tableplane.altitude);
|
||||||
tableplane.tr.cells[4].textContent = format_speed(tableplane.speed);
|
tableplane.tr.cells[4].textContent = format_speed_brief(tableplane.speed);
|
||||||
|
|
||||||
if (tableplane.latitude !== null)
|
if (tableplane.position !== null)
|
||||||
++TrackedAircraftPositions;
|
++TrackedAircraftPositions;
|
||||||
|
|
||||||
// Add distance column to table if site coordinates are provided
|
tableplane.tr.cells[5].textContent = format_distance_brief(tableplane.sitedist);
|
||||||
if (SitePosition !== null && tableplane.latitude !== null) {
|
tableplane.tr.cells[6].textContent = format_track_brief(tableplane.track);
|
||||||
var planeLatLon = new google.maps.LatLng(tableplane.latitude, tableplane.longitude);
|
|
||||||
var dist = google.maps.geometry.spherical.computeDistanceBetween (SitePosition, planeLatLon);
|
|
||||||
tableplane.tr.cells[5].textContent = format_distance(dist);
|
|
||||||
tableplane.sitedist = dist;
|
|
||||||
} else {
|
|
||||||
tableplane.tr.cells[5].textContent = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
tableplane.tr.cells[6].textContent = (tableplane.track !== null ? tableplane.track : "");
|
|
||||||
tableplane.tr.cells[7].textContent = tableplane.messages;
|
tableplane.tr.cells[7].textContent = tableplane.messages;
|
||||||
tableplane.tr.cells[8].textContent = tableplane.seen;
|
tableplane.tr.cells[8].textContent = tableplane.seen;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue