Add ability to switch display units

This commit is contained in:
Carlos Salaverria 2016-08-22 16:48:17 -05:00
parent c99375d51c
commit 96fe1e0ee5
5 changed files with 183 additions and 89 deletions

View file

@ -11,14 +11,11 @@ PlaneCountInTitle = true;
MessageRateInTitle = false; MessageRateInTitle = false;
// -- Output Settings ------------------------------------- // -- Output Settings -------------------------------------
// Show metric values // The DisplayUnits setting controls whether nautical (ft, NM, knots),
// The Metric setting controls whether metric (m, km, km/h) or // metric (m, km, km/h) or imperial (ft, mi, mph) units are used in the
// imperial (ft, NM, knots) units are used in the plane table // plane table and in the detailed plane info. Valid values are
// and in the detailed plane info. If ShowOtherUnits is true, // "nautical", "metric", or "imperial".
// then the other unit will also be shown in the detailed plane DisplayUnits = "nautical";
// info.
Metric = false;
ShowOtherUnits = true;
// -- Map settings ---------------------------------------- // -- Map settings ----------------------------------------
// These settings are overridden by any position information // These settings are overridden by any position information
@ -98,7 +95,7 @@ OutlineADSBColor = '#000000';
OutlineMlatColor = '#4040FF'; OutlineMlatColor = '#4040FF';
SiteCircles = true; // true to show circles (only shown if the center marker is shown) 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); 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 // Show the clocks at the top of the righthand pane? You can disable the clocks if you want here

View file

@ -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 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 // 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) // track in degrees (0..359)
function format_track_brief(track) { function format_track_brief(track) {
if (track === null){ if (track === null){
@ -31,7 +46,7 @@ function format_track_long(track) {
// altitude (input: alt in feet) // altitude (input: alt in feet)
// brief will always show either Metric or Imperial // brief will always show either Metric or Imperial
function format_altitude_brief(alt, vr) { function format_altitude_brief(alt, vr, displayUnits) {
var alt_text; var alt_text;
if (alt === null){ if (alt === null){
@ -40,7 +55,7 @@ function format_altitude_brief(alt, vr) {
return "ground"; return "ground";
} }
if (Metric) { if (displayUnits === "metric") {
alt_text = Math.round(alt / 3.2828) + NBSP; // Altitude to meters alt_text = Math.round(alt / 3.2828) + NBSP; // Altitude to meters
} else { } else {
alt_text = Math.round(alt) + NBSP; alt_text = Math.round(alt) + NBSP;
@ -57,14 +72,16 @@ function format_altitude_brief(alt, vr) {
} }
// alt in ft // alt in ft
function _alt_to_unit(alt, m) { function _alt_to_unit(alt, displayUnits) {
if (m) var unitLabel = get_unit_label("altitude", displayUnits);
return Math.round(alt / 3.2828) + NBSP + "m";
if (displayUnits === "metric")
return Math.round(alt / 3.2828) + NBSP + unitLabel;
else else
return Math.round(alt) + NBSP + "ft"; return Math.round(alt) + NBSP + unitLabel;
} }
function format_altitude_long(alt, vr) { function format_altitude_long(alt, vr, displayUnits) {
var alt_text = ""; var alt_text = "";
if (alt === null) { if (alt === null) {
@ -73,13 +90,7 @@ function format_altitude_long(alt, vr) {
return "on ground"; return "on ground";
} }
// Primary unit alt_text = _alt_to_unit(alt, displayUnits);
alt_text = _alt_to_unit(alt, Metric);
// Secondary unit
if (ShowOtherUnits) {
alt_text = alt_text + ' | ' + _alt_to_unit(alt, !Metric);
}
if (vr > 128) { if (vr > 128) {
return UP_TRIANGLE + NBSP + alt_text; return UP_TRIANGLE + NBSP + alt_text;
@ -91,13 +102,15 @@ function format_altitude_long(alt, vr) {
} }
//input: speed in kts //input: speed in kts
function format_speed_brief(speed) { function format_speed_brief(speed, displayUnits) {
if (speed === null) { if (speed === null) {
return ""; return "";
} }
if (Metric) { if (displayUnits === "metric") {
return Math.round(speed * 1.852); // knots to kilometers per hour return Math.round(speed * 1.852); // knots to kilometers per hour
} else if (displayUnits === "imperial") {
return Math.round(speed * 1.151); // knots to miles per hour
} else { } else {
return Math.round(speed); // knots return Math.round(speed); // knots
} }
@ -105,67 +118,78 @@ function format_speed_brief(speed) {
// speed in kts // speed in kts
function _speed_to_unit(speed, m) { function _speed_to_unit(speed, displayUnits) {
if (m) var unitLabel = get_unit_label("speed", displayUnits);
return Math.round(speed * 1.852) + NBSP + "km/h";
if (displayUnits === "metric")
return Math.round(speed * 1.852) + NBSP + unitLabel;
else if (displayUnits === "imperial")
return Math.round(speed * 1.151) + NBSP + unitLabel;
else else
return Math.round(speed) + NBSP + "kt"; return Math.round(speed) + NBSP + unitLabel;
} }
function format_speed_long(speed) { function format_speed_long(speed, displayUnits) {
if (speed === null) { if (speed === null) {
return "n/a"; return "n/a";
} }
// Primary unit var speed_text = _speed_to_unit(speed, displayUnits);
var speed_text = _speed_to_unit(speed, Metric);
// Secondary unit
if (ShowOtherUnits) {
speed_text = speed_text + ' | ' + _speed_to_unit(speed, !Metric);
}
return speed_text; return speed_text;
} }
// dist in meters // dist in meters
function format_distance_brief(dist) { function format_distance_brief(dist, displayUnits) {
if (dist === null) { if (dist === null) {
return ""; return "";
} }
if (Metric) { if (displayUnits === "metric") {
return (dist/1000).toFixed(1); // meters to kilometers return (dist/1000).toFixed(1); // meters to kilometers
} else if (displayUnits === "imperial") {
return (dist/1609).toFixed(1); // meters to miles
} else { } else {
return (dist/1852).toFixed(1); // meters to nautocal miles return (dist/1852).toFixed(1); // meters to nautical miles
} }
} }
// dist in metres // dist in metres
function _dist_to_unit(dist, m) { function _dist_to_unit(dist, displayUnits) {
if (m) var unitLabel = get_unit_label("distance", displayUnits);
return (dist/1000).toFixed(1) + NBSP + "km";
if (displayUnits === "metric")
return (dist/1000).toFixed(1) + NBSP + unitLabel;
else if (displayUnits === "imperial")
return (dist/1609).toFixed(1) + NBSP + unitLabel;
else else
return (dist/1852).toFixed(1) + NBSP + "NM"; return (dist/1852).toFixed(1) + NBSP + unitLabel;
} }
function format_distance_long(dist) { function format_distance_long(dist, displayUnits) {
if (dist === null) { if (dist === null) {
return "n/a"; return "n/a";
} }
// Primary unit var dist_text = _dist_to_unit(dist, displayUnits);
var dist_text = _dist_to_unit(dist, Metric);
// Secondary unit
if (ShowOtherUnits) {
dist_text = dist_text + ' | ' + _dist_to_unit(dist, !Metric);
}
return dist_text; return dist_text;
} }
// rate in ft/min
function format_vert_rate_brief(rate, displayUnits) {
if (rate === null) {
return "";
}
if (displayUnits === "metric") {
return (rate/196.85).toFixed(1); // ft/min to m/s
} else {
return Math.round(rate);
}
}
// p is a [lon, lat] coordinate // p is a [lon, lat] coordinate
function format_latlng(p) { function format_latlng(p) {
return p[1].toFixed(3) + DEGREES + "," + NBSP + p[0].toFixed(3) + DEGREES; return p[1].toFixed(3) + DEGREES + "," + NBSP + p[0].toFixed(3) + DEGREES;

View file

@ -160,6 +160,15 @@
</table> </table>
</div> <!-- selected_infoblock --> </div> <!-- selected_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>
<div id="planes_table"> <div id="planes_table">
<table id="tableinfo" style="width: 100%"> <table id="tableinfo" style="width: 100%">
<thead style="background-color: #BBBBBB; cursor: pointer;"> <thead style="background-color: #BBBBBB; cursor: pointer;">
@ -170,10 +179,10 @@
<td id="registration" onclick="sortByRegistration();">Registration</td> <td id="registration" onclick="sortByRegistration();">Registration</td>
<td id="aircraft_type" onclick="sortByAircraftType();"> Aircraft type</td> <td id="aircraft_type" onclick="sortByAircraftType();"> Aircraft type</td>
<td id="squawk" onclick="sortBySquawk();" style="text-align: right">Squawk</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="altitude" onclick="sortByAltitude();" style="text-align: right">Altitude (<span id="header_altitude_unit"></span>)</td>
<td id="speed" onclick="sortBySpeed();" style="text-align: right">Speed</td> <td id="speed" onclick="sortBySpeed();" style="text-align: right">Speed (<span id="header_speed_unit"></span>)</td>
<td id="vert_rate" onclick="sortByVerticalRate();" style="text-align: right">Vertical Rate</td> <td id="vert_rate" onclick="sortByVerticalRate();" style="text-align: right">Vertical Rate (<span id="header_vert_rate_unit"></span>)</td>
<td id="distance" onclick="sortByDistance();" style="text-align: right">Distance</td> <td id="distance" onclick="sortByDistance();" style="text-align: right">Distance (<span id="header_distance_unit"></span>)</td>
<td id="track" onclick="sortByTrack();" style="text-align: right">Track</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="msgs" onclick="sortByMsgs();" style="text-align: right">Msgs</td>
<td id="seen" onclick="sortBySeen();" style="text-align: right">Age</td> <td id="seen" onclick="sortBySeen();" style="text-align: right">Age</td>

View file

@ -4,6 +4,7 @@
// Define our global variables // Define our global variables
var OLMap = null; var OLMap = null;
var StaticFeatures = new ol.Collection(); var StaticFeatures = new ol.Collection();
var SiteCircleFeatures = new ol.Collection();
var PlaneIconFeatures = new ol.Collection(); var PlaneIconFeatures = new ol.Collection();
var PlaneTrailFeatures = new ol.Collection(); var PlaneTrailFeatures = new ol.Collection();
var Planes = {}; var Planes = {};
@ -222,6 +223,9 @@ function initialize() {
$("#show_map_button").hide(); $("#show_map_button").hide();
setColumnVisibility(); setColumnVisibility();
// Initialize other controls
initializeUnitsSelector();
// Force map to redraw if sidebar container is resized - use a timer to debounce // Force map to redraw if sidebar container is resized - use a timer to debounce
var mapResizeTimeout; var mapResizeTimeout;
$("#sidebar_container").on("resize", function() { $("#sidebar_container").on("resize", function() {
@ -470,7 +474,7 @@ function initialize_map() {
controls: [new ol.control.Zoom(), controls: [new ol.control.Zoom(),
new ol.control.Rotate(), new ol.control.Rotate(),
new ol.control.Attribution({collapsed: false}), new ol.control.Attribution({collapsed: false}),
new ol.control.ScaleLine({units: Metric ? "metric" : "nautical"}), new ol.control.ScaleLine({units: DisplayUnits}),
new ol.control.LayerSwitcher() new ol.control.LayerSwitcher()
], ],
loadTilesWhileAnimating: true, loadTilesWhileAnimating: true,
@ -531,26 +535,7 @@ function initialize_map() {
StaticFeatures.push(feature); StaticFeatures.push(feature);
if (SiteCircles) { if (SiteCircles) {
var circleStyle = new ol.style.Style({ createSiteCircleFeatures();
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);
}
} }
} }
@ -604,6 +589,39 @@ 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 // This looks for planes to reap out of the master Planes variable
function reaper() { function reaper() {
//console.log("Reaping started.."); //console.log("Reaping started..");
@ -716,7 +734,7 @@ function refreshSelected() {
emerg.className = 'hidden'; 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') { if (selected.squawk === null || selected.squawk === '0000') {
$('#selected_squawk').text('n/a'); $('#selected_squawk').text('n/a');
@ -724,7 +742,7 @@ function refreshSelected() {
$('#selected_squawk').text(selected.squawk); $('#selected_squawk').text(selected.squawk);
} }
$('#selected_speed').text(format_speed_long(selected.speed)); $('#selected_speed').text(format_speed_long(selected.speed, DisplayUnits));
$('#selected_icao').text(selected.icao.toUpperCase()); $('#selected_icao').text(selected.icao.toUpperCase());
$('#airframes_post_icao').attr('value',selected.icao); $('#airframes_post_icao').attr('value',selected.icao);
$('#selected_track').text(format_track_long(selected.track)); $('#selected_track').text(format_track_long(selected.track));
@ -763,7 +781,7 @@ 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_rssi').text(selected.rssi.toFixed(1) + ' dBFS');
} }
@ -804,18 +822,23 @@ function refreshTableInfo() {
tableplane.tr.cells[3].textContent = (tableplane.registration !== null ? tableplane.registration : ""); tableplane.tr.cells[3].textContent = (tableplane.registration !== null ? tableplane.registration : "");
tableplane.tr.cells[4].textContent = (tableplane.icaotype !== null ? tableplane.icaotype : ""); tableplane.tr.cells[4].textContent = (tableplane.icaotype !== null ? tableplane.icaotype : "");
tableplane.tr.cells[5].textContent = (tableplane.squawk !== null ? tableplane.squawk : ""); tableplane.tr.cells[5].textContent = (tableplane.squawk !== null ? tableplane.squawk : "");
tableplane.tr.cells[6].textContent = format_altitude_brief(tableplane.altitude, tableplane.vert_rate); tableplane.tr.cells[6].textContent = format_altitude_brief(tableplane.altitude, tableplane.vert_rate, DisplayUnits);
tableplane.tr.cells[7].textContent = format_speed_brief(tableplane.speed); tableplane.tr.cells[7].textContent = format_speed_brief(tableplane.speed, DisplayUnits);
tableplane.tr.cells[8].textContent = (tableplane.vert_rate !== null ? tableplane.vert_rate : ""); tableplane.tr.cells[8].textContent = format_vert_rate_brief(tableplane.vert_rate, DisplayUnits);
tableplane.tr.cells[9].textContent = format_distance_brief(tableplane.sitedist); tableplane.tr.cells[9].textContent = format_distance_brief(tableplane.sitedist, DisplayUnits);
tableplane.tr.cells[10].textContent = format_track_brief(tableplane.track); tableplane.tr.cells[10].textContent = format_track_brief(tableplane.track);
tableplane.tr.cells[11].textContent = tableplane.messages; tableplane.tr.cells[11].textContent = tableplane.messages;
tableplane.tr.cells[12].textContent = tableplane.seen.toFixed(0); tableplane.tr.cells[12].textContent = tableplane.seen.toFixed(0);
tableplane.tr.cells[13].textContent = (tableplane.rssi !== null ? tableplane.rssi : ""); tableplane.tr.cells[13].textContent = (tableplane.rssi !== null ? tableplane.rssi : "");
tableplane.tr.cells[14].textContent = (tableplane.position !== null ? tableplane.position[1] : ""); tableplane.tr.cells[14].textContent = (tableplane.position !== null ? tableplane.position[1].toFixed(4) : "");
tableplane.tr.cells[15].textContent = (tableplane.position !== null ? tableplane.position[0] : ""); 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[16].textContent = format_data_source(tableplane.getDataSource());
tableplane.tr.className = classes; tableplane.tr.className = classes;
$("#header_altitude_unit").text(get_unit_label("altitude", DisplayUnits));
$("#header_speed_unit").text(get_unit_label("speed", DisplayUnits));
$("#header_distance_unit").text(get_unit_label("distance", DisplayUnits));
$("#header_vert_rate_unit").text(get_unit_label("verticalRate", DisplayUnits));
} }
} }
@ -1073,7 +1096,7 @@ function showMap() {
$("#splitter").show(); $("#splitter").show();
$("#sudo_buttons").show(); $("#sudo_buttons").show();
$("#show_map_button").hide(); $("#show_map_button").hide();
$("#sidebar_container").width("410px"); $("#sidebar_container").width("420px");
setColumnVisibility(); setColumnVisibility();
updateMapSize(); updateMapSize();
} }
@ -1102,3 +1125,40 @@ function setColumnVisibility() {
showColumn(infoTable, "#lon", !mapIsVisible); showColumn(infoTable, "#lon", !mapIsVisible);
showColumn(infoTable, "#data_source", !mapIsVisible); showColumn(infoTable, "#data_source", !mapIsVisible);
} }
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;
// Refresh data
refreshTableInfo();
refreshSelected();
// Redraw range rings
if (SiteCircleFeatures) {
createSiteCircleFeatures();
}
// Reset map scale line units
OLMap.getControls().forEach(function(control) {
if (control instanceof ol.control.ScaleLine) {
control.setUnits(displayUnits);
}
});
}

View file

@ -78,7 +78,7 @@ html, body {
#sidebar_container { #sidebar_container {
display: flex; display: flex;
width: 410px; width: 420px;
left: 0 !important; left: 0 !important;
} }
@ -108,6 +108,10 @@ div#loader { z-index: 99; position: absolute; left: 0; top: 0; bottom: 0; right:
#tableinfo, #sudo_buttons { font-size: x-small; font-family: monospace; } #tableinfo, #sudo_buttons { font-size: x-small; font-family: monospace; }
#units_selector {
margin: 10px 0 10px 0;
}
.vPosition { font-weight: bold; background-color: #d5ffd5; } .vPosition { font-weight: bold; background-color: #d5ffd5; }
.mlat { font-weight: bold; background-color: #d5d5ff; } .mlat { font-weight: bold; background-color: #d5d5ff; }
.squawk7500 { font-weight: bold; background-color: #ff5555; } .squawk7500 { font-weight: bold; background-color: #ff5555; }