diff --git a/htdocs/css/map.css b/htdocs/css/map.css index 8d78995e..a7c6539e 100644 --- a/htdocs/css/map.css +++ b/htdocs/css/map.css @@ -66,7 +66,7 @@ ul { border-width: 0; border-style: none; font-size: 24px; - text-alignment: center; + text-align: center; } .openwebrx-map-legend select { diff --git a/htdocs/lib/FeatureMarker.js b/htdocs/lib/FeatureMarker.js index 4003923b..3a7a64e7 100644 --- a/htdocs/lib/FeatureMarker.js +++ b/htdocs/lib/FeatureMarker.js @@ -1,3 +1,92 @@ +// +// Features Management +// + +function Features() { + // Currently known features + this.types = {}; + + // Colors used for features + this.colors = { + 'KiwiSDR' : '#800000', + 'WebSDR' : '#000080', + 'OpenWebRX' : '#006000' + }; + + // Symbols used for features + this.symbols = { + 'KiwiSDR' : '⨺', + 'WebSDR' : '◬', + 'OpenWebRX' : '⨹', + 'APRS' : '⚐', + 'AIS' : '⩯', + 'HFDL' : '✈' + }; + + // Feature type shown/hidden status + this.enabled = { + 'KiwiSDR' : false, + 'WebSDR' : false, + 'OpenWebRX' : false + }; +} + +Features.prototype.getColor = function(type) { + // Default color is black + return type in this.colors? this.colors[type] : '#000000'; +}; + +Features.prototype.getSymbol = function(type) { + // Default symbol is a rombus + return type in this.symbols? this.symbols[type] : '◇'; +}; + +Features.prototype.isEnabled = function(type) { + // Features are shown by default + return type in this.enabled? this.enabled[type] : true; +}; + +Features.prototype.toggle = function(map, markers, type, onoff) { + // Keep track of each feature table being show or hidden + this.enabled[type] = onoff; + + // Show or hide features on the map + $.each(markers, function(_, r) { + if (r.mode === type) r.setMap(onoff ? map : undefined); + }); +}; + +Features.prototype.addType = function(type) { + // Do not add feature twice + if (type in this.types) return; + + // Determine symbol and its color + var color = this.getColor(type); + var symbol = this.getSymbol(type); + var enabled = this.isEnabled(type); + + // Add type to the list of known types + this.types[type] = symbol; + this.enabled[type] = enabled; + + // If there is a list of features... + var $content = $(".openwebrx-map-legend").find('.features'); + if($content) + { + // Add visual list item for the type + $content.append( + '
  • ' + + '' + + symbol + '' + type + '
  • ' + ); + } +}; + +// +// Feature Markers +// + function FeatureMarker() {} FeatureMarker.prototype = new google.maps.OverlayView(); diff --git a/htdocs/map.html b/htdocs/map.html index ee032a3e..8bfec92e 100644 --- a/htdocs/map.html +++ b/htdocs/map.html @@ -24,10 +24,6 @@

    Features

    diff --git a/htdocs/map.js b/htdocs/map.js index dd3a4edc..a6cbb76c 100644 --- a/htdocs/map.js +++ b/htdocs/map.js @@ -41,12 +41,8 @@ $(function(){ var vessel_url = null; var flight_url = null; - // colors used for features - var featureColors = { - 'KiwiSDR' : '#800000', - 'WebSDR' : '#000080', - 'OpenWebRX' : '#006000' - }; + // Features functionality + var features = null; var colorKeys = {}; var colorScale = chroma.scale(['red', 'blue', 'green']).mode('hsl'); @@ -142,10 +138,11 @@ $(function(){ showMarkerInfoWindow(update.callsign, pos); }); markers[update.callsign] = marker; + features.addType(update.mode); } marker.setOptions($.extend({ position: pos, - map: map, + map: features.isEnabled(update.mode)? map : undefined, title: update.callsign }, aprsOptions, getMarkerOpacityOptions(update.lastseen) )); marker.lastseen = update.lastseen; @@ -174,29 +171,41 @@ $(function(){ break; case 'feature': var pos = new google.maps.LatLng(update.location.lat, update.location.lon); - var marker; - var markerClass = google.maps.Marker; var options = {} + var marker; + + // If no symbol or color supplied, use defaults by type if (update.location.symbol) { - markerClass = FeatureMarker; options.symbol = update.location.symbol; - options.color = update.mode in featureColors? - featureColors[update.mode] : '#000000'; + } else { + options.symbol = features.getSymbol(update.mode); } + if (update.location.color) { + options.color = update.location.color; + } else { + options.color = features.getColor(update.mode); + } + + // If new item, create a new feature marker for it if (markers[update.callsign]) { marker = markers[update.callsign]; } else { - marker = new markerClass(); + marker = new FeatureMarker(); marker.addListener('click', function(){ showMarkerInfoWindow(update.callsign, pos); }); markers[update.callsign] = marker; + features.addType(update.mode); } + + // Apply marker options marker.setOptions($.extend({ position: pos, - map: map, + map: features.isEnabled(update.mode)? map : undefined, title: update.callsign - }, options, getMarkerOpacityOptions(update.lastseen) )); + }, options)); + + // Get attributes marker.lastseen = update.lastseen; marker.mode = update.mode; marker.url = update.location.url; @@ -315,12 +324,14 @@ $(function(){ }); $.getScript('static/lib/AprsMarker.js').done(function(){ if(typeof(FeatureMarker) != 'undefined') { + features = new Features(); processUpdates(updateQueue); updateQueue = []; } }); $.getScript('static/lib/FeatureMarker.js').done(function(){ if(typeof(AprsMarker) != 'undefined') { + features = new Features(); processUpdates(updateQueue); updateQueue = []; } @@ -745,20 +756,13 @@ $(function(){ $content = $legend.find('.features'); $content.on('click', 'li', function() { var $el = $(this); - $lis = $content.find('li'); - if ($lis.hasClass('disabled') && !$el.hasClass('disabled')) { - $lis.removeClass('disabled'); - // @@@ ADD CODE HERE - } else { + var onoff = $el.hasClass('disabled'); + if (onoff) { $el.removeClass('disabled'); - $lis.filter(function() { - return this != $el[0] - }).addClass('disabled'); - - var key = colorMode.slice(2); - var selector = $el.data('selector'); - // @@@ ADD CODE HERE + } else { + $el.addClass('disabled'); } + features.toggle(map, markers, $el.data('selector'), onoff); }); } diff --git a/owrx/receiverdb.py b/owrx/receiverdb.py index 92326e21..83ace10b 100644 --- a/owrx/receiverdb.py +++ b/owrx/receiverdb.py @@ -26,7 +26,7 @@ class ReceiverLocation(LatLngLocation): super().__init__(lat, lon) def getId(self): - return re.sub(r"^.*://(.*)[/:].*$", r"\1", self.attrs["url"]) + return re.sub(r"^.*://(.*?)(/.*)?$", r"\1", self.attrs["url"]) def getMode(self): return re.sub(r"^([A-Za-z]+).*$", r"\1", self.attrs["device"]) @@ -170,9 +170,7 @@ class ReceiverDatabase(object): "lon" : lon, "comment" : r["label"], "url" : r["url"], - "device" : dev, - "symbol" : "◬", - "color" : self.getColor(dev) + "device" : dev }) result[rl.getId()] = rl # Offset colocated receivers by ~500m @@ -202,9 +200,7 @@ class ReceiverDatabase(object): "comment" : entry["desc"], "url" : entry["url"], #"users" : int(entry["users"]), - "device" : "WebSDR", - "symbol" : "◬", - "color" : self.getColor("WebSDR") + "device" : "WebSDR" }) result[rl.getId()] = rl @@ -248,9 +244,7 @@ class ReceiverDatabase(object): "loc" : entry["loc"], "altitude": int(entry["asl"]), "antenna" : entry["antenna"], - "device" : re.sub("_v", " ", entry["sw_version"]), - "symbol" : "◬", - "color" : self.getColor("KiwiSDR") + "device" : re.sub("_v", " ", entry["sw_version"]) }) result[rl.getId()] = rl # Clear current entry