Phi: some cleanup and a airport chart
- fix a cornercase bug in the RouteLayer - some cleanup in the map widget - add a airport chart as a start for a reposition dialog
This commit is contained in:
parent
f9923979b5
commit
c68f3f5cc9
4 changed files with 256 additions and 7 deletions
68
webgui/topics/Environment/Position.html
Normal file
68
webgui/topics/Environment/Position.html
Normal file
|
@ -0,0 +1,68 @@
|
|||
<style>
|
||||
|
||||
</style>
|
||||
<fieldset data-bind="visible: hasAirports">
|
||||
<legend>Airports</legend>
|
||||
<input type="text" data-bind="autocomplete: { source: airports, select: onSelect }" style="width: 100%;">
|
||||
</fieldset>
|
||||
|
||||
<div style="width=100%" data-bind="with: selectedAirport">
|
||||
<div style="float: left;">
|
||||
<div style="font-size: 20pt; font-weight: bold;" data-bind="text: id"></div>
|
||||
<div>
|
||||
<span style="font-size: 12pt; font-weight: normal;">Apt Elev </span>
|
||||
<span style="font-size: 14pt; font-weight: bold;" data-bind="text: elevation"></span>
|
||||
<span style="font-size: 14pt; font-weight: bold;">'</span>
|
||||
</div>
|
||||
<div>
|
||||
<span style="font-size: 12pt; font-weight: normal;" data-bind="text: arpFormatted"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="float: right;">
|
||||
<div>
|
||||
<!--
|
||||
<span style="font-size: 20pt; font-weight: bold;" data-bind="text: city"></span>
|
||||
<span style="font-size: 20pt; font-weight: bold;">, </span>
|
||||
<span style="font-size: 20pt; font-weight: bold;" data-bind="text: country"></span>
|
||||
-->
|
||||
</div>
|
||||
<div>
|
||||
<span style="font-size: 14pt; font-weight: normal; float: right" data-bind="text: name"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui-helper-clearfix"></div>
|
||||
|
||||
<fieldset data-bind="with: selectedAirport">
|
||||
<legend>Communication</legend>
|
||||
<table style="width: 100%">
|
||||
<tr data-bind="foreach: comm">
|
||||
<td>
|
||||
<div data-bind="text: name" style="text-align: center"></div>
|
||||
<div data-bind="foreach: frequencies" style="text-align: center">
|
||||
<span data-bind="text: $data"></span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
<div id="phi-environment-position-map" style="height: 400px;"></div>
|
||||
</fieldset>
|
||||
|
||||
<fieldset data-bind="with: selectedAirport">
|
||||
<legend>Runway Information</legend>
|
||||
<table style="width: 100%" data-bind="foreach: runway">
|
||||
<tr>
|
||||
<td><span data-bind="text: id"></span></td>
|
||||
<td><span data-bind="text: heading"></span>°</td>
|
||||
<td><span data-bind="text: surface"></span></td>
|
||||
<td><span data-bind="text: lengthFt"></span>ft <span data-bind="text: lengthM"></span>m</td>
|
||||
<td><span data-bind="text: widthFt"></span>ft <span data-bind="text: widthM"></span>m</td>
|
||||
<td><span data-bind="text: displacedThresholdFt"></span>ft <span data-bind="text: displacedThresholdM"></span>m</td>
|
||||
<td><span data-bind="text: stopwayFt"></span>ft <span data-bind="text: stopwayM"></span>m</td>
|
||||
</tr>
|
||||
</table>
|
||||
</fieldset>
|
||||
|
180
webgui/topics/Environment/Position.js
Normal file
180
webgui/topics/Environment/Position.js
Normal file
|
@ -0,0 +1,180 @@
|
|||
define([
|
||||
'jquery', 'knockout', 'text!./Position.html', 'sprintf', 'leaflet', 'kojqui/autocomplete'
|
||||
], function( jquery, ko, htmlString, sprintf, leaflet ) {
|
||||
|
||||
function getAirportList(obs) {
|
||||
if(typeof(Storage) !== "undefined") {
|
||||
var storedList = sessionStorage.getItem("phiPositionAirportlist");
|
||||
if( storedList ) {
|
||||
obs(JSON.parse(storedList));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// get airport list only once
|
||||
jquery.get("/navdb?q=airports").done(function(data) {
|
||||
sessionStorage.setItem("phiPositionAirportlist",JSON.stringify(data));
|
||||
obs(data);
|
||||
}).fail(function() {
|
||||
}).always(function() {
|
||||
});
|
||||
}
|
||||
|
||||
function getAirportId( txt ) {
|
||||
var end = txt.lastIndexOf(')');
|
||||
if( end < 0 ) return "";
|
||||
var start = txt.lastIndexOf('(', end );
|
||||
if( start < 0 ) return "";
|
||||
return txt.substr(start+1,end-start-1);
|
||||
}
|
||||
|
||||
function RunwayViewModel(rwy) {
|
||||
var self = this;
|
||||
self.id = ko.observable(rwy.id);
|
||||
self.heading = ko.observable(Number(rwy.heading_deg||0).toFixed(0));
|
||||
|
||||
self.lengthM = ko.observable(Number(rwy.length_m||0).toFixed(0));
|
||||
self.lengthFt = ko.pureComputed(function(){
|
||||
return (self.lengthM()/0.3048).toFixed(0);
|
||||
});
|
||||
|
||||
self.widthM = ko.observable(Number(rwy.width_m||0).toFixed(0));
|
||||
self.widthFt = ko.pureComputed(function(){
|
||||
return (self.widthM()/0.3048).toFixed(0);
|
||||
});
|
||||
|
||||
self.displacedThresholdM = ko.observable(Number(rwy.dispacedThreshold_m||0).toFixed(0));
|
||||
self.displacedThresholdFt = ko.pureComputed(function(){
|
||||
return (self.displacedThresholdM()/0.3048).toFixed(0);
|
||||
});
|
||||
|
||||
self.stopwayM = ko.observable(Number(rwy.stopway_m||0).toFixed(0));
|
||||
self.stopwayFt = ko.pureComputed(function(){
|
||||
return (self.stopwayM()/0.3048).toFixed(0);
|
||||
});
|
||||
|
||||
self.surface = ko.observable(rwy.surface);
|
||||
}
|
||||
|
||||
function AirportViewModel(geoJson, id) {
|
||||
var self = this;
|
||||
self.geoJson = geoJson;
|
||||
|
||||
jquery.get("/navdb?q=airport&id=" + id ).done(function(data) {
|
||||
// expect geoJSON FeatureCollection
|
||||
if( "FeatureCollection" !== data.type )
|
||||
return;
|
||||
|
||||
// expect one feature
|
||||
if( !(data.features && data.features.length == 1) )
|
||||
return;
|
||||
|
||||
var airport = data.features[0];
|
||||
|
||||
var rwy = self.runway();
|
||||
airport.properties.runways.forEach(function(r){
|
||||
rwy.push( new RunwayViewModel(r));
|
||||
});
|
||||
self.runway(rwy);
|
||||
|
||||
self.id(airport.properties.id);
|
||||
self.name(airport.properties.name);
|
||||
self.city(airport.properties.name);
|
||||
self.country(airport.properties.name);
|
||||
|
||||
var comm = {};
|
||||
airport.properties.comm.forEach(function(c){
|
||||
var f = comm[c.id] || [];
|
||||
f.push( c.mhz );
|
||||
comm[c.id] = f;
|
||||
});
|
||||
var a = [];
|
||||
for( var id in comm ) {
|
||||
a.push({ name: id, frequencies: comm[id]} );
|
||||
}
|
||||
self.comm(a);
|
||||
|
||||
var arp = airport.geometry.geometries[0].coordinates;
|
||||
self.elevation((Number(arp[2]||0)/0.3048).toFixed(0));
|
||||
self.longitude(Number(arp[0]||0));
|
||||
self.latitude(Number(arp[1]||0));
|
||||
|
||||
self.geoJson.clearLayers();
|
||||
self.geoJson.addData(airport);
|
||||
self.geoJson._map.setView([ self.latitude(), self.longitude() ], 13);
|
||||
});
|
||||
|
||||
self.id = ko.observable('');
|
||||
self.name = ko.observable('');
|
||||
self.city = ko.observable('');
|
||||
self.country = ko.observable('');
|
||||
self.elevation = ko.observable(0);
|
||||
self.longitude = ko.observable(0);
|
||||
self.latitude = ko.observable(0);
|
||||
self.arpFormatted = ko.pureComputed(function() {
|
||||
function dm(v) {
|
||||
var s = v < 0;
|
||||
if( s ) v = -v;
|
||||
var d = v|0;
|
||||
return {
|
||||
's': s,
|
||||
'd': d,
|
||||
'm': (v-d)*60,
|
||||
}
|
||||
}
|
||||
|
||||
var lat = dm(self.latitude());
|
||||
var lon = dm(self.longitude());
|
||||
return sprintf.sprintf("%s%02d %3.1f %s%03d %3.1f",
|
||||
lat.s ? 'S' : 'N', lat.d, lat.m, lon.s ? 'W' : 'E', lon.d, lon.m );
|
||||
});
|
||||
|
||||
self.comm = ko.observableArray([]);
|
||||
self.runway = ko.observableArray([]);
|
||||
}
|
||||
|
||||
function ViewModel(params) {
|
||||
var self = this;
|
||||
|
||||
self.map = leaflet.map("phi-environment-position-map", {
|
||||
dragging: false,
|
||||
touchZoom: false,
|
||||
scrollWheelZoom: false,
|
||||
});
|
||||
self.geoJson = leaflet.geoJson(null,{
|
||||
style : function(feature) {
|
||||
return {
|
||||
color : 'black',
|
||||
weight : 3,
|
||||
fill : 'true',
|
||||
fillColor : '#606060',
|
||||
fillOpacity : 1.0,
|
||||
lineJoin : 'bevel',
|
||||
};
|
||||
}
|
||||
});
|
||||
self.geoJson._map = self.map;
|
||||
self.geoJson.addTo(self.map);
|
||||
|
||||
self.airports = ko.observableArray([]);
|
||||
getAirportList(self.airports);
|
||||
self.hasAirports = ko.pureComputed(function() {
|
||||
return self.airports().length;
|
||||
});
|
||||
|
||||
self.selectedAirport = ko.observable();
|
||||
|
||||
self.onSelect = function(ev,ui) {
|
||||
self.selectedAirport(new AirportViewModel(self.geoJson,getAirportId(ui.item.value)));
|
||||
}
|
||||
}
|
||||
|
||||
ViewModel.prototype.dispose = function() {
|
||||
}
|
||||
|
||||
// Return component definition
|
||||
return {
|
||||
viewModel : ViewModel,
|
||||
template : htmlString
|
||||
};
|
||||
});
|
|
@ -14,7 +14,6 @@
|
|||
options : {
|
||||
|
||||
style : function(feature) {
|
||||
console.log(this,feature);
|
||||
if (feature.geometry.type == "LineString")
|
||||
return {
|
||||
'color' : '#4d56db',
|
||||
|
@ -43,8 +42,10 @@
|
|||
},
|
||||
|
||||
stop : function() {
|
||||
this.waypointCountSubscription.dispose();
|
||||
this.waypointCount.dispose();
|
||||
if (this.waypointCountSubscription) {
|
||||
this.waypointCountSubscription.dispose();
|
||||
this.waypointCount.dispose();
|
||||
}
|
||||
},
|
||||
|
||||
update : function(id) {
|
||||
|
@ -107,4 +108,4 @@
|
|||
return new leaflet.RouteLayer(null, options);
|
||||
}
|
||||
|
||||
}));
|
||||
}));
|
||||
|
|
|
@ -28,11 +28,11 @@ define(
|
|||
|
||||
if (params && params.css) {
|
||||
for ( var p in params.css) {
|
||||
$(self.element).css(p, params.css[p]);
|
||||
jquery(self.element).css(p, params.css[p]);
|
||||
}
|
||||
}
|
||||
if ($(self.element).height() < 1) {
|
||||
$(self.element).css("min-height", $(self.element).width());
|
||||
if (jquery(self.element).height() < 1) {
|
||||
jquery(self.element).css("min-height", jquery(self.element).width());
|
||||
}
|
||||
|
||||
var MapOptions = {
|
||||
|
|
Loading…
Reference in a new issue