Merge remote-tracking branch 'csfa/map_enhancements' into dev
This commit is contained in:
commit
7dee192157
|
@ -11,14 +11,11 @@ PlaneCountInTitle = true;
|
|||
MessageRateInTitle = false;
|
||||
|
||||
// -- Output Settings -------------------------------------
|
||||
// Show metric values
|
||||
// The Metric setting controls whether metric (m, km, km/h) or
|
||||
// imperial (ft, NM, knots) units are used in the plane table
|
||||
// and in the detailed plane info. If ShowOtherUnits is true,
|
||||
// then the other unit will also be shown in the detailed plane
|
||||
// info.
|
||||
Metric = false;
|
||||
ShowOtherUnits = true;
|
||||
// The DisplayUnits setting controls whether nautical (ft, NM, knots),
|
||||
// metric (m, km, km/h) or imperial (ft, mi, mph) units are used in the
|
||||
// plane table and in the detailed plane info. Valid values are
|
||||
// "nautical", "metric", or "imperial".
|
||||
DisplayUnits = "nautical";
|
||||
|
||||
// -- Map settings ----------------------------------------
|
||||
// These settings are overridden by any position information
|
||||
|
@ -98,7 +95,7 @@ OutlineADSBColor = '#000000';
|
|||
OutlineMlatColor = '#4040FF';
|
||||
|
||||
SiteCircles = true; // true to show circles (only shown if the center marker is shown)
|
||||
// In nautical miles or km (depending settings value 'Metric')
|
||||
// In miles, nautical miles, or km (depending settings value 'DisplayUnits')
|
||||
SiteCirclesDistances = new Array(100,150,200);
|
||||
|
||||
// Show the clocks at the top of the righthand pane? You can disable the clocks if you want here
|
||||
|
|
3
public_html/db/aircraft_types/README
Normal file
3
public_html/db/aircraft_types/README
Normal file
|
@ -0,0 +1,3 @@
|
|||
Aircraft type data was retrieved from http://www.icao.int/publications/DOC8643/ and converted to JSON format.
|
||||
|
||||
Data was last updated on 2016-03-23 and retrieved on 2016-08-25.
|
1
public_html/db/aircraft_types/icao_aircraft_types.json
Normal file
1
public_html/db/aircraft_types/icao_aircraft_types.json
Normal file
File diff suppressed because one or more lines are too long
|
@ -22,6 +22,7 @@
|
|||
"use strict";
|
||||
|
||||
var _aircraft_cache = {};
|
||||
var _aircraft_type_cache = null;
|
||||
|
||||
function getAircraftData(icao) {
|
||||
var defer;
|
||||
|
@ -48,7 +49,7 @@ function request_from_db(icao, level, defer) {
|
|||
var subkey;
|
||||
|
||||
if (dkey in data) {
|
||||
defer.resolve(data[dkey]);
|
||||
getIcaoAircraftTypeData(data[dkey], defer);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -67,6 +68,36 @@ function request_from_db(icao, level, defer) {
|
|||
});
|
||||
}
|
||||
|
||||
function getIcaoAircraftTypeData(aircraftData, defer) {
|
||||
if (_aircraft_type_cache === null) {
|
||||
$.getJSON("db/aircraft_types/icao_aircraft_types.json")
|
||||
.done(function(typeLookupData) {
|
||||
_aircraft_type_cache = typeLookupData;
|
||||
})
|
||||
.always(function() {
|
||||
lookupIcaoAircraftType(aircraftData, defer);
|
||||
});
|
||||
}
|
||||
else {
|
||||
lookupIcaoAircraftType(aircraftData, defer);
|
||||
}
|
||||
}
|
||||
|
||||
function lookupIcaoAircraftType(aircraftData, defer) {
|
||||
if (_aircraft_type_cache !== null && "t" in aircraftData) {
|
||||
var typeDesignator = aircraftData.t.toUpperCase();
|
||||
if (typeDesignator in _aircraft_type_cache) {
|
||||
var typeData = _aircraft_type_cache[typeDesignator];
|
||||
if (typeData.desc != undefined && typeData.desc != null && typeData.desc.length == 3) {
|
||||
aircraftData.desc = typeData.desc;
|
||||
}
|
||||
aircraftData.wtc = typeData.wtc;
|
||||
}
|
||||
}
|
||||
|
||||
defer.resolve(aircraftData);
|
||||
}
|
||||
|
||||
var _request_count = 0;
|
||||
var _request_queue = [];
|
||||
var _request_cache = {};
|
||||
|
|
|
@ -8,8 +8,23 @@ var DOWN_TRIANGLE='\u25bc'; // U+25BC BLACK DOWN-POINTING TRIANGLE
|
|||
|
||||
var TrackDirections = ["North","Northeast","East","Southeast","South","Southwest","West","Northwest"];
|
||||
|
||||
var UnitLabels = {
|
||||
'altitude': { metric: "m", imperial: "ft", nautical: "ft"},
|
||||
'speed': { metric: "km/h", imperial: "mph", nautical: "kt" },
|
||||
'distance': { metric: "km", imperial: "mi", nautical: "NM" },
|
||||
'verticalRate': { metric: "m/s", imperial: "ft/min", nautical: "ft/min" }
|
||||
};
|
||||
|
||||
// formatting helpers
|
||||
|
||||
function get_unit_label(quantity, systemOfMeasurement) {
|
||||
var labels = UnitLabels[quantity];
|
||||
if (labels !== undefined && labels[systemOfMeasurement] !== undefined) {
|
||||
return labels[systemOfMeasurement];
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// track in degrees (0..359)
|
||||
function format_track_brief(track) {
|
||||
if (track === null){
|
||||
|
@ -29,9 +44,8 @@ function format_track_long(track) {
|
|||
return Math.round(track) + DEGREES + NBSP + "(" + TrackDirections[trackDir] + ")";
|
||||
}
|
||||
|
||||
// altitude (input: alt in feet)
|
||||
// brief will always show either Metric or Imperial
|
||||
function format_altitude_brief(alt, vr) {
|
||||
// alt in feet
|
||||
function format_altitude_brief(alt, vr, displayUnits) {
|
||||
var alt_text;
|
||||
|
||||
if (alt === null){
|
||||
|
@ -40,31 +54,24 @@ function format_altitude_brief(alt, vr) {
|
|||
return "ground";
|
||||
}
|
||||
|
||||
if (Metric) {
|
||||
alt_text = Math.round(alt / 3.2828) + NBSP; // Altitude to meters
|
||||
} else {
|
||||
alt_text = Math.round(alt) + NBSP;
|
||||
}
|
||||
alt_text = Math.round(convert_altitude(alt, displayUnits)) + NBSP;
|
||||
|
||||
// Vertical Rate Triangle
|
||||
var verticalRateTriangle = "<span class=\"verticalRateTriangle\">";
|
||||
if (vr > 128){
|
||||
return alt_text + UP_TRIANGLE;
|
||||
verticalRateTriangle += UP_TRIANGLE;
|
||||
} else if (vr < -128){
|
||||
return alt_text + DOWN_TRIANGLE;
|
||||
verticalRateTriangle += DOWN_TRIANGLE;
|
||||
} else {
|
||||
return alt_text + NBSP;
|
||||
verticalRateTriangle += NBSP;
|
||||
}
|
||||
verticalRateTriangle += "</span>"
|
||||
|
||||
return alt_text + verticalRateTriangle;
|
||||
}
|
||||
|
||||
// alt in ft
|
||||
function _alt_to_unit(alt, m) {
|
||||
if (m)
|
||||
return Math.round(alt / 3.2828) + NBSP + "m";
|
||||
else
|
||||
return Math.round(alt) + NBSP + "ft";
|
||||
}
|
||||
|
||||
function format_altitude_long(alt, vr) {
|
||||
// alt in feet
|
||||
function format_altitude_long(alt, vr, displayUnits) {
|
||||
var alt_text = "";
|
||||
|
||||
if (alt === null) {
|
||||
|
@ -73,13 +80,7 @@ function format_altitude_long(alt, vr) {
|
|||
return "on ground";
|
||||
}
|
||||
|
||||
// Primary unit
|
||||
alt_text = _alt_to_unit(alt, Metric);
|
||||
|
||||
// Secondary unit
|
||||
if (ShowOtherUnits) {
|
||||
alt_text = alt_text + ' | ' + _alt_to_unit(alt, !Metric);
|
||||
}
|
||||
alt_text = Math.round(convert_altitude(alt, displayUnits)) + NBSP + get_unit_label("altitude", displayUnits);
|
||||
|
||||
if (vr > 128) {
|
||||
return UP_TRIANGLE + NBSP + alt_text;
|
||||
|
@ -90,83 +91,123 @@ function format_altitude_long(alt, vr) {
|
|||
}
|
||||
}
|
||||
|
||||
//input: speed in kts
|
||||
function format_speed_brief(speed) {
|
||||
// alt in feet
|
||||
function convert_altitude(alt, displayUnits) {
|
||||
if (displayUnits === "metric") {
|
||||
return alt / 3.2808; // feet to meters
|
||||
}
|
||||
|
||||
return alt;
|
||||
}
|
||||
|
||||
// speed in knots
|
||||
function format_speed_brief(speed, displayUnits) {
|
||||
if (speed === null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (Metric) {
|
||||
return Math.round(speed * 1.852); // knots to kilometers per hour
|
||||
} else {
|
||||
return Math.round(speed); // knots
|
||||
}
|
||||
return Math.round(convert_speed(speed, displayUnits));
|
||||
}
|
||||
|
||||
// speed in kts
|
||||
|
||||
function _speed_to_unit(speed, m) {
|
||||
if (m)
|
||||
return Math.round(speed * 1.852) + NBSP + "km/h";
|
||||
else
|
||||
return Math.round(speed) + NBSP + "kt";
|
||||
}
|
||||
|
||||
function format_speed_long(speed) {
|
||||
// speed in knots
|
||||
function format_speed_long(speed, displayUnits) {
|
||||
if (speed === null) {
|
||||
return "n/a";
|
||||
}
|
||||
|
||||
// Primary unit
|
||||
var speed_text = _speed_to_unit(speed, Metric);
|
||||
|
||||
// Secondary unit
|
||||
if (ShowOtherUnits) {
|
||||
speed_text = speed_text + ' | ' + _speed_to_unit(speed, !Metric);
|
||||
}
|
||||
var speed_text = Math.round(convert_speed(speed, displayUnits)) + NBSP + get_unit_label("speed", displayUnits);
|
||||
|
||||
return speed_text;
|
||||
}
|
||||
|
||||
// speed in knots
|
||||
function convert_speed(speed, displayUnits) {
|
||||
if (displayUnits === "metric") {
|
||||
return speed * 1.852; // knots to kilometers per hour
|
||||
}
|
||||
else if (displayUnits === "imperial") {
|
||||
return speed * 1.151; // knots to miles per hour
|
||||
}
|
||||
|
||||
return speed;
|
||||
}
|
||||
|
||||
// dist in meters
|
||||
function format_distance_brief(dist) {
|
||||
function format_distance_brief(dist, displayUnits) {
|
||||
if (dist === null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (Metric) {
|
||||
return (dist/1000).toFixed(1); // meters to kilometers
|
||||
} else {
|
||||
return (dist/1852).toFixed(1); // meters to nautocal miles
|
||||
}
|
||||
return convert_distance(dist, displayUnits).toFixed(1);
|
||||
}
|
||||
|
||||
// dist in metres
|
||||
|
||||
function _dist_to_unit(dist, m) {
|
||||
if (m)
|
||||
return (dist/1000).toFixed(1) + NBSP + "km";
|
||||
else
|
||||
return (dist/1852).toFixed(1) + NBSP + "NM";
|
||||
}
|
||||
|
||||
function format_distance_long(dist) {
|
||||
// dist in meters
|
||||
function format_distance_long(dist, displayUnits) {
|
||||
if (dist === null) {
|
||||
return "n/a";
|
||||
}
|
||||
|
||||
// Primary unit
|
||||
var dist_text = _dist_to_unit(dist, Metric);
|
||||
|
||||
// Secondary unit
|
||||
if (ShowOtherUnits) {
|
||||
dist_text = dist_text + ' | ' + _dist_to_unit(dist, !Metric);
|
||||
}
|
||||
var dist_text = convert_distance(dist, displayUnits).toFixed(1) + NBSP + get_unit_label("distance", displayUnits);
|
||||
|
||||
return dist_text;
|
||||
}
|
||||
|
||||
// dist in meters
|
||||
function convert_distance(dist, displayUnits) {
|
||||
if (displayUnits === "metric") {
|
||||
return (dist / 1000); // meters to kilometers
|
||||
}
|
||||
else if (displayUnits === "imperial") {
|
||||
return (dist / 1609); // meters to miles
|
||||
}
|
||||
return (dist / 1852); // meters to nautical miles
|
||||
}
|
||||
|
||||
// rate in ft/min
|
||||
function format_vert_rate_brief(rate, displayUnits) {
|
||||
if (rate === null || rate === undefined) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return convert_vert_rate(rate, displayUnits).toFixed(displayUnits === "metric" ? 1 : 0);
|
||||
}
|
||||
|
||||
// rate in ft/min
|
||||
function format_vert_rate_long(rate, displayUnits) {
|
||||
if (rate === null || rate === undefined) {
|
||||
return "n/a";
|
||||
}
|
||||
|
||||
var rate_text = convert_vert_rate(rate, displayUnits).toFixed(displayUnits === "metric" ? 1 : 0) + NBSP + get_unit_label("verticalRate", displayUnits);
|
||||
|
||||
return rate_text;
|
||||
}
|
||||
|
||||
// rate in ft/min
|
||||
function convert_vert_rate(rate, displayUnits) {
|
||||
if (displayUnits === "metric") {
|
||||
return (rate / 196.85); // ft/min to m/s
|
||||
}
|
||||
|
||||
return rate;
|
||||
}
|
||||
|
||||
// p is a [lon, lat] coordinate
|
||||
function format_latlng(p) {
|
||||
return p[1].toFixed(3) + DEGREES + "," + NBSP + p[0].toFixed(3) + DEGREES;
|
||||
}
|
||||
|
||||
function format_data_source(source) {
|
||||
switch (source) {
|
||||
case 'mlat':
|
||||
return "MLAT";
|
||||
case 'adsb':
|
||||
return "ADS-B";
|
||||
case 'mode_s':
|
||||
return "Mode S";
|
||||
case 'mode_ac':
|
||||
return "Mode A/C";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
|
BIN
public_html/images/hide_sidebar_active_48x40.png
Normal file
BIN
public_html/images/hide_sidebar_active_48x40.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
BIN
public_html/images/hide_sidebar_inactive_48x40.png
Normal file
BIN
public_html/images/hide_sidebar_inactive_48x40.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.8 KiB |
BIN
public_html/images/show_sidebar_active_48x40.png
Normal file
BIN
public_html/images/show_sidebar_active_48x40.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2 KiB |
BIN
public_html/images/show_sidebar_inactive_48x40.png
Normal file
BIN
public_html/images/show_sidebar_inactive_48x40.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.8 KiB |
|
@ -6,6 +6,7 @@
|
|||
<link rel="stylesheet" href="jquery/jquery-ui-1.11.4-smoothness.css" />
|
||||
<script src="jquery/jquery-3.0.0.min.js"></script>
|
||||
<script src="jquery/jquery-ui-1.11.4.min.js"></script>
|
||||
<script src="jquery/plugins/jquery.validate.min.js"></script>
|
||||
|
||||
<link rel="stylesheet" href="ol3/ol-3.17.1.css" type="text/css" />
|
||||
<script src="ol3/ol-3.17.1.js" type="text/javascript"></script>
|
||||
|
@ -45,147 +46,187 @@
|
|||
<input type="hidden" name="submit" value="submit">
|
||||
</form>
|
||||
|
||||
<div id="map_container">
|
||||
<div id="map_canvas"></div>
|
||||
</div>
|
||||
<div id="layout_container">
|
||||
<div id="selected_infoblock" class="hidden">
|
||||
<table style="width: 100%">
|
||||
<tr class="infoblock_heading">
|
||||
<td colspan="2">
|
||||
<b>
|
||||
<span id="selected_callsign" onclick="toggleFollowSelected();" class="pointer">n/a</span>
|
||||
</b>
|
||||
<span id="selected_follow" onclick="toggleFollowSelected();" class="pointer">⇒</span>
|
||||
|
||||
<div id="sidebar_container">
|
||||
<div id="sidebar_canvas">
|
||||
<div id="sudo_buttons">
|
||||
<table style="width: 100%">
|
||||
<tr>
|
||||
<td style="width: 150px; text-align: center;" class="pointer">
|
||||
[ <span onclick="resetMap();">Reset Map</span> ]
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div> <!-- sudo_buttons -->
|
||||
<span id="selected_flag">
|
||||
<img style="width: 20px; height=12px" src="about:blank" alt="Flag">
|
||||
</span>
|
||||
|
||||
<div id="dump1090_infoblock">
|
||||
<table style="width: 100%">
|
||||
<tr class="infoblock_heading">
|
||||
<td>
|
||||
<b id="infoblock_name">FlightAware dump1090</b>
|
||||
</td>
|
||||
<td style="text-align: right">
|
||||
<a href="https://github.com/flightaware/dump1090" id="dump1090_version" target="_blank"></a>
|
||||
</td>
|
||||
</tr>
|
||||
<a href="http://www.airframes.org/" onclick="document.getElementById('horrible_hack').submit.call(document.getElementById('airframes_post')); return false;">
|
||||
<span id="selected_icao"></span>
|
||||
</a>
|
||||
<span id="selected_registration"></span>
|
||||
<span id="selected_icaotype"></span>
|
||||
<span id="selected_emergency"></span>
|
||||
<span id="selected_flightaware_link"></span>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr class="infoblock_body">
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr id="infoblock_country" class="infoblock_body">
|
||||
<td colspan="2">Country of registration: <span id="selected_country">n/a</span></td>
|
||||
</tr>
|
||||
|
||||
<tr class="infoblock_body dim">
|
||||
<td>(no aircraft selected)</td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr class="infoblock_body">
|
||||
<td style="width: 55%">Altitude: <span id="selected_altitude"></span></td>
|
||||
<td style="width: 45%">Squawk: <span id="selected_squawk"></span></td>
|
||||
</tr>
|
||||
|
||||
<tr class="infoblock_body">
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr class="infoblock_body">
|
||||
<td>Speed: <span id="selected_speed">n/a</span></td>
|
||||
<td>RSSI: <span id="selected_rssi">n/a</span></td>
|
||||
</tr>
|
||||
|
||||
<tr class="infoblock_body">
|
||||
<td>Aircraft (total): <span id="dump1090_total_ac">n/a</span></td>
|
||||
<td>Messages: <span id="dump1090_message_rate">n/a</span>/sec</td>
|
||||
</tr>
|
||||
<tr class="infoblock_body">
|
||||
<td>Vertical rate: <span id="selected_vertical_rate">n/a</span></td>
|
||||
<td>Messages: <span id="selected_message_count">n/a</span></td>
|
||||
</tr>
|
||||
|
||||
<tr class="infoblock_body">
|
||||
<td>(with positions): <span id="dump1090_total_ac_positions">n/a</span></td>
|
||||
<td>History: <span id="dump1090_total_history">n/a</span> positions</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div> <!-- dump1090_infoblock -->
|
||||
<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>
|
||||
|
||||
<div id="selected_infoblock" class="hidden">
|
||||
<table style="width: 100%">
|
||||
<tr class="infoblock_heading">
|
||||
<td colspan="2">
|
||||
<b>
|
||||
<span id="selected_callsign" onclick="toggleFollowSelected();" class="pointer">n/a</span>
|
||||
</b>
|
||||
<span id="selected_follow" onclick="toggleFollowSelected();" class="pointer">⇒</span>
|
||||
<tr class="infoblock_body">
|
||||
<td colspan="2">Position: <span id="selected_position">n/a</span></td>
|
||||
</tr>
|
||||
|
||||
<span id="selected_flag">
|
||||
<img style="width: 20px; height=12px" src="about:blank" alt="Flag">
|
||||
</span>
|
||||
<tr class="infoblock_body">
|
||||
<td colspan="2">Distance from Site: <span id="selected_sitedist">n/a</span></td>
|
||||
</tr>
|
||||
<tr class="infoblock_body">
|
||||
<td colspan="2"><span id="selected_photo_link"></span></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div> <!-- selected_infoblock -->
|
||||
<div id="map_container">
|
||||
<div id="map_canvas"></div>
|
||||
<a id="toggle_sidebar_button" class="hide_sidebar" href="#"></a>
|
||||
<a id="expand_sidebar_button" href="#"></a>
|
||||
</div>
|
||||
<div id="sidebar_container">
|
||||
<div id="splitter" class="ui-resizable-handle ui-resizable-w"></div>
|
||||
<div id="sidebar_canvas">
|
||||
|
||||
<a href="http://www.airframes.org/" onclick="document.getElementById('horrible_hack').submit.call(document.getElementById('airframes_post')); return false;">
|
||||
<span id="selected_icao"></span>
|
||||
</a>
|
||||
<span id="selected_registration"></span>
|
||||
<span id="selected_icaotype"></span>
|
||||
<span id="selected_emergency"></span>
|
||||
<a id="selected_flightaware_link" href="" target="_blank">[FlightAware]</a>
|
||||
</td>
|
||||
</tr>
|
||||
<div id="dump1090_infoblock">
|
||||
<table style="width: 100%">
|
||||
<tr class="infoblock_heading">
|
||||
<td>
|
||||
<b id="infoblock_name">FlightAware dump1090</b>
|
||||
</td>
|
||||
<td>
|
||||
<span id="show_map_button" class="sidebarButton pointer">Show Map</span>
|
||||
</td>
|
||||
<td style="text-align: right">
|
||||
<a href="https://github.com/flightaware/dump1090" id="dump1090_version" target="_blank"></a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr id="infoblock_country" class="infoblock_body">
|
||||
<td colspan="2">Country of registration: <span id="selected_country">n/a</span></td>
|
||||
</tr>
|
||||
|
||||
<tr class="infoblock_body">
|
||||
<td style="width: 55%">Altitude: <span id="selected_altitude"></span></td>
|
||||
<td style="width: 45%">Squawk: <span id="selected_squawk"></span></td>
|
||||
</tr>
|
||||
|
||||
<tr class="infoblock_body">
|
||||
<td>Speed: <span id="selected_speed">n/a</span></td>
|
||||
<td>RSSI: <span id="selected_rssi">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">Position: <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> <!-- selected_infoblock -->
|
||||
|
||||
<div id="planes_table">
|
||||
<table id="tableinfo" style="width: 100%">
|
||||
<thead style="background-color: #BBBBBB; cursor: pointer;">
|
||||
<tr>
|
||||
<td id="icao" onclick="sortByICAO();">ICAO</td>
|
||||
<td id="flag" onclick="sortByCountry()"><!-- column for flag image --></td>
|
||||
<td id="flight" onclick="sortByFlight();">Flight</td>
|
||||
<td id="squawk" onclick="sortBySquawk();" style="text-align: right">Squawk</td>
|
||||
<td id="altitude" onclick="sortByAltitude();" style="text-align: right">Altitude</td>
|
||||
<td id="speed" onclick="sortBySpeed();" style="text-align: right">Speed</td>
|
||||
<td id="distance" onclick="sortByDistance();" style="text-align: right">Distance</td>
|
||||
<td id="track" onclick="sortByTrack();" style="text-align: right">Track</td>
|
||||
<td id="msgs" onclick="sortByMsgs();" style="text-align: right">Msgs</td>
|
||||
<td id="seen" onclick="sortBySeen();" style="text-align: right">Age</td>
|
||||
<td colspan="2">
|
||||
<div id="sudo_buttons">
|
||||
<span class="sidebarButton pointer" onclick="resetMap();">Reset Map</span>
|
||||
<span class="sidebarButton pointer" onclick="selectAllPlanes();">Select All</span>
|
||||
<span class="sidebarButton pointer" onclick="deselectAllPlanes();">Select None</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr id="plane_row_template" class="plane_table_row hidden">
|
||||
<td>ICAO</td>
|
||||
<td><img style="width: 20px; height=12px" src="about:blank" alt="Flag"></td>
|
||||
<td>FLIGHT</td>
|
||||
<td style="text-align: right">SQUAWK</td>
|
||||
<td style="text-align: right">ALTITUDE</td>
|
||||
<td style="text-align: right">SPEED</td>
|
||||
<td style="text-align: right">DISTANCE</td>
|
||||
<td style="text-align: right">TRACK</td>
|
||||
<td style="text-align: right">MSGS</td>
|
||||
<td style="text-align: right">SEEN</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div> <!-- planes_table -->
|
||||
|
||||
</div> <!-- sidebar_canvas -->
|
||||
</div> <!-- sidebar_container -->
|
||||
<tr class="infoblock_body">
|
||||
<td>Aircraft (total): <span id="dump1090_total_ac">n/a</span></td>
|
||||
<td>Messages: <span id="dump1090_message_rate">n/a</span>/sec</td>
|
||||
</tr>
|
||||
|
||||
<tr class="infoblock_body">
|
||||
<td>(with positions): <span id="dump1090_total_ac_positions">n/a</span></td>
|
||||
<td>History: <span id="dump1090_total_history">n/a</span> positions</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div> <!-- dump1090_infoblock -->
|
||||
|
||||
<div id="units_container">
|
||||
<label for="units_selector">Units:</label>
|
||||
<select name="units_selector" id="units_selector">
|
||||
<option value="nautical">Aeronautical</option>
|
||||
<option value="metric">Metric</option>
|
||||
<option value="imperial">Imperial</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<form id="altitude_filter_form">
|
||||
<label>Filter by altitude:</label>
|
||||
<input id="altitude_filter_min" name="minAltitude" type="text" class="altitudeFilterInput" maxlength="5">
|
||||
<label for="minAltitude" class="altitudeUnit"></label>
|
||||
<span> to </span>
|
||||
<input id="altitude_filter_max" name="maxAltitude" type="text" class="altitudeFilterInput" maxlength="5">
|
||||
<label for="maxAltitude" class="altitudeUnit"></label>
|
||||
<button type="submit">Filter</button>
|
||||
<button id="altitude_filter_reset_button">Reset</button>
|
||||
</form>
|
||||
|
||||
<div id="planes_table">
|
||||
<table id="tableinfo" style="width: 100%">
|
||||
<thead class="aircraft_table_header">
|
||||
<tr>
|
||||
<td id="icao" onclick="sortByICAO();">ICAO</td>
|
||||
<td id="flag" onclick="sortByCountry()"><!-- column for flag image --></td>
|
||||
<td id="flight" onclick="sortByFlight();">Ident</td>
|
||||
<td id="registration" onclick="sortByRegistration();">Registration</td>
|
||||
<td id="aircraft_type" onclick="sortByAircraftType();"> Aircraft type</td>
|
||||
<td id="squawk" onclick="sortBySquawk();">Squawk</td>
|
||||
<td id="altitude" onclick="sortByAltitude();">Altitude (<span class="altitudeUnit"></span>)</td>
|
||||
<td id="speed" onclick="sortBySpeed();">Speed (<span class="speedUnit"></span>)</td>
|
||||
<td id="vert_rate" onclick="sortByVerticalRate();">Vertical Rate (<span class="verticalRateUnit"></span>)</td>
|
||||
<td id="distance" onclick="sortByDistance();">Distance (<span class="distanceUnit"></span>)</td>
|
||||
<td id="track" onclick="sortByTrack();">Track</td>
|
||||
<td id="msgs" onclick="sortByMsgs();">Msgs</td>
|
||||
<td id="seen" onclick="sortBySeen();">Age</td>
|
||||
<td id="rssi" onclick="sortByRssi();">RSSI</td>
|
||||
<td id="lat" onclick="sortByLatitude();">Latitude</td>
|
||||
<td id="lon" onclick="sortByLongitude();">Longitude</td>
|
||||
<td id="data_source" onclick="sortByDataSource();">Data Source</td>
|
||||
<td id="airframes_mode_s_link">Airframes.org Link</td>
|
||||
<td id="flightaware_mode_s_link">FlightAware Link</td>
|
||||
<td id="flightaware_photo_link">Photos</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr id="plane_row_template" class="plane_table_row hidden">
|
||||
<td style="text-transform: uppercase">ICAO</td>
|
||||
<td><img style="width: 20px; height=12px" src="about:blank" alt="Flag"></td>
|
||||
<td>FLIGHT</td>
|
||||
<td>REGISTRATION</td>
|
||||
<td>AIRCRAFT_TYPE</td>
|
||||
<td style="text-align: right">SQUAWK</td>
|
||||
<td style="text-align: right">ALTITUDE</td>
|
||||
<td style="text-align: right">SPEED</td>
|
||||
<td style="text-align: right">VERT_RATE</td>
|
||||
<td style="text-align: right">DISTANCE</td>
|
||||
<td style="text-align: right">TRACK</td>
|
||||
<td style="text-align: right">MSGS</td>
|
||||
<td style="text-align: right">SEEN</td>
|
||||
<td style="text-align: right">RSSI</td>
|
||||
<td style="text-align: right">LAT</td>
|
||||
<td style="text-align: right">LON</td>
|
||||
<td style="text-align: right">DATA_SOURCE</td>
|
||||
<td style="text-align: center">AIRFRAMES_MODE_S_LINK</td>
|
||||
<td style="text-align: center">FLIGHTAWARE_MODE_S_LINK</td>
|
||||
<td style="text-align: center">FLIGHTAWARE_PHOTO_LINK</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div> <!-- planes_table -->
|
||||
|
||||
</div> <!-- sidebar_canvas -->
|
||||
</div> <!-- sidebar_container -->
|
||||
</div> <!-- layout_container -->
|
||||
|
||||
<div id="SpecialSquawkWarning" class="hidden">
|
||||
<b>Squawk 7x00 is reported and shown.</b><br>
|
||||
|
|
4
public_html/jquery/plugins/jquery.validate.min.js
vendored
Executable file
4
public_html/jquery/plugins/jquery.validate.min.js
vendored
Executable file
File diff suppressed because one or more lines are too long
|
@ -73,7 +73,7 @@ var _a320 = {
|
|||
|
||||
var _b777 = {
|
||||
key: "b777",
|
||||
scale: 1.15 * 0.75,
|
||||
scale: 0.80 * 0.75,
|
||||
size: [64, 64],
|
||||
anchor: [32, 32],
|
||||
path: "m 32,1 2,1 1,2 0,20 4,4 0,-4 3,0 0,4 -1,2 17,12 0,2 -16,-5 -7,0 0,13 -1,5 7,5 0,2 -8,-2 -1,2 -1,-2 -8,2 0,-2 7,-5 -1,-5 0,-13 -7,0 -16,5 0,-2 17,-12 -1,-2 0,-4 3,0 0,4 4,-4 0,-20 1,-2 2,-1z"
|
||||
|
@ -121,6 +121,21 @@ var _balloon = {
|
|||
markerRadius: 32
|
||||
};
|
||||
|
||||
var _helicopter = {
|
||||
key : "helicopter",
|
||||
scale : 0.50,
|
||||
size : [64, 64],
|
||||
anchor : [22, 32],
|
||||
path : _rotorcraft_svg
|
||||
};
|
||||
|
||||
var _single_prop = {
|
||||
key : "single_prop",
|
||||
scale : 0.30,
|
||||
size : [64, 64],
|
||||
anchor : [32, 25],
|
||||
path : _beechcraft_svg
|
||||
};
|
||||
|
||||
// by Oliver Jowett <oliver@mutability.co.uk>
|
||||
// licensed under CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/)
|
||||
|
@ -134,13 +149,13 @@ var _a380 = {
|
|||
|
||||
var _b738 = {
|
||||
key: "b738",
|
||||
scale: 0.63 * 0.75,
|
||||
scale: 0.70 * 0.75,
|
||||
size: [64, 64],
|
||||
anchor: [32, 32],
|
||||
path: "m 32,61 -1,-1 -9,2 -2,1 0,-2 9,-6 1,-1 -1,-9 0,-11 -7,0 -1,1 0,-1 -3,1 -1,1 0,-1 -3,1 -9,3 -1,1 0,-2 1,-2 17,-9 1,-1 -1,-2 0,-3 1,-1 2,0 1,1 0,3 3,-2 0,-13 1,-5 1,-3 1,-1 1,1 1,3 1,5 0,13 3,2 0,-3 1,-1 2,0 1,1 0,3 -1,2 1,1 17,9 1,2 0,2 -1,-1 -9,-3 -3,-1 0,1 -1,-1 -3,-1 0,1 -1,-1 -7,0 0,11 -1,9 1,1 9,6 0,2 -2,-1 -9,-2 -1,1 z"
|
||||
};
|
||||
|
||||
var TypeIcons = {
|
||||
var TypeDesignatorIcons = {
|
||||
'A318': _a320, // shortened a320
|
||||
'A319': _a320, // shortened a320
|
||||
'A320': _a320,
|
||||
|
@ -182,14 +197,30 @@ var TypeIcons = {
|
|||
'C30J': _c130
|
||||
};
|
||||
|
||||
// Maps ICAO aircraft type description codes (e.g. "L2J") to aircraft icons. This is used if the ICAO type designator (e.g. "B731")
|
||||
// cannot be found in the TypeDesignatorIcons mappings. The key can be one of the following:
|
||||
// - Single character: The basic aircraft type letter code (e.g. "H" for helicopter).
|
||||
// - Three characters: The ICAO type description code (e.g. "L2J" for landplanes with 2 jet engines).
|
||||
// - Five characters: The ICAO type description code concatenated with the wake turbulence category code, separated by
|
||||
// a dash (e.g. "L2J-M").
|
||||
|
||||
var TypeDescriptionIcons = {
|
||||
'H': _helicopter,
|
||||
|
||||
'L1J': _g650,
|
||||
'L1P': _single_prop,
|
||||
'L1T': _single_prop,
|
||||
|
||||
'L2P': _b200,
|
||||
'L2T': _b200,
|
||||
|
||||
'L2J-L': _g650,
|
||||
'L2J-M': _a320,
|
||||
'L2J-H': _b777,
|
||||
};
|
||||
|
||||
var CategoryIcons = {
|
||||
"A1" : {
|
||||
key : "A1",
|
||||
scale : 0.30,
|
||||
size : [64, 64],
|
||||
anchor : [32, 25],
|
||||
path : _beechcraft_svg
|
||||
},
|
||||
"A1" : _single_prop,
|
||||
|
||||
"A2" : {
|
||||
key : "A2",
|
||||
|
@ -215,13 +246,7 @@ var CategoryIcons = {
|
|||
path : _heavy_svg
|
||||
},
|
||||
|
||||
"A7" : {
|
||||
key : "A7",
|
||||
scale : 0.50,
|
||||
size : [64, 64],
|
||||
anchor : [22, 32],
|
||||
path : _rotorcraft_svg
|
||||
},
|
||||
"A7" : _helicopter,
|
||||
|
||||
"B2" : _balloon
|
||||
};
|
||||
|
@ -234,9 +259,27 @@ var DefaultIcon = {
|
|||
path : _generic_plane_svg
|
||||
};
|
||||
|
||||
function getBaseMarker(category, type) {
|
||||
if (type in TypeIcons) {
|
||||
return TypeIcons[type];
|
||||
function getBaseMarker(category, typeDesignator, typeDescription, wtc) {
|
||||
if (typeDesignator in TypeDesignatorIcons) {
|
||||
return TypeDesignatorIcons[typeDesignator];
|
||||
}
|
||||
|
||||
if (typeDescription !== undefined && typeDescription !== null && typeDescription.length === 3) {
|
||||
if (wtc !== undefined && wtc !== null && wtc.length === 1) {
|
||||
var typeDescriptionWithWtc = typeDescription + "-" + wtc;
|
||||
if (typeDescriptionWithWtc in TypeDescriptionIcons) {
|
||||
return TypeDescriptionIcons[typeDescriptionWithWtc];
|
||||
}
|
||||
}
|
||||
|
||||
if (typeDescription in TypeDescriptionIcons) {
|
||||
return TypeDescriptionIcons[typeDescription];
|
||||
}
|
||||
|
||||
var basicType = typeDescription.charAt(0);
|
||||
if (basicType in TypeDescriptionIcons) {
|
||||
return TypeDescriptionIcons[basicType];
|
||||
}
|
||||
}
|
||||
|
||||
if (category in CategoryIcons) {
|
||||
|
@ -246,7 +289,7 @@ function getBaseMarker(category, type) {
|
|||
return DefaultIcon;
|
||||
}
|
||||
|
||||
function svgPathToSvg(path, size, stroke, width, fill) {
|
||||
function svgPathToSvg(path, size, stroke, width, fill, transparentBorderWidth) {
|
||||
var svg = '<svg width="' + size[0] + 'px" height="' + size[1] + 'px" version="1.1" xmlns="http://www.w3.org/2000/svg">';
|
||||
svg += '<path d="' + path + '"';
|
||||
if (stroke !== null) {
|
||||
|
@ -258,11 +301,19 @@ function svgPathToSvg(path, size, stroke, width, fill) {
|
|||
if (fill !== null) {
|
||||
svg += ' fill="' + fill + '"';
|
||||
}
|
||||
svg += '/></svg>';
|
||||
svg += '/>';
|
||||
// Add a transparent border to increase the size of the plane marker clickable area.
|
||||
if (transparentBorderWidth > 0) {
|
||||
// If the border is 100% transparent, OpenLayers will ignore it completely - see
|
||||
// https://github.com/openlayers/ol3/issues/2961. The stroke opacity is set to 1% as a workaround.
|
||||
// This is transparent enough to be invisible to the user.
|
||||
svg += '<path d="' + path + '" fill="none" stroke="#FFFFFF" stroke-opacity="0.01" stroke-width="' + transparentBorderWidth + '" />';
|
||||
}
|
||||
svg += '</svg>';
|
||||
return svg;
|
||||
}
|
||||
|
||||
|
||||
function svgPathToURI(path, size, stroke, width, fill) {
|
||||
return "data:image/svg+xml;base64," + btoa(svgPathToSvg(path, size, stroke, width, fill));
|
||||
function svgPathToURI(path, size, stroke, width, fill, transparentBorderWidth) {
|
||||
return "data:image/svg+xml;base64," + btoa(svgPathToSvg(path, size, stroke, width, fill, transparentBorderWidth));
|
||||
}
|
||||
|
|
|
@ -43,11 +43,14 @@ function PlaneObject(icao) {
|
|||
this.markerStaticIcon = null;
|
||||
this.markerStyleKey = null;
|
||||
this.markerSvgKey = null;
|
||||
this.filter = {};
|
||||
|
||||
// start from a computed registration, let the DB override it
|
||||
// if it has something else.
|
||||
this.registration = registration_from_hexid(this.icao);
|
||||
this.icaotype = null;
|
||||
this.typeDescription = null;
|
||||
this.wtc = null;
|
||||
|
||||
// request metadata
|
||||
getAircraftData(this.icao).done(function(data) {
|
||||
|
@ -59,12 +62,32 @@ function PlaneObject(icao) {
|
|||
this.icaotype = data.t;
|
||||
}
|
||||
|
||||
if ("desc" in data) {
|
||||
this.typeDescription = data.desc;
|
||||
}
|
||||
|
||||
if ("wtc" in data) {
|
||||
this.wtc = data.wtc;
|
||||
}
|
||||
|
||||
if (this.selected) {
|
||||
refreshSelected();
|
||||
}
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
PlaneObject.prototype.isFiltered = function() {
|
||||
if (this.filter.minAltitude !== undefined && this.filter.maxAltitude !== undefined) {
|
||||
if (this.altitude === null || this.altitude === undefined) {
|
||||
return true;
|
||||
}
|
||||
var planeAltitude = this.altitude === "ground" ? 0 : convert_altitude(this.altitude, this.filter.altitudeUnits);
|
||||
return planeAltitude < this.filter.minAltitude || planeAltitude > this.filter.maxAltitude;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Appends data to the running track so we can get a visual tail on the plane
|
||||
// Only useful for a long running browser session.
|
||||
PlaneObject.prototype.updateTrack = function(estimate_time) {
|
||||
|
@ -183,6 +206,27 @@ PlaneObject.prototype.clearLines = function() {
|
|||
}
|
||||
};
|
||||
|
||||
PlaneObject.prototype.getDataSource = function() {
|
||||
// MLAT
|
||||
if (this.position_from_mlat) {
|
||||
return 'mlat';
|
||||
}
|
||||
|
||||
// Not MLAT, but position reported - ADSB
|
||||
if (this.position !== null) {
|
||||
return 'adsb';
|
||||
}
|
||||
|
||||
var emptyHexRegex = /^0*$/;
|
||||
// No position and no ICAO hex code - Mode A/C
|
||||
if (emptyHexRegex.test(this.icao)) {
|
||||
return 'mode_ac';
|
||||
}
|
||||
|
||||
// No position and ICAO hex code present - Mode S
|
||||
return 'mode_s';
|
||||
};
|
||||
|
||||
PlaneObject.prototype.getMarkerColor = function() {
|
||||
// Emergency squawks override everything else
|
||||
if (this.squawk in SpecialSquawks)
|
||||
|
@ -258,9 +302,10 @@ PlaneObject.prototype.updateIcon = function() {
|
|||
var col = this.getMarkerColor();
|
||||
var opacity = (this.position_from_mlat ? 0.75 : 1.0);
|
||||
var outline = (this.position_from_mlat ? OutlineMlatColor : OutlineADSBColor);
|
||||
var baseMarker = getBaseMarker(this.category, this.icaotype);
|
||||
var baseMarker = getBaseMarker(this.category, this.icaotype, this.typeDescription, this.wtc);
|
||||
var weight = ((this.selected ? 2 : 1) / baseMarker.scale).toFixed(1);
|
||||
var rotation = (this.track === null ? 0 : this.track);
|
||||
var transparentBorderWidth = 16;
|
||||
|
||||
var svgKey = col + '!' + outline + '!' + baseMarker.key + '!' + weight;
|
||||
var styleKey = opacity + '!' + rotation;
|
||||
|
@ -274,7 +319,7 @@ PlaneObject.prototype.updateIcon = function() {
|
|||
anchorYUnits: 'pixels',
|
||||
scale: baseMarker.scale,
|
||||
imgSize: baseMarker.size,
|
||||
src: svgPathToURI(baseMarker.path, baseMarker.size, outline, weight, col),
|
||||
src: svgPathToURI(baseMarker.path, baseMarker.size, outline, weight, col, transparentBorderWidth),
|
||||
rotation: (baseMarker.noRotate ? 0 : rotation * Math.PI / 180.0),
|
||||
opacity: opacity,
|
||||
rotateWithView: (baseMarker.noRotate ? false : true)
|
||||
|
@ -300,7 +345,7 @@ PlaneObject.prototype.updateIcon = function() {
|
|||
anchorYUnits: 'pixels',
|
||||
scale: 1.0,
|
||||
imgSize: [size, size],
|
||||
src: svgPathToURI(arrowPath, [size, size], outline, 1, outline),
|
||||
src: svgPathToURI(arrowPath, [size, size], outline, 1, outline, transparentBorderWidth),
|
||||
rotation: rotation * Math.PI / 180.0,
|
||||
opacity: opacity,
|
||||
rotateWithView: true
|
||||
|
@ -421,7 +466,7 @@ PlaneObject.prototype.clearMarker = function() {
|
|||
|
||||
// Update our marker on the map
|
||||
PlaneObject.prototype.updateMarker = function(moved) {
|
||||
if (!this.visible || this.position == null) {
|
||||
if (!this.visible || this.position == null || this.isFiltered()) {
|
||||
this.clearMarker();
|
||||
return;
|
||||
}
|
||||
|
@ -480,9 +525,10 @@ PlaneObject.prototype.updateLines = function() {
|
|||
var lastfixed = lastseg.fixed.getCoordinateAt(1.0);
|
||||
var geom = new ol.geom.LineString([lastfixed, ol.proj.fromLonLat(this.position)]);
|
||||
var feature = new ol.Feature(geom);
|
||||
lastseg.feature = feature;
|
||||
feature.setStyle(this.altitude === 'ground' ? groundStyle : airStyle);
|
||||
|
||||
if (PlaneTrailFeatures.length == 0) {
|
||||
if (PlaneTrailFeatures.getLength() == 0) {
|
||||
PlaneTrailFeatures.push(feature);
|
||||
} else {
|
||||
PlaneTrailFeatures.setAt(0, feature);
|
||||
|
|
|
@ -4,11 +4,15 @@
|
|||
// Define our global variables
|
||||
var OLMap = null;
|
||||
var StaticFeatures = new ol.Collection();
|
||||
var SiteCircleFeatures = new ol.Collection();
|
||||
var PlaneIconFeatures = new ol.Collection();
|
||||
var PlaneTrailFeatures = new ol.Collection();
|
||||
var Planes = {};
|
||||
var PlanesModeAc = {};
|
||||
var PlanesOrdered = [];
|
||||
var PlaneFilter = {};
|
||||
var SelectedPlane = null;
|
||||
var SelectedAllPlanes = false;
|
||||
var FollowSelected = false;
|
||||
|
||||
var SpecialSquawks = {
|
||||
|
@ -62,15 +66,19 @@ function processReceiverUpdate(data) {
|
|||
for (var j=0; j < acs.length; j++) {
|
||||
var ac = acs[j];
|
||||
var hex = ac.hex;
|
||||
var squawk = ac.squawk;
|
||||
var plane = null;
|
||||
|
||||
// Do we already have this plane object in Planes?
|
||||
// If not make it.
|
||||
|
||||
if (Planes[hex]) {
|
||||
if (hex !== "000000" && Planes[hex]) {
|
||||
plane = Planes[hex];
|
||||
} else if (hex === "000000" && PlanesModeAc[squawk]) {
|
||||
plane = PlanesModeAc[squawk];
|
||||
} else {
|
||||
plane = new PlaneObject(hex);
|
||||
plane.filter = PlaneFilter;
|
||||
plane.tr = PlaneRowTemplate.cloneNode(true);
|
||||
|
||||
if (hex[0] === '~') {
|
||||
|
@ -89,17 +97,34 @@ function processReceiverUpdate(data) {
|
|||
$('img', plane.tr.cells[1]).css('display', 'none');
|
||||
}
|
||||
|
||||
plane.tr.addEventListener('click', function(h, evt) {
|
||||
selectPlaneByHex(h, false);
|
||||
evt.preventDefault();
|
||||
}.bind(undefined, hex));
|
||||
if (hex !== "000000") {
|
||||
plane.tr.addEventListener('click', function(h, evt) {
|
||||
if (evt.srcElement instanceof HTMLAnchorElement) {
|
||||
evt.stopPropagation();
|
||||
return;
|
||||
}
|
||||
|
||||
plane.tr.addEventListener('dblclick', function(h, evt) {
|
||||
selectPlaneByHex(h, true);
|
||||
evt.preventDefault();
|
||||
}.bind(undefined, hex));
|
||||
if (!$("#map_container").is(":visible")) {
|
||||
showMap();
|
||||
}
|
||||
selectPlaneByHex(h, false);
|
||||
adjustSelectedInfoBlockPosition();
|
||||
evt.preventDefault();
|
||||
}.bind(undefined, hex));
|
||||
|
||||
Planes[hex] = plane;
|
||||
plane.tr.addEventListener('dblclick', function(h, evt) {
|
||||
if (!$("#map_container").is(":visible")) {
|
||||
showMap();
|
||||
}
|
||||
selectPlaneByHex(h, true);
|
||||
adjustSelectedInfoBlockPosition();
|
||||
evt.preventDefault();
|
||||
}.bind(undefined, hex));
|
||||
|
||||
Planes[hex] = plane;
|
||||
} else {
|
||||
PlanesModeAc[squawk] = plane;
|
||||
}
|
||||
PlanesOrdered.push(plane);
|
||||
}
|
||||
|
||||
|
@ -129,6 +154,7 @@ function fetchData() {
|
|||
plane.updateTick(now, LastReceiverTimestamp);
|
||||
}
|
||||
|
||||
selectNewPlanes();
|
||||
refreshTableInfo();
|
||||
refreshSelected();
|
||||
|
||||
|
@ -197,6 +223,53 @@ function initialize() {
|
|||
|
||||
$("#loader").removeClass("hidden");
|
||||
|
||||
// Set up map/sidebar splitter
|
||||
$("#sidebar_container").resizable({handles: {w: '#splitter'}});
|
||||
|
||||
// Set up aircraft information panel
|
||||
$("#selected_infoblock").draggable({containment: "parent"});
|
||||
|
||||
// Set up event handlers for buttons
|
||||
$("#toggle_sidebar_button").click(toggleSidebarVisibility);
|
||||
$("#expand_sidebar_button").click(expandSidebar);
|
||||
$("#show_map_button").click(showMap);
|
||||
|
||||
// Set initial element visibility
|
||||
$("#show_map_button").hide();
|
||||
setColumnVisibility();
|
||||
|
||||
// Initialize other controls
|
||||
initializeUnitsSelector();
|
||||
|
||||
// Set up altitude filter button event handlers and validation options
|
||||
$("#altitude_filter_form").submit(onFilterByAltitude);
|
||||
$("#altitude_filter_form").validate({
|
||||
errorPlacement: function(error, element) {
|
||||
return true;
|
||||
},
|
||||
|
||||
rules: {
|
||||
minAltitude: {
|
||||
number: true,
|
||||
min: -99999,
|
||||
max: 99999
|
||||
},
|
||||
maxAltitude: {
|
||||
number: true,
|
||||
min: -99999,
|
||||
max: 99999
|
||||
}
|
||||
}
|
||||
});
|
||||
$("#altitude_filter_reset_button").click(onResetAltitudeFilter);
|
||||
|
||||
// Force map to redraw if sidebar container is resized - use a timer to debounce
|
||||
var mapResizeTimeout;
|
||||
$("#sidebar_container").on("resize", function() {
|
||||
clearTimeout(mapResizeTimeout);
|
||||
mapResizeTimeout = setTimeout(updateMapSize, 10);
|
||||
});
|
||||
|
||||
// Get receiver metadata, reconfigure using it, then continue
|
||||
// with initialization
|
||||
$.ajax({ url: 'data/receiver.json',
|
||||
|
@ -354,7 +427,7 @@ function initialize_map() {
|
|||
sortByDistance();
|
||||
} else {
|
||||
SitePosition = null;
|
||||
PlaneRowTemplate.cells[6].style.display = 'none'; // hide distance column
|
||||
PlaneRowTemplate.cells[9].style.display = 'none'; // hide distance column
|
||||
document.getElementById("distance").style.display = 'none'; // hide distance header
|
||||
sortByAltitude();
|
||||
}
|
||||
|
@ -457,7 +530,7 @@ function initialize_map() {
|
|||
controls: [new ol.control.Zoom(),
|
||||
new ol.control.Rotate(),
|
||||
new ol.control.Attribution({collapsed: false}),
|
||||
new ol.control.ScaleLine({units: Metric ? "metric" : "nautical"}),
|
||||
new ol.control.ScaleLine({units: DisplayUnits}),
|
||||
new ol.control.LayerSwitcher()
|
||||
],
|
||||
loadTilesWhileAnimating: true,
|
||||
|
@ -496,6 +569,10 @@ function initialize_map() {
|
|||
null);
|
||||
if (hex) {
|
||||
selectPlaneByHex(hex, (evt.type === 'dblclick'));
|
||||
adjustSelectedInfoBlockPosition();
|
||||
evt.stopPropagation();
|
||||
} else {
|
||||
deselectAllPlanes();
|
||||
evt.stopPropagation();
|
||||
}
|
||||
});
|
||||
|
@ -518,26 +595,7 @@ function initialize_map() {
|
|||
StaticFeatures.push(feature);
|
||||
|
||||
if (SiteCircles) {
|
||||
var circleStyle = new ol.style.Style({
|
||||
fill: null,
|
||||
stroke: new ol.style.Stroke({
|
||||
color: '#000000',
|
||||
width: 1
|
||||
})
|
||||
});
|
||||
|
||||
for (var i=0; i < SiteCirclesDistances.length; ++i) {
|
||||
var distance = SiteCirclesDistances[i] * 1000.0;
|
||||
if (!Metric) {
|
||||
distance *= 1.852;
|
||||
}
|
||||
|
||||
var circle = make_geodesic_circle(SitePosition, distance, 360);
|
||||
circle.transform('EPSG:4326', 'EPSG:3857');
|
||||
var feature = new ol.Feature(circle);
|
||||
feature.setStyle(circleStyle);
|
||||
StaticFeatures.push(feature);
|
||||
}
|
||||
createSiteCircleFeatures();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -591,27 +649,62 @@ function initialize_map() {
|
|||
});
|
||||
}
|
||||
|
||||
function createSiteCircleFeatures() {
|
||||
// Clear existing circles first
|
||||
SiteCircleFeatures.forEach(function(circleFeature) {
|
||||
StaticFeatures.remove(circleFeature);
|
||||
});
|
||||
SiteCircleFeatures.clear();
|
||||
|
||||
var circleStyle = new ol.style.Style({
|
||||
fill: null,
|
||||
stroke: new ol.style.Stroke({
|
||||
color: '#000000',
|
||||
width: 1
|
||||
})
|
||||
});
|
||||
|
||||
var conversionFactor = 1000.0;
|
||||
if (DisplayUnits === "nautical") {
|
||||
conversionFactor = 1852.0;
|
||||
} else if (DisplayUnits === "imperial") {
|
||||
conversionFactor = 1609.0;
|
||||
}
|
||||
|
||||
for (var i=0; i < SiteCirclesDistances.length; ++i) {
|
||||
var distance = SiteCirclesDistances[i] * conversionFactor;
|
||||
var circle = make_geodesic_circle(SitePosition, distance, 360);
|
||||
circle.transform('EPSG:4326', 'EPSG:3857');
|
||||
var feature = new ol.Feature(circle);
|
||||
feature.setStyle(circleStyle);
|
||||
StaticFeatures.push(feature);
|
||||
SiteCircleFeatures.push(feature);
|
||||
}
|
||||
}
|
||||
|
||||
// This looks for planes to reap out of the master Planes variable
|
||||
function reaper() {
|
||||
//console.log("Reaping started..");
|
||||
|
||||
// Look for planes where we have seen no messages for >300 seconds
|
||||
// Look for planes where we have seen no messages for >300 seconds
|
||||
var newPlanes = [];
|
||||
for (var i = 0; i < PlanesOrdered.length; ++i) {
|
||||
var plane = PlanesOrdered[i];
|
||||
if (plane.seen > 300) {
|
||||
// Reap it.
|
||||
//console.log("Reaping " + plane.icao);
|
||||
//console.log("parent " + plane.tr.parentNode);
|
||||
// Reap it.
|
||||
plane.tr.parentNode.removeChild(plane.tr);
|
||||
plane.tr = null;
|
||||
delete Planes[plane.icao];
|
||||
if (plane.icao === "000000") {
|
||||
delete PlanesModeAc[plane.squawk];
|
||||
} else {
|
||||
delete Planes[plane.icao];
|
||||
}
|
||||
plane.destroy();
|
||||
} else {
|
||||
} else {
|
||||
// Keep it.
|
||||
newPlanes.push(plane);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
PlanesOrdered = newPlanes;
|
||||
refreshTableInfo();
|
||||
|
@ -655,33 +748,30 @@ function refreshSelected() {
|
|||
selected = Planes[SelectedPlane];
|
||||
}
|
||||
|
||||
if (!selected) {
|
||||
$('#selected_infoblock').css('display','none');
|
||||
$('#dump1090_infoblock').css('display','block');
|
||||
$('#dump1090_version').text(Dump1090Version);
|
||||
$('#dump1090_total_ac').text(TrackedAircraft);
|
||||
$('#dump1090_total_ac_positions').text(TrackedAircraftPositions);
|
||||
$('#dump1090_total_history').text(TrackedHistorySize);
|
||||
$('#dump1090_infoblock').css('display','block');
|
||||
$('#dump1090_version').text(Dump1090Version);
|
||||
$('#dump1090_total_ac').text(TrackedAircraft);
|
||||
$('#dump1090_total_ac_positions').text(TrackedAircraftPositions);
|
||||
$('#dump1090_total_history').text(TrackedHistorySize);
|
||||
|
||||
if (MessageRate !== null) {
|
||||
$('#dump1090_message_rate').text(MessageRate.toFixed(1));
|
||||
} else {
|
||||
$('#dump1090_message_rate').text("n/a");
|
||||
}
|
||||
|
||||
return;
|
||||
if (MessageRate !== null) {
|
||||
$('#dump1090_message_rate').text(MessageRate.toFixed(1));
|
||||
} else {
|
||||
$('#dump1090_message_rate').text("n/a");
|
||||
}
|
||||
|
||||
$('#dump1090_infoblock').css('display','none');
|
||||
$('#selected_infoblock').css('display','block');
|
||||
setSelectedInfoBlockVisibility();
|
||||
|
||||
$('#selected_flightaware_link').attr('href','//flightaware.com/live/modes/'+selected.icao+'/redirect');
|
||||
if (!selected) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (selected.flight !== null && selected.flight !== "") {
|
||||
$('#selected_callsign').text(selected.flight);
|
||||
} else {
|
||||
$('#selected_callsign').text('n/a');
|
||||
}
|
||||
$('#selected_flightaware_link').html(getFlightAwareModeSLink(selected.icao, selected.flight, "[FlightAware]"));
|
||||
|
||||
if (selected.registration !== null) {
|
||||
$('#selected_registration').text(selected.registration);
|
||||
|
@ -703,7 +793,7 @@ function refreshSelected() {
|
|||
emerg.className = 'hidden';
|
||||
}
|
||||
|
||||
$("#selected_altitude").text(format_altitude_long(selected.altitude, selected.vert_rate));
|
||||
$("#selected_altitude").text(format_altitude_long(selected.altitude, selected.vert_rate, DisplayUnits));
|
||||
|
||||
if (selected.squawk === null || selected.squawk === '0000') {
|
||||
$('#selected_squawk').text('n/a');
|
||||
|
@ -711,7 +801,8 @@ function refreshSelected() {
|
|||
$('#selected_squawk').text(selected.squawk);
|
||||
}
|
||||
|
||||
$('#selected_speed').text(format_speed_long(selected.speed));
|
||||
$('#selected_speed').text(format_speed_long(selected.speed, DisplayUnits));
|
||||
$('#selected_vertical_rate').text(format_vert_rate_long(selected.vert_rate, DisplayUnits));
|
||||
$('#selected_icao').text(selected.icao.toUpperCase());
|
||||
$('#airframes_post_icao').attr('value',selected.icao);
|
||||
$('#selected_track').text(format_track_long(selected.track));
|
||||
|
@ -750,8 +841,10 @@ function refreshSelected() {
|
|||
}
|
||||
}
|
||||
|
||||
$('#selected_sitedist').text(format_distance_long(selected.sitedist));
|
||||
$('#selected_sitedist').text(format_distance_long(selected.sitedist, DisplayUnits));
|
||||
$('#selected_rssi').text(selected.rssi.toFixed(1) + ' dBFS');
|
||||
$('#selected_message_count').text(selected.messages);
|
||||
$('#selected_photo_link').html(getFlightAwarePhotoLink(selected.registration));
|
||||
}
|
||||
|
||||
// Refreshes the larger table of all the planes
|
||||
|
@ -762,10 +855,15 @@ function refreshTableInfo() {
|
|||
TrackedAircraftPositions = 0
|
||||
TrackedHistorySize = 0
|
||||
|
||||
$(".altitudeUnit").text(get_unit_label("altitude", DisplayUnits));
|
||||
$(".speedUnit").text(get_unit_label("speed", DisplayUnits));
|
||||
$(".distanceUnit").text(get_unit_label("distance", DisplayUnits));
|
||||
$(".verticalRateUnit").text(get_unit_label("verticalRate", DisplayUnits));
|
||||
|
||||
for (var i = 0; i < PlanesOrdered.length; ++i) {
|
||||
var tableplane = PlanesOrdered[i];
|
||||
TrackedHistorySize += tableplane.history_size;
|
||||
if (!tableplane.visible) {
|
||||
if (!tableplane.visible || tableplane.isFiltered()) {
|
||||
tableplane.tr.className = "plane_table_row hidden";
|
||||
} else {
|
||||
TrackedAircraft++;
|
||||
|
@ -787,14 +885,24 @@ function refreshTableInfo() {
|
|||
}
|
||||
|
||||
// ICAO doesn't change
|
||||
tableplane.tr.cells[2].textContent = (tableplane.flight !== null ? tableplane.flight : "");
|
||||
tableplane.tr.cells[3].textContent = (tableplane.squawk !== null ? tableplane.squawk : "");
|
||||
tableplane.tr.cells[4].textContent = format_altitude_brief(tableplane.altitude, tableplane.vert_rate);
|
||||
tableplane.tr.cells[5].textContent = format_speed_brief(tableplane.speed);
|
||||
tableplane.tr.cells[6].textContent = format_distance_brief(tableplane.sitedist);
|
||||
tableplane.tr.cells[7].textContent = format_track_brief(tableplane.track);
|
||||
tableplane.tr.cells[8].textContent = tableplane.messages;
|
||||
tableplane.tr.cells[9].textContent = tableplane.seen.toFixed(0);
|
||||
tableplane.tr.cells[2].innerHTML = getFlightAwareIdentLink(tableplane.flight);
|
||||
tableplane.tr.cells[3].textContent = (tableplane.registration !== null ? tableplane.registration : "");
|
||||
tableplane.tr.cells[4].textContent = (tableplane.icaotype !== null ? tableplane.icaotype : "");
|
||||
tableplane.tr.cells[5].textContent = (tableplane.squawk !== null ? tableplane.squawk : "");
|
||||
tableplane.tr.cells[6].innerHTML = format_altitude_brief(tableplane.altitude, tableplane.vert_rate, DisplayUnits);
|
||||
tableplane.tr.cells[7].textContent = format_speed_brief(tableplane.speed, DisplayUnits);
|
||||
tableplane.tr.cells[8].textContent = format_vert_rate_brief(tableplane.vert_rate, DisplayUnits);
|
||||
tableplane.tr.cells[9].textContent = format_distance_brief(tableplane.sitedist, DisplayUnits);
|
||||
tableplane.tr.cells[10].textContent = format_track_brief(tableplane.track);
|
||||
tableplane.tr.cells[11].textContent = tableplane.messages;
|
||||
tableplane.tr.cells[12].textContent = tableplane.seen.toFixed(0);
|
||||
tableplane.tr.cells[13].textContent = (tableplane.rssi !== null ? tableplane.rssi : "");
|
||||
tableplane.tr.cells[14].textContent = (tableplane.position !== null ? tableplane.position[1].toFixed(4) : "");
|
||||
tableplane.tr.cells[15].textContent = (tableplane.position !== null ? tableplane.position[0].toFixed(4) : "");
|
||||
tableplane.tr.cells[16].textContent = format_data_source(tableplane.getDataSource());
|
||||
tableplane.tr.cells[17].innerHTML = getAirframesModeSLink(tableplane.icao);
|
||||
tableplane.tr.cells[18].innerHTML = getFlightAwareModeSLink(tableplane.icao, tableplane.flight);
|
||||
tableplane.tr.cells[19].innerHTML = getFlightAwarePhotoLink(tableplane.registration);
|
||||
tableplane.tr.className = classes;
|
||||
}
|
||||
}
|
||||
|
@ -829,14 +937,21 @@ function compareNumeric(xf,yf) {
|
|||
|
||||
function sortByICAO() { sortBy('icao', compareAlpha, function(x) { return x.icao; }); }
|
||||
function sortByFlight() { sortBy('flight', compareAlpha, function(x) { return x.flight; }); }
|
||||
function sortByRegistration() { sortBy('registration', compareAlpha, function(x) { return x.registration; }); }
|
||||
function sortByAircraftType() { sortBy('icaotype', compareAlpha, function(x) { return x.icaotype; }); }
|
||||
function sortBySquawk() { sortBy('squawk', compareAlpha, function(x) { return x.squawk; }); }
|
||||
function sortByAltitude() { sortBy('altitude',compareNumeric, function(x) { return (x.altitude == "ground" ? -1e9 : x.altitude); }); }
|
||||
function sortBySpeed() { sortBy('speed', compareNumeric, function(x) { return x.speed; }); }
|
||||
function sortByVerticalRate() { sortBy('vert_rate', compareNumeric, function(x) { return x.vert_rate; }); }
|
||||
function sortByDistance() { sortBy('sitedist',compareNumeric, function(x) { return x.sitedist; }); }
|
||||
function sortByTrack() { sortBy('track', compareNumeric, function(x) { return x.track; }); }
|
||||
function sortByMsgs() { sortBy('msgs', compareNumeric, function(x) { return x.messages; }); }
|
||||
function sortBySeen() { sortBy('seen', compareNumeric, function(x) { return x.seen; }); }
|
||||
function sortByCountry() { sortBy('country', compareAlpha, function(x) { return x.icaorange.country; }); }
|
||||
function sortByRssi() { sortBy('rssi', compareNumeric, function(x) { return x.rssi }); }
|
||||
function sortByLatitude() { sortBy('lat', compareNumeric, function(x) { return (x.position !== null ? x.position[1] : null) }); }
|
||||
function sortByLongitude() { sortBy('lon', compareNumeric, function(x) { return (x.position !== null ? x.position[0] : null) }); }
|
||||
function sortByDataSource() { sortBy('data_source', compareAlpha, function(x) { return x.getDataSource() } ); }
|
||||
|
||||
var sortId = '';
|
||||
var sortCompare = null;
|
||||
|
@ -894,6 +1009,11 @@ function sortBy(id,sc,se) {
|
|||
function selectPlaneByHex(hex,autofollow) {
|
||||
//console.log("select: " + hex);
|
||||
// If SelectedPlane has something in it, clear out the selected
|
||||
|
||||
if (SelectedAllPlanes) {
|
||||
deselectAllPlanes();
|
||||
}
|
||||
|
||||
if (SelectedPlane != null) {
|
||||
Planes[SelectedPlane].selected = false;
|
||||
Planes[SelectedPlane].clearLines();
|
||||
|
@ -902,31 +1022,92 @@ function selectPlaneByHex(hex,autofollow) {
|
|||
}
|
||||
|
||||
// If we are clicking the same plane, we are deselecting it.
|
||||
// (unless it was a doubleclick..)
|
||||
// (unless it was a doubleclick..)
|
||||
if (SelectedPlane === hex && !autofollow) {
|
||||
hex = null;
|
||||
}
|
||||
hex = null;
|
||||
}
|
||||
|
||||
if (hex !== null) {
|
||||
if (hex !== null) {
|
||||
// Assign the new selected
|
||||
SelectedPlane = hex;
|
||||
Planes[SelectedPlane].selected = true;
|
||||
Planes[SelectedPlane].updateLines();
|
||||
Planes[SelectedPlane].updateMarker();
|
||||
$(Planes[SelectedPlane].tr).addClass("selected");
|
||||
$(Planes[SelectedPlane].tr).addClass("selected");
|
||||
} else {
|
||||
SelectedPlane = null;
|
||||
}
|
||||
|
||||
if (SelectedPlane !== null && autofollow) {
|
||||
FollowSelected = true;
|
||||
if (OLMap.getView().getZoom() < 8)
|
||||
OLMap.getView().setZoom(8);
|
||||
} else {
|
||||
FollowSelected = false;
|
||||
}
|
||||
if (SelectedPlane !== null && autofollow) {
|
||||
FollowSelected = true;
|
||||
if (OLMap.getView().getZoom() < 8)
|
||||
OLMap.getView().setZoom(8);
|
||||
} else {
|
||||
FollowSelected = false;
|
||||
}
|
||||
|
||||
refreshSelected();
|
||||
refreshSelected();
|
||||
}
|
||||
|
||||
// loop through the planes and mark them as selected to show the paths for all planes
|
||||
function selectAllPlanes() {
|
||||
// if all planes are already selected, deselect them all
|
||||
if (SelectedAllPlanes) {
|
||||
deselectAllPlanes();
|
||||
} else {
|
||||
// If SelectedPlane has something in it, clear out the selected
|
||||
if (SelectedPlane != null) {
|
||||
Planes[SelectedPlane].selected = false;
|
||||
Planes[SelectedPlane].clearLines();
|
||||
Planes[SelectedPlane].updateMarker();
|
||||
$(Planes[SelectedPlane].tr).removeClass("selected");
|
||||
}
|
||||
|
||||
SelectedPlane = null;
|
||||
|
||||
for(var key in Planes) {
|
||||
if (Planes[key].visible && !Planes[key].isFiltered()) {
|
||||
Planes[key].selected = true;
|
||||
Planes[key].updateLines();
|
||||
Planes[key].updateMarker();
|
||||
}
|
||||
}
|
||||
SelectedAllPlanes = true;
|
||||
}
|
||||
|
||||
refreshSelected();
|
||||
}
|
||||
|
||||
// on refreshes, try to find new planes and mark them as selected
|
||||
function selectNewPlanes() {
|
||||
if (SelectedAllPlanes) {
|
||||
for (var key in Planes) {
|
||||
if (!Planes[key].visible || Planes[key].isFiltered()) {
|
||||
Planes[key].selected = false;
|
||||
Planes[key].clearLines();
|
||||
Planes[key].updateMarker();
|
||||
} else {
|
||||
if (Planes[key].selected !== true) {
|
||||
Planes[key].selected = true;
|
||||
Planes[key].updateLines();
|
||||
Planes[key].updateMarker();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// deselect all the planes
|
||||
function deselectAllPlanes() {
|
||||
for(var key in Planes) {
|
||||
Planes[key].selected = false;
|
||||
Planes[key].clearLines();
|
||||
Planes[key].updateMarker();
|
||||
$(Planes[key].tr).removeClass("selected");
|
||||
}
|
||||
SelectedPlane = null;
|
||||
SelectedAllPlanes = false;
|
||||
refreshSelected();
|
||||
}
|
||||
|
||||
function toggleFollowSelected() {
|
||||
|
@ -948,3 +1129,269 @@ function resetMap() {
|
|||
|
||||
selectPlaneByHex(null,false);
|
||||
}
|
||||
|
||||
function updateMapSize() {
|
||||
OLMap.updateSize();
|
||||
}
|
||||
|
||||
function toggleSidebarVisibility(e) {
|
||||
e.preventDefault();
|
||||
$("#sidebar_container").toggle();
|
||||
$("#expand_sidebar_button").toggle();
|
||||
$("#toggle_sidebar_button").toggleClass("show_sidebar");
|
||||
$("#toggle_sidebar_button").toggleClass("hide_sidebar");
|
||||
updateMapSize();
|
||||
}
|
||||
|
||||
function expandSidebar(e) {
|
||||
e.preventDefault();
|
||||
$("#map_container").hide()
|
||||
$("#toggle_sidebar_button").hide();
|
||||
$("#splitter").hide();
|
||||
$("#sudo_buttons").hide();
|
||||
$("#show_map_button").show();
|
||||
$("#sidebar_container").width("100%");
|
||||
setColumnVisibility();
|
||||
setSelectedInfoBlockVisibility();
|
||||
updateMapSize();
|
||||
}
|
||||
|
||||
function showMap() {
|
||||
$("#map_container").show()
|
||||
$("#toggle_sidebar_button").show();
|
||||
$("#splitter").show();
|
||||
$("#sudo_buttons").show();
|
||||
$("#show_map_button").hide();
|
||||
$("#sidebar_container").width("470px");
|
||||
setColumnVisibility();
|
||||
setSelectedInfoBlockVisibility();
|
||||
updateMapSize();
|
||||
}
|
||||
|
||||
function showColumn(table, columnId, visible) {
|
||||
var index = $(columnId).index();
|
||||
if (index >= 0) {
|
||||
var cells = $(table).find("td:nth-child(" + (index + 1).toString() + ")");
|
||||
if (visible) {
|
||||
cells.show();
|
||||
} else {
|
||||
cells.hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setColumnVisibility() {
|
||||
var mapIsVisible = $("#map_container").is(":visible");
|
||||
var infoTable = $("#tableinfo");
|
||||
|
||||
showColumn(infoTable, "#registration", !mapIsVisible);
|
||||
showColumn(infoTable, "#aircraft_type", !mapIsVisible);
|
||||
showColumn(infoTable, "#vert_rate", !mapIsVisible);
|
||||
showColumn(infoTable, "#rssi", !mapIsVisible);
|
||||
showColumn(infoTable, "#lat", !mapIsVisible);
|
||||
showColumn(infoTable, "#lon", !mapIsVisible);
|
||||
showColumn(infoTable, "#data_source", !mapIsVisible);
|
||||
showColumn(infoTable, "#airframes_mode_s_link", !mapIsVisible);
|
||||
showColumn(infoTable, "#flightaware_mode_s_link", !mapIsVisible);
|
||||
showColumn(infoTable, "#flightaware_photo_link", !mapIsVisible);
|
||||
}
|
||||
|
||||
function setSelectedInfoBlockVisibility() {
|
||||
var mapIsVisible = $("#map_container").is(":visible");
|
||||
var planeSelected = (typeof SelectedPlane !== 'undefined' && SelectedPlane != null && SelectedPlane != "ICAO");
|
||||
|
||||
if (planeSelected && mapIsVisible) {
|
||||
$('#selected_infoblock').show();
|
||||
}
|
||||
else {
|
||||
$('#selected_infoblock').hide();
|
||||
}
|
||||
}
|
||||
|
||||
// Reposition selected plane info box if it overlaps plane marker
|
||||
function adjustSelectedInfoBlockPosition() {
|
||||
if (typeof Planes === 'undefined' || typeof SelectedPlane === 'undefined' || Planes === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var selectedPlane = Planes[SelectedPlane];
|
||||
|
||||
if (selectedPlane === undefined || selectedPlane === null || selectedPlane.marker === undefined || selectedPlane.marker === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Get marker position
|
||||
var marker = selectedPlane.marker;
|
||||
var markerCoordinates = selectedPlane.marker.getGeometry().getCoordinates();
|
||||
var markerPosition = OLMap.getPixelFromCoordinate(markerCoordinates);
|
||||
|
||||
// Get info box position and size
|
||||
var infoBox = $('#selected_infoblock');
|
||||
var infoBoxPosition = infoBox.position();
|
||||
var infoBoxExtent = getExtent(infoBoxPosition.left, infoBoxPosition.top, infoBox.outerWidth(), infoBox.outerHeight());
|
||||
|
||||
// Get map size
|
||||
var mapCanvas = $('#map_canvas');
|
||||
var mapExtent = getExtent(0, 0, mapCanvas.width(), mapCanvas.height());
|
||||
|
||||
// Check for overlap
|
||||
if (isPointInsideExtent(markerPosition[0], markerPosition[1], infoBoxExtent)) {
|
||||
// Array of possible new positions for info box
|
||||
var candidatePositions = [];
|
||||
candidatePositions.push( { x: 20, y: 20 } );
|
||||
candidatePositions.push( { x: 20, y: markerPosition[1] + 40 } );
|
||||
|
||||
// Find new position
|
||||
for (var i = 0; i < candidatePositions.length; i++) {
|
||||
var candidatePosition = candidatePositions[i];
|
||||
var candidateExtent = getExtent(candidatePosition.x, candidatePosition.y, infoBox.outerWidth(), infoBox.outerHeight());
|
||||
|
||||
if (!isPointInsideExtent(markerPosition[0], markerPosition[1], candidateExtent) && isPointInsideExtent(candidatePosition.x, candidatePosition.y, mapExtent)) {
|
||||
// Found a new position that doesn't overlap marker - move box to that position
|
||||
infoBox.css("left", candidatePosition.x);
|
||||
infoBox.css("top", candidatePosition.y);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(e) { }
|
||||
}
|
||||
|
||||
function getExtent(x, y, width, height) {
|
||||
return {
|
||||
xMin: x,
|
||||
yMin: y,
|
||||
xMax: x + width - 1,
|
||||
yMax: y + height - 1,
|
||||
};
|
||||
}
|
||||
|
||||
function isPointInsideExtent(x, y, extent) {
|
||||
return x >= extent.xMin && x <= extent.xMax && y >= extent.yMin && y <= extent.yMax;
|
||||
}
|
||||
|
||||
function initializeUnitsSelector() {
|
||||
// Get display unit preferences from local storage
|
||||
if (!localStorage.getItem('displayUnits')) {
|
||||
localStorage['displayUnits'] = "nautical";
|
||||
}
|
||||
var displayUnits = localStorage['displayUnits'];
|
||||
DisplayUnits = displayUnits;
|
||||
|
||||
// Initialize drop-down
|
||||
var unitsSelector = $("#units_selector");
|
||||
unitsSelector.val(displayUnits);
|
||||
unitsSelector.on("change", onDisplayUnitsChanged);
|
||||
}
|
||||
|
||||
function onDisplayUnitsChanged(e) {
|
||||
var displayUnits = event.target.value;
|
||||
// Save display units to local storage
|
||||
localStorage['displayUnits'] = displayUnits;
|
||||
DisplayUnits = displayUnits;
|
||||
|
||||
// Update filters
|
||||
updatePlaneFilter();
|
||||
|
||||
// Refresh data
|
||||
refreshTableInfo();
|
||||
refreshSelected();
|
||||
|
||||
// Redraw range rings
|
||||
if (SitePosition !== null && SitePosition !== undefined && SiteCircles) {
|
||||
createSiteCircleFeatures();
|
||||
}
|
||||
|
||||
// Reset map scale line units
|
||||
OLMap.getControls().forEach(function(control) {
|
||||
if (control instanceof ol.control.ScaleLine) {
|
||||
control.setUnits(displayUnits);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function onFilterByAltitude(e) {
|
||||
e.preventDefault();
|
||||
updatePlaneFilter();
|
||||
refreshTableInfo();
|
||||
|
||||
var selectedPlane = Planes[SelectedPlane];
|
||||
if (selectedPlane !== undefined && selectedPlane !== null && selectedPlane.isFiltered()) {
|
||||
SelectedPlane = null;
|
||||
selectedPlane.selected = false;
|
||||
selectedPlane.clearLines();
|
||||
selectedPlane.updateMarker();
|
||||
refreshSelected();
|
||||
}
|
||||
}
|
||||
|
||||
function onResetAltitudeFilter(e) {
|
||||
$("#altitude_filter_min").val("");
|
||||
$("#altitude_filter_max").val("");
|
||||
|
||||
updatePlaneFilter();
|
||||
refreshTableInfo();
|
||||
}
|
||||
|
||||
function updatePlaneFilter() {
|
||||
var minAltitude = parseFloat($("#altitude_filter_min").val().trim());
|
||||
var maxAltitude = parseFloat($("#altitude_filter_max").val().trim());
|
||||
|
||||
if (minAltitude === NaN) {
|
||||
minAltitude = -Infinity;
|
||||
}
|
||||
|
||||
if (maxAltitude === NaN) {
|
||||
maxAltitude = Infinity;
|
||||
}
|
||||
|
||||
PlaneFilter.minAltitude = minAltitude;
|
||||
PlaneFilter.maxAltitude = maxAltitude;
|
||||
PlaneFilter.altitudeUnits = DisplayUnits;
|
||||
}
|
||||
|
||||
function getFlightAwareIdentLink(ident, linkText) {
|
||||
if (ident !== null && ident !== "") {
|
||||
if (!linkText) {
|
||||
linkText = ident;
|
||||
}
|
||||
return "<a target=\"_blank\" href=\"https://flightaware.com/live/flight/" + ident.trim() + "\">" + linkText + "</a>";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
function getFlightAwareModeSLink(code, ident, linkText) {
|
||||
if (code !== null && code.length > 0 && code[0] !== '~' && code !== "000000") {
|
||||
if (!linkText) {
|
||||
linkText = "FlightAware: " + code.toUpperCase();
|
||||
}
|
||||
|
||||
var linkHtml = "<a target=\"_blank\" href=\"https://flightaware.com/live/modes/" + code ;
|
||||
if (ident !== null && ident !== "") {
|
||||
linkHtml += "/ident/" + ident.trim();
|
||||
}
|
||||
linkHtml += "/redirect\">" + linkText + "</a>";
|
||||
return linkHtml;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
function getFlightAwarePhotoLink(registration) {
|
||||
if (registration !== null && registration !== "") {
|
||||
return "<a target=\"_blank\" href=\"https://flightaware.com/photos/aircraft/" + registration.trim() + "\">See Photos</a>";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
function getAirframesModeSLink(code) {
|
||||
if (code !== null && code.length > 0 && code[0] !== '~' && code !== "000000") {
|
||||
return "<a href=\"http://www.airframes.org/\" onclick=\"$('#airframes_post_icao').attr('value','" + code + "'); document.getElementById('horrible_hack').submit.call(document.getElementById('airframes_post')); return false;\">Airframes.org: " + code.toUpperCase() + "</a>";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
|
|
@ -2,10 +2,96 @@ html, body {
|
|||
margin: 0; padding: 0; background-color: #ffffff; font-family: Tahoma, Sans-Serif;
|
||||
font-size: 10pt; overflow: auto; height: 100%;
|
||||
}
|
||||
div#map_container { float: left; width: 100%; height: 100%; }
|
||||
div#map_canvas { height: 100%; margin-right: 420px; }
|
||||
|
||||
div#sidebar_container { float: left; width: 410px; margin-left: -410px; height: 100%; overflow: auto; }
|
||||
#layout_container {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#selected_infoblock {
|
||||
position: absolute;
|
||||
left: 20px;
|
||||
top: 20px;
|
||||
min-width: 360px;
|
||||
padding: 20px;
|
||||
background: #ffffff;
|
||||
box-shadow: 4px 4px 10px #444444;
|
||||
cursor: pointer;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
#map_container {
|
||||
flex: 1 1 auto;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#map_canvas {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#toggle_sidebar_button {
|
||||
display: block;
|
||||
width: 48px;
|
||||
height: 40px;
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
#toggle_sidebar_button.show_sidebar {
|
||||
background-image: url("images/show_sidebar_inactive_48x40.png");
|
||||
}
|
||||
|
||||
#toggle_sidebar_button.show_sidebar:hover {
|
||||
background-image: url("images/show_sidebar_active_48x40.png");
|
||||
}
|
||||
|
||||
#toggle_sidebar_button.hide_sidebar {
|
||||
background-image: url("images/hide_sidebar_inactive_48x40.png");
|
||||
}
|
||||
|
||||
#toggle_sidebar_button.hide_sidebar:hover {
|
||||
background-image: url("images/hide_sidebar_active_48x40.png");
|
||||
}
|
||||
|
||||
#expand_sidebar_button {
|
||||
display: block;
|
||||
width: 48px;
|
||||
height: 40px;
|
||||
position: absolute;
|
||||
top: 56px;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
#expand_sidebar_button {
|
||||
background-image: url("images/show_sidebar_inactive_48x40.png");
|
||||
}
|
||||
|
||||
#expand_sidebar_button:hover {
|
||||
background-image: url("images/show_sidebar_active_48x40.png");
|
||||
}
|
||||
|
||||
#sidebar_container {
|
||||
display: flex;
|
||||
width: 470px;
|
||||
left: 0 !important;
|
||||
}
|
||||
|
||||
#splitter {
|
||||
flex: 0 0 6px;
|
||||
cursor: col-resize;
|
||||
background-color: #bbbbbb;
|
||||
left: 0 !important;
|
||||
}
|
||||
|
||||
#sidebar_canvas {
|
||||
flex: 1 1 auto;
|
||||
padding: 10px;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
div#SpecialSquawkWarning { position: absolute; bottom: 25px; right: 430px; border: 2px solid red;
|
||||
background-color: #FFFFA3; opacity: 0.75; filter:alpha(opacity=75); padding: 5px;
|
||||
|
@ -19,10 +105,37 @@ div#loader { z-index: 99; position: absolute; left: 0; top: 0; bottom: 0; right:
|
|||
#spinny { width: 128px; height: 128px; position: absolute; top: 50%; left: 50%; margin: -64px 0 0 -64px; }
|
||||
#loader_progress { width: 250px; height: 20px; position: absolute; top: 50%; left: 50%; margin: 128px 0 0 -125px; }
|
||||
|
||||
#tableinfo, #sudo_buttons { font-size: x-small; font-family: monospace; }
|
||||
#tableinfo { font-size: small; }
|
||||
|
||||
.vPosition { font-weight: bold; background-color: #d5ffd5; }
|
||||
.mlat { font-weight: bold; background-color: #d5d5ff; }
|
||||
#sudo_buttons {
|
||||
display: flex;
|
||||
padding: 15px 40px 15px 40px;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#units_container,
|
||||
#altitude_filter_form {
|
||||
font-size: small;
|
||||
margin: 10px 0 10px 0;
|
||||
}
|
||||
|
||||
.aircraft_table_header {
|
||||
background-color: #409EDF;
|
||||
color: #FFFFFF;
|
||||
cursor: pointer;
|
||||
}
|
||||
.aircraft_table_header td {
|
||||
font-size: smaller;
|
||||
padding: 5px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.verticalRateTriangle {
|
||||
font-family: "Courier New",monospace;
|
||||
}
|
||||
|
||||
.vPosition { background-color: #C3FFDF; }
|
||||
.mlat { background-color: #C7EAFC; }
|
||||
.squawk7500 { font-weight: bold; background-color: #ff5555; }
|
||||
.squawk7600 { font-weight: bold; background-color: #00ffff; }
|
||||
.squawk7700 { font-weight: bold; background-color: #ffff00; }
|
||||
|
@ -42,3 +155,33 @@ div#loader { z-index: 99; position: absolute; left: 0; top: 0; bottom: 0; right:
|
|||
|
||||
.pointer { cursor: pointer; }
|
||||
|
||||
.sidebarButton {
|
||||
background-color: #409EDF;
|
||||
padding: 4px 15px 4px 15px;
|
||||
color: #FFFFFF;
|
||||
font-weight: normal;
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
.sidebarButton:hover {
|
||||
background-color: #3c6ea3;
|
||||
}
|
||||
|
||||
.altitudeFilterInput {
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
select.error, textarea.error, input.error {
|
||||
color: #FF0000;
|
||||
}
|
||||
|
||||
.ol-zoom {
|
||||
left: auto !important;
|
||||
right: 20px !important;
|
||||
top: 120px !important;
|
||||
}
|
||||
|
||||
.layer-switcher {
|
||||
top: 190px !important;
|
||||
right: 10px !important;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue