From 2812cc63213f090005afdb395d05a56b2e4b9deb Mon Sep 17 00:00:00 2001 From: Torsten Dreyer Date: Thu, 30 Jul 2015 21:03:06 +0200 Subject: [PATCH] Phi: refactor some map marker - better aircraft marker symbol - aircraft symbol loaded from file, no longer hardcoded - marker as knockout component --- Phi/images/aircraft.svg | 9 +- Phi/main.js | 4 + Phi/topics/Map/AILayer.js | 52 ++++++------ Phi/topics/Map/NavdbLayer.js | 2 +- Phi/widgets/AircraftMarker.html | 24 ++++++ Phi/widgets/AircraftMarker.js | 41 ++++++++++ Phi/widgets/map.html | 34 +++----- Phi/widgets/map.js | 141 +++++++++++--------------------- 8 files changed, 168 insertions(+), 139 deletions(-) create mode 100644 Phi/widgets/AircraftMarker.html create mode 100644 Phi/widgets/AircraftMarker.js diff --git a/Phi/images/aircraft.svg b/Phi/images/aircraft.svg index bf39266e3..c214e5965 100644 --- a/Phi/images/aircraft.svg +++ b/Phi/images/aircraft.svg @@ -1,4 +1,11 @@ - + + + + + + + + diff --git a/Phi/main.js b/Phi/main.js index 96a4940b3..fd286aa91 100644 --- a/Phi/main.js +++ b/Phi/main.js @@ -454,6 +454,10 @@ require([ require : 'widgets/radiostack' }); + ko.components.register('AircraftMarker', { + require : 'widgets/AircraftMarker' + }); + ko.components.register('METAR', { require : 'widgets/metar' }); diff --git a/Phi/topics/Map/AILayer.js b/Phi/topics/Map/AILayer.js index 884a65f07..0f3eb2ceb 100644 --- a/Phi/topics/Map/AILayer.js +++ b/Phi/topics/Map/AILayer.js @@ -2,13 +2,20 @@ if (typeof define === "function" && define.amd) { // AMD. Register as an anonymous module. define([ - 'leaflet', 'props', './MapIcons' + 'knockout', 'leaflet', 'props' ], factory); } else { // Browser globals factory(); } -}(function(leaflet, SGPropertyNode, MAP_ICON) { +}(function(ko, leaflet, SGPropertyNode ) { + + function ViewModel(h,l1,l2) { + var self = this; + + self.heading = h; + self.labelLines = [ l1,l2 ]; + } leaflet.AILayer = leaflet.GeoJSON.extend({ options : { @@ -20,27 +27,22 @@ }; if (feature.properties.type == "aircraft" || feature.properties.type == "multiplayer") { - options.angle = feature.properties.heading; - options.icon = MAP_ICON["aircraft"]; - } - return new leaflet.RotatedMarker(latlng, options); - }, - - onEachFeature : function(feature, layer) { - if (feature.properties) { - var popupString = ''; - layer.bindPopup(popupString, { - maxHeight : 200 - }); + var l1 = feature.properties.callsign, + l2 = feature.properties.heading + 'T ' + feature.properties.speed + 'KTAS ' + + 'F' + (feature.geometry.coordinates[2]/100).toFixed(0); + var m = L.aircraftMarker(latlng); + m.on('add', function(e) { + ko.applyBindings( new ViewModel(feature.properties.heading,l1,l2), e.target._icon); + }); + return m; } + return new leaflet.Marker(latlng, options); }, +// onEachFeature : function(feature, layer) { +// }, }, + onAdd : function(map) { leaflet.GeoJSON.prototype.onAdd.call(this, map); this.update(++this.updateId); @@ -67,22 +69,21 @@ self.clearLayers(); self.addData(self.aiPropsToGeoJson(data, [ "aircraft", "multiplayer", "carrier" - ])); + ], self._map.getBounds())); }).fail(function(a, b) { self.updateId++; - console.log(a, b); alert('failed to load AI data'); }).always(function() { }); if (self.updateId == id) { setTimeout(function() { - self.update(id) + self.update(id) }, 10000); } }, - aiPropsToGeoJson : function(props, types) { + aiPropsToGeoJson : function(props, types, bounds ) { var geoJSON = { type : "FeatureCollection", features : [], @@ -100,7 +101,10 @@ var velocities = child.getNode("velocities"); var lon = position.getNode("longitude-deg").getValue(); var lat = position.getNode("latitude-deg").getValue(); - var alt = position.getNode("altitude-ft") * 0.3048; + if( false == bounds.contains(L.latLng(lat,lon)) ) { + return; + } + var alt = position.getNode("altitude-ft").getValue(); var heading = orientation.getNode("true-heading-deg").getValue(); var id = child.getNode("id").getValue(); var callsign = ""; diff --git a/Phi/topics/Map/NavdbLayer.js b/Phi/topics/Map/NavdbLayer.js index 8013c286b..83712e831 100644 --- a/Phi/topics/Map/NavdbLayer.js +++ b/Phi/topics/Map/NavdbLayer.js @@ -43,7 +43,7 @@ } } - return new leaflet.RotatedMarker(latlng, options); + return new leaflet./*Rotated*/Marker(latlng, options); }, onEachFeature : function(feature, layer) { diff --git a/Phi/widgets/AircraftMarker.html b/Phi/widgets/AircraftMarker.html new file mode 100644 index 000000000..794cd2d5b --- /dev/null +++ b/Phi/widgets/AircraftMarker.html @@ -0,0 +1,24 @@ +
+
+ +
+
+ diff --git a/Phi/widgets/AircraftMarker.js b/Phi/widgets/AircraftMarker.js new file mode 100644 index 000000000..4d9404470 --- /dev/null +++ b/Phi/widgets/AircraftMarker.js @@ -0,0 +1,41 @@ +define([ + 'jquery', 'knockout', 'text!./AircraftMarker.html', 'text!../images/aircraft.svg' +], function(jquery, ko, htmlString, aircraftSvgFileContent ) { + + // extract root element which should be from image xml (strip pi) and convert to string + // what an easy way to make Safari happy :-P + var iconSvgString = jquery('
') // wrap into detached
to get it's innerHTML + .append( + jquery( aircraftSvgFileContent ) // parse the file content + .filter(":first")[0]) // get root element + .html(); + + function ViewModel(params) { + var self = this; + + self.iconSvg = iconSvgString; + self.rotate = 0; + self.label = []; + + if( params && params.rotate ) { + self.rotate = params.rotate; + } + + if( params && params.label ) { + self.label = params.label; + } + + self.transformCss = function() { + return 'rotate(' + ko.unwrap(self.rotate) + 'deg)'; + } + } + +// ViewModel.prototype.dispose = function() { +// } + + // Return component definition + return { + viewModel : ViewModel, + template : htmlString + }; +}); diff --git a/Phi/widgets/map.html b/Phi/widgets/map.html index 9fe7fc033..befe771e6 100644 --- a/Phi/widgets/map.html +++ b/Phi/widgets/map.html @@ -7,33 +7,25 @@ fill: rgba(0, 255, 0, 0.4); } -.aircraft-marker-popup .leaflet-popup-tip { - display: none; -} - -.aircraft-marker-popup .leaflet-popup-content-wrapper { - background-color: rgba(255, 255, 255, 0.50); -} - -.aircraft-marker-popup .leaflet-popup-content { - margin: 5px 5px; -} - -.aircraft-marker-altitude { - width: 33%; -} - -.aircraft-marker-heading { - text-align: center; - width: 33%; -} - .aircraft-marker { float: left; color: #00ff00; text-shadow: 1px 1px #404040; } +.aircraft-marker-label { + white-space: nowrap; + border-radius: 3px; + font-size: 10px; + text-shadow: 0px 1px 0px black; + line-height: 110%; + background: rgba(0,0,0,0.2); + border: 1px solid rgba(0,0,0,0.3); + padding: 2px 3px; + display: inline-block; + color: rgb(255,255,255); +} + .aircraft-marker span { padding-left: 0.5em; } diff --git a/Phi/widgets/map.js b/Phi/widgets/map.js index d926379d8..888e7f3bc 100644 --- a/Phi/widgets/map.js +++ b/Phi/widgets/map.js @@ -1,24 +1,56 @@ define( [ - 'knockout', 'jquery', 'leaflet', 'text!./map.html', 'text!../images/aircraft.svg' + 'knockout', 'jquery', 'leaflet', 'text!./map.html' ], - function(ko, jquery, leaflet, htmlString, aircraftSvg ) { + function(ko, jquery, leaflet, htmlString ) { + if( !L.AircraftMarker ) { + L.AircraftMarker = L.Marker + .extend({ + options : { + clickable : false, + keyboard : false, + icon : L + .divIcon({ + iconSize : [ + 60, 60 + ], + iconAnchor : [ + 30, 30 + ], + className : 'aircraft-marker-icon', + html : + '
', + }), + zIndexOffset : 10000, + updateInterval : 100, + }, + + initialize : function(latlng, options) { + L.Marker.prototype.initialize(latlng, options); + L.Util.setOptions(this, options); + }, + + }); + + L.aircraftMarker = function(latlng, options) { + return new L.AircraftMarker(latlng, options); + } + } + function ViewModel(params, componentInfo) { var self = this; - { // extract element from image xml (strip pi) - var xmlDoc = jquery.parseXML( aircraftSvg ); - aircraftSvg = jquery( xmlDoc ).find("svg")[0].outerHTML; - } - self.element = componentInfo.element; self.followAircraft = ko.observable(true); self.toggleFollowAircraft = function(a) { self.followAircraft(!self.followAircraft()); } - + self.altitude = ko.observable(0).extend({ fgprop : 'altitude' }); @@ -27,10 +59,6 @@ define( fgprop : 'groundspeed' }); - self.heading = ko.observable(0).extend({ - fgprop : 'heading' - }); - if (params && params.css) { for ( var p in params.css) { jquery(self.element).css(p, params.css[p]); @@ -101,78 +129,6 @@ define( L.control.scale(params.scale).addTo(self.map); } - L.RotatedMarker = L.Marker.extend({ - options : { - angle : 0 - }, - - _setPos : function(pos) { - L.Marker.prototype._setPos.call(this, pos); - this._icon.style[L.DomUtil.TRANSFORM] += ' rotate(' + this.options.angle + 'deg)'; - } - }); - - L.AircraftMarker = L.RotatedMarker - .extend({ - options : { - angle : 0, - clickable : false, - keyboard : false, - icon : L - .divIcon({ - iconSize : [ - 60, 60 - ], - iconAnchor : [ - 30, 30 - ], - className : 'aircraft-marker-icon', - html : aircraftSvg, - }), - zIndexOffset : 10000, - updateInterval : 100, - }, - - initialize : function(latlng, options) { - L.RotatedMarker.prototype.initialize(latlng, options); - L.Util.setOptions(this, options); - }, - - onAdd : function(map) { - L.RotatedMarker.prototype.onAdd.call(this, map); - this.popup = L.popup({ - autoPan : false, - keepInView : false, - closeButton : false, - className : 'aircraft-marker-popup', - closeOnClick : false, - maxWidth : 200, - minWidth : 120, - offset : [ - 30, 30 - ], - }, this); - this.popup - .setContent('
ft
' - + '
°
' - + '
kt
'); - this.bindPopup(this.popup); - this.addTo(this._map); - this.openPopup(); - }, - - onRemove : function(map) { - if (this.timeoutid != null) - clearTimeout(this.timeoutid); - L.RotatedMarker.prototype.onRemove.call(this, map); - }, - - }); - - L.aircraftMarker = function(latlng, options) { - return new L.AircraftMarker(latlng, options); - } - var aircraftMarker = L.aircraftMarker(self.map.getCenter()); aircraftMarker.addTo(self.map); @@ -203,13 +159,15 @@ define( aircraftMarker.setLatLng(newValue); }); - self.heading.subscribe(function(newValue) { - var h = Math.round( newValue ); - if( aircraftMarker.options.angle != h ) { - aircraftMarker.options.angle = h; - aircraftMarker.setLatLng(self.position()); - } - }); + self.labelLines = [ + 'You', + ko.pureComputed(function() { + var h = Math.round(self.heading()); + var t = Math.round(self.tas()); + var a = Math.round(self.altitude()); + return '' + h + "T " + t + "KTAS " + a + "ft"; + }), + ]; self.mapCenter = ko.pureComputed(function() { return leaflet.latLng(self.latitude(), self.longitude()); @@ -233,7 +191,6 @@ define( var center = leaflet.latLng(self.latitude(), self.longitude()); self.map.setView( center ); - aircraftMarker.options.angle = self.heading(); aircraftMarker.setLatLng(center); }