From 7dc8f910d5a89dcca374331e3f86c4fe13404371 Mon Sep 17 00:00:00 2001 From: Marat Fayzullin Date: Mon, 31 Jul 2023 21:53:07 -0400 Subject: [PATCH] Finished refactoring maps. --- htdocs/lib/Map.js | 197 ++++++ .../lib/{LocatorManager.js => MapLocators.js} | 41 -- .../lib/{MarkerManager.js => MapMarkers.js} | 50 -- htdocs/map.js | 657 +++++++----------- owrx/controllers/assets.py | 3 + 5 files changed, 462 insertions(+), 486 deletions(-) create mode 100644 htdocs/lib/Map.js rename htdocs/lib/{LocatorManager.js => MapLocators.js} (85%) rename htdocs/lib/{MarkerManager.js => MapMarkers.js} (93%) diff --git a/htdocs/lib/Map.js b/htdocs/lib/Map.js new file mode 100644 index 00000000..22b96efd --- /dev/null +++ b/htdocs/lib/Map.js @@ -0,0 +1,197 @@ +// +// Map Manager handles web socket connection and traffic processing +// + +function MapManager() { + var self = this; + + // Determine web socket URL + var protocol = window.location.protocol.match(/https/) ? 'wss' : 'ws'; + var href = window.location.href.replace(/\/[^\/]*$/,''); + href = protocol + '://' + href.split('://')[1]; + this.ws_url = href + (href.endsWith('/')? '':'/') + 'ws/'; + + // Reset everything for now + this.reconnect_timeout = false; + this.config = {}; + + // Markers management (features, APRS, AIS, HFDL, etc) + this.mman = new MarkerManager(); + + // Locators management (FT8, FT4, WSPR, etc) + this.lman = new LocatorManager(); + + // Clock display + this.clock = new Clock($("#openwebrx-clock-utc")); + + // Toggle color modes on click + $(function() { + $('#openwebrx-map-colormode').on('change', function() { + self.lman.setColorMode(map, $(this).val()); + }); + }); + + // Toggle legend box on/off when clicking the clock + $(function() { + $('#openwebrx-clock-utc').on('click', function() { + var el = document.getElementById('openwebrx-map-selectors'); + if (el) { + el.style.display = el.style.display === 'none'? + 'block' : 'none'; + } + }); + }); + + // Fade out / remove positions after time + setInterval(function() { + self.lman.ageAll(); + self.mman.ageAll(); + }, 1000); + + // Connect web socket + this.connect(); +} + +// +// Process a message received over web socket +// +MapManager.prototype.process = function(e) { + if (typeof e.data != 'string') { + console.error("unsupported binary data on websocket; ignoring"); + return + } + + if (e.data.substr(0, 16) == "CLIENT DE SERVER") { + return + } + + try { + var json = JSON.parse(e.data); + switch (json.type) { + case "update": + this.processUpdates(json.value); + break; + + case 'receiver_details': + $('.webrx-top-container').header().setDetails(json.value); + break; + + case "config": + Object.assign(this.config, json.value); + if ('receiver_gps' in this.config) { + // Passing API key even if this particular map + // engine does not need it (Google Maps do) + this.initializeMap( + this.config.receiver_gps, + this.config.google_maps_api_key + ); + } + if ('receiver_name' in this.config) { + this.setReceiverName(this.config.receiver_name); + } + if ('map_position_retention_time' in this.config) { + retention_time = this.config.map_position_retention_time * 1000; + } + if ('callsign_url' in this.config) { + callsign_url = this.config.callsign_url; + } + if ('vessel_url' in this.config) { + vessel_url = this.config.vessel_url; + } + if ('flight_url' in this.config) { + flight_url = this.config.flight_url; + } + break; + + default: + console.warn('received message of unknown type: ' + json.type); + } + } catch (e) { + // Don't lose exception + console.error(e); + } +}; + +// +// Connect web socket +// +MapManager.prototype.connect = function() { + var ws = new WebSocket(this.ws_url); + var self = this; + + // When socket opens... + ws.onopen = function() { + ws.send("SERVER DE CLIENT client=map.js type=map"); + self.reconnect_timeout = false + }; + + // When socket closes... + ws.onclose = function() { + // Clear map + self.removeReceiver(); + self.mman.clear(); + self.lman.clear(); + + if (self.reconnect_timeout) { + // Max value: roundabout 8 and a half minutes + self.reconnect_timeout = Math.min(self.reconnect_timeout * 2, 512000); + } else { + // Initial value: 1s + self.reconnect_timeout = 1000; + } + + // Try reconnecting after timeout + setTimeout(self.connect, self.reconnect_timeout); + }; + + // When socket receives a message... + ws.onmessage = function(e) { + self.process(e); + } + + // When socket gets an error... + //ws.onerror = function() { + // console.info("websocket error"); + //}; + + // http://stackoverflow.com/questions/4812686/closing-websocket-correctly-html5-javascript + window.onbeforeunload = function() { + ws.onclose = function () {}; + ws.close(); + }; +}; + +// +// Set up legend filter toggles inside given HTML element. +// +MapManager.prototype.setupLegendFilters = function($legend) { + var self = this; + + $content = $legend.find('.content'); + $content.on('click', 'li', function() { + var $el = $(this); + $lis = $content.find('li'); + if ($lis.hasClass('disabled') && !$el.hasClass('disabled')) { + $lis.removeClass('disabled'); + self.lman.setFilter(map); + } else { + $el.removeClass('disabled'); + $lis.filter(function() { + return this != $el[0] + }).addClass('disabled'); + self.lman.setFilter(map, $el.data('selector')); + } + }); + + $content1 = $legend.find('.features'); + $content1.on('click', 'li', function() { + var $el = $(this); + var onoff = $el.hasClass('disabled'); + if (onoff) { + $el.removeClass('disabled'); + } else { + $el.addClass('disabled'); + } + self.mman.toggle(map, $el.data('selector'), onoff); + }); +}; diff --git a/htdocs/lib/LocatorManager.js b/htdocs/lib/MapLocators.js similarity index 85% rename from htdocs/lib/LocatorManager.js rename to htdocs/lib/MapLocators.js index 3e2cf799..9e8f7523 100644 --- a/htdocs/lib/LocatorManager.js +++ b/htdocs/lib/MapLocators.js @@ -205,44 +205,3 @@ Locator.prototype.age = function(age) { return false; } }; - -// -// GoogleMaps-specific Map Locator (derived from generic locator) -// - -function GLocator() { - this.rect = new google.maps.Rectangle(); - this.rect.setOptions({ - strokeWeight : 2, - strokeColor : "#FFFFFF", - fillColor : "#FFFFFF" - }); -} - -GLocator.prototype = new Locator(); - -GLocator.prototype.setMap = function(map) { - this.rect.setMap(map); -}; - -GLocator.prototype.setCenter = function(lat, lon) { - this.center = new google.maps.LatLng({lat: lat, lng: lon}); - - this.rect.setOptions({ bounds : { - north : lat - 0.5, - south : lat + 0.5, - west : lon - 1.0, - east : lon + 1.0 - }}); -} - -GLocator.prototype.setColor = function(color) { - this.rect.setOptions({ strokeColor: color, fillColor: color }); -}; - -GLocator.prototype.setOpacity = function(opacity) { - this.rect.setOptions({ - strokeOpacity : LocatorManager.strokeOpacity * opacity, - fillOpacity : LocatorManager.fillOpacity * opacity - }); -}; diff --git a/htdocs/lib/MarkerManager.js b/htdocs/lib/MapMarkers.js similarity index 93% rename from htdocs/lib/MarkerManager.js rename to htdocs/lib/MapMarkers.js index 0f41aa4f..e51c279a 100644 --- a/htdocs/lib/MarkerManager.js +++ b/htdocs/lib/MapMarkers.js @@ -564,53 +564,3 @@ AprsMarker.prototype.getInfoHTML = function(name, receiverMarker = null) { + ( this.band ? ' on ' + this.band : '' ) + '' + commentString + weatherString + detailsString + hopsString; }; - -// -// GoogleMaps-Specific Markers (derived from generic markers) -// - -function GMarker() {} -GMarker.prototype = new google.maps.OverlayView(); - -GMarker.prototype.setMarkerOptions = function(options) { - this.setOptions(options); - this.draw(); -}; - -GMarker.prototype.onAdd = function() { - // Create HTML elements representing the mark - var div = this.create(); - - var self = this; - google.maps.event.addDomListener(div, "click", function(event) { - event.stopPropagation(); - google.maps.event.trigger(self, "click", event); - }); - - var panes = this.getPanes(); - panes.overlayImage.appendChild(div); -}; - -GMarker.prototype.getAnchorPoint = function() { - var offset = this.getAnchorOffset(); - return new google.maps.Point(offset[0], offset[1]); -}; - -GMarker.prototype.setMarkerOpacity = function(opacity) { - this.setOptions({ opacity: opacity }); -}; - -GMarker.prototype.setMarkerPosition = function(title, lat, lon) { - this.setOptions({ - title : title, - position : new google.maps.LatLng(lat, lon) - }); -}; - -// GoogleMaps-Specific FeatureMarker -function GFeatureMarker() { $.extend(this, new FeatureMarker()); } -GFeatureMarker.prototype = new GMarker(); - -// GoogleMaps-Specific AprsMarker -function GAprsMarker() { $.extend(this, new AprsMarker()); } -GAprsMarker.prototype = new GMarker(); diff --git a/htdocs/map.js b/htdocs/map.js index 73ec14fc..08e8ef31 100644 --- a/htdocs/map.js +++ b/htdocs/map.js @@ -6,406 +6,273 @@ var flight_url = null; // reasonable default; will be overriden by server var retention_time = 2 * 60 * 60 * 1000; -// Function to toggle legend box on/off -function toggleElement(el_name) { - var el = document.getElementById(el_name); - if (el) el.style.display = el.style.display === 'none'? 'block' : 'none'; +// Our Google Map +var map = null; + +// Receiver location marker +var receiverMarker = null; + +// Information bubble window +var infoWindow = null; + +// Updates are queued here +var updateQueue = []; + +// Web socket connection management, message processing +var mapManager = new MapManager(); + +var query = window.location.search.replace(/^\?/, '').split('&').map(function(v){ + var s = v.split('='); + var r = {}; + r[s[0]] = s.slice(1).join('='); + return r; +}).reduce(function(a, b){ + return a.assign(b); +}); + +var expectedCallsign = query.callsign? decodeURIComponent(query.callsign) : null; +var expectedLocator = query.locator? query.locator : null; + +// Get information bubble window +function getInfoWindow() { + if (!infoWindow) { + infoWindow = new google.maps.InfoWindow(); + google.maps.event.addListener(infoWindow, 'closeclick', function() { + delete infoWindow.locator; + delete infoWindow.callsign; + }); + } + delete infoWindow.locator; + delete infoWindow.callsign; + return infoWindow; +}; + +// Show information bubble for a locator +function showLocatorInfoWindow(locator, pos) { + var iw = getInfoWindow(); + + iw.locator = locator; + iw.setContent(mapManager.lman.getInfoHTML(locator, pos, receiverMarker)); + iw.setPosition(pos); + iw.open(map); +}; + +// Show information bubble for a marker +function showMarkerInfoWindow(name, pos) { + var marker = mapManager.mman.find(name); + var iw = getInfoWindow(); + + iw.callsign = name; + iw.setContent(marker.getInfoHTML(name, receiverMarker)); + iw.open(map, marker); +}; + +// Show information bubble for the receiver location +function showReceiverInfoWindow(marker) { + var iw = getInfoWindow() + iw.setContent( + '

' + marker.config['receiver_name'] + '

' + + '
Receiver Location
' + ); + iw.open(map, marker); +}; + +// +// GOOGLE-SPECIFIC MAP MANAGER METHODS +// + +MapManager.prototype.setReceiverName = function(name) { + if (this.receiverMarker) this.receiverMarker.setOptions({ title: name }); } -$(function(){ - var query = window.location.search.replace(/^\?/, '').split('&').map(function(v){ - var s = v.split('='); - var r = {}; - r[s[0]] = s.slice(1).join('='); - return r; - }).reduce(function(a, b){ - return a.assign(b); - }); +MapManager.prototype.removeReceiver = function() { + if (this.receiverMarker) this.receiverMarker.setMap(); +} - var expectedCallsign; - if (query.callsign) expectedCallsign = decodeURIComponent(query.callsign); - var expectedLocator; - if (query.locator) expectedLocator = query.locator; +MapManager.prototype.initializeMap = function(receiver_gps, api_key) { + var receiverPos = { lat: receiver_gps.lat, lng: receiver_gps.lon }; - var protocol = window.location.protocol.match(/https/) ? 'wss' : 'ws'; - - var href = window.location.href; - var index = href.lastIndexOf('/'); - if (index > 0) { - href = href.substr(0, index + 1); - } - href = href.split("://")[1]; - href = protocol + "://" + href; - if (!href.endsWith('/')) { - href += '/'; - } - var ws_url = href + "ws/"; - - var map; - var receiverMarker; - var updateQueue = []; - - // marker and locator managers - var markmanager = null; - var locmanager = null; - - // clock - var clock = new Clock($("#openwebrx-clock-utc")); - - $(function() { - $('#openwebrx-map-colormode').on('change', function() { - locmanager.setColorMode(map, $(this).val()); + if (map) { + this.receiverMarker.setOptions({ + map : map, + position : receiverPos, + config : this.config }); - }); + } else { + var self = this; - var processUpdates = function(updates) { - if (!markmanager || !locmanager) { - updateQueue = updateQueue.concat(updates); - return; - } - updates.forEach(function(update) { - switch (update.location.type) { - case 'latlon': - var marker = markmanager.find(update.callsign); - var markerClass = google.maps.Marker; - var aprsOptions = {} - - if (update.location.symbol) { - markerClass = GAprsMarker; - aprsOptions.symbol = update.location.symbol; - aprsOptions.course = update.location.course; - aprsOptions.speed = update.location.speed; - } - - // If new item, create a new marker for it - if (!marker) { - marker = new markerClass(); - markmanager.addType(update.mode); - markmanager.add(update.callsign, marker); - marker.addListener('click', function() { - showMarkerInfoWindow(update.callsign, marker.pos); - }); - } - - // Update marker attributes and age - marker.update(update); - - // Assign marker to map - marker.setMap(markmanager.isEnabled(update.mode)? map : undefined); - - // Apply marker options - marker.setMarkerOptions(aprsOptions); - - if (expectedCallsign && expectedCallsign == update.callsign) { - map.panTo(marker.pos); - showMarkerInfoWindow(update.callsign, marker.pos); - expectedCallsign = false; - } - - if (infowindow && infowindow.callsign && infowindow.callsign == update.callsign) { - showMarkerInfoWindow(infowindow.callsign, marker.pos); - } - break; - - case 'feature': - var marker = markmanager.find(update.callsign); - var options = {} - - // If no symbol or color supplied, use defaults by type - if (update.location.symbol) { - options.symbol = update.location.symbol; - } else { - options.symbol = markmanager.getSymbol(update.mode); - } - if (update.location.color) { - options.color = update.location.color; - } else { - options.color = markmanager.getColor(update.mode); - } - - // If new item, create a new marker for it - if (!marker) { - marker = new GFeatureMarker(); - markmanager.addType(update.mode); - markmanager.add(update.callsign, marker); - marker.addListener('click', function() { - showMarkerInfoWindow(update.callsign, marker.pos); - }); - } - - // Update marker attributes and age - marker.update(update); - - // Assign marker to map - marker.setMap(markmanager.isEnabled(update.mode)? map : undefined); - - // Apply marker options - marker.setMarkerOptions(options); - - if (expectedCallsign && expectedCallsign == update.callsign) { - map.panTo(marker.pos); - showMarkerInfoWindow(update.callsign, marker.pos); - expectedCallsign = false; - } - - if (infowindow && infowindow.callsign && infowindow.callsign == update.callsign) { - showMarkerInfoWindow(infowindow.callsign, marker.pos); - } - break; - - case 'locator': - var rectangle = locmanager.find(update.callsign); - - // If new item, create a new locator for it - if (!rectangle) { - rectangle = new GLocator(); - locmanager.add(update.callsign, rectangle); - rectangle.rect.addListener('click', function() { - showLocatorInfoWindow(rectangle.locator, rectangle.center); - }); - } - - // Update locator attributes, center, age - rectangle.update(update); - - // Assign locator to map and set its color - rectangle.setMap(locmanager.filter(rectangle)? map : undefined); - rectangle.setColor(locmanager.getColor(rectangle)); - - if (expectedLocator && expectedLocator == update.location.locator) { - map.panTo(rectangle.center); - showLocatorInfoWindow(expectedLocator, rectangle.center); - expectedLocator = false; - } - - if (infowindow && infowindow.locator && infowindow.locator == update.location.locator) { - showLocatorInfoWindow(infowindow.locator, rectangle.center); - } - break; - } - }); - }; - - var clearMap = function(){ - var reset = function(callsign, item) { item.setMap(); }; - receiverMarker.setMap(); - markmanager.clear(); - locmanager.clear(); - }; - - var reconnect_timeout = false; - - var config = {} - - var connect = function(){ - var ws = new WebSocket(ws_url); - ws.onopen = function(){ - ws.send("SERVER DE CLIENT client=map.js type=map"); - reconnect_timeout = false - }; - - ws.onmessage = function(e){ - if (typeof e.data != 'string') { - console.error("unsupported binary data on websocket; ignoring"); - return - } - if (e.data.substr(0, 16) == "CLIENT DE SERVER") { - return - } - try { - var json = JSON.parse(e.data); - switch (json.type) { - case "config": - Object.assign(config, json.value); - if ('receiver_gps' in config) { - var receiverPos = { - lat: config.receiver_gps.lat, - lng: config.receiver_gps.lon - }; - if (!map) $.getScript("https://maps.googleapis.com/maps/api/js?key=" + config.google_maps_api_key).done(function(){ - map = new google.maps.Map($('.openwebrx-map')[0], { - center: receiverPos, - zoom: 5, - }); - - $.getScript("static/lib/nite-overlay.js").done(function(){ - nite.init(map); - setInterval(function() { nite.refresh() }, 10000); // every 10s - }); - - $.getScript('static/lib/MarkerManager.js').done(function(){ - markmanager = new MarkerManager(); - if (locmanager) { - processUpdates(updateQueue); - updateQueue = []; - } - }); - - $.getScript('static/lib/LocatorManager.js').done(function(){ - locmanager = new LocatorManager(); - if (markmanager) { - processUpdates(updateQueue); - updateQueue = []; - } - }); - - var $legend = $(".openwebrx-map-legend"); - setupLegendFilters($legend); - map.controls[google.maps.ControlPosition.LEFT_BOTTOM].push($legend[0]); - - if (!receiverMarker) { - receiverMarker = new google.maps.Marker(); - receiverMarker.addListener('click', function() { - showReceiverInfoWindow(receiverMarker); - }); - } - receiverMarker.setOptions({ - map: map, - position: receiverPos, - title: config['receiver_name'], - config: config - }); - - }); else { - receiverMarker.setOptions({ - map: map, - position: receiverPos, - config: config - }); - } - } - if ('receiver_name' in config && receiverMarker) { - receiverMarker.setOptions({ - title: config['receiver_name'] - }); - } - if ('map_position_retention_time' in config) { - retention_time = config.map_position_retention_time * 1000; - } - if ('callsign_url' in config) { - callsign_url = config['callsign_url']; - } - if ('vessel_url' in config) { - vessel_url = config['vessel_url']; - } - if ('flight_url' in config) { - flight_url = config['flight_url']; - } - break; - case "update": - processUpdates(json.value); - break; - case 'receiver_details': - $('.webrx-top-container').header().setDetails(json['value']); - break; - default: - console.warn('received message of unknown type: ' + json['type']); - } - } catch (e) { - // don't lose exception - console.error(e); - } - }; - ws.onclose = function(){ - clearMap(); - if (reconnect_timeout) { - // max value: roundabout 8 and a half minutes - reconnect_timeout = Math.min(reconnect_timeout * 2, 512000); - } else { - // initial value: 1s - reconnect_timeout = 1000; - } - setTimeout(connect, reconnect_timeout); - }; - - window.onbeforeunload = function() { //http://stackoverflow.com/questions/4812686/closing-websocket-correctly-html5-javascript - ws.onclose = function () {}; - ws.close(); - }; - - /* - ws.onerror = function(){ - console.info("websocket error"); - }; - */ - }; - - connect(); - - var getInfoWindow = function() { - if (!infowindow) { - infowindow = new google.maps.InfoWindow(); - google.maps.event.addListener(infowindow, 'closeclick', function() { - delete infowindow.locator; - delete infowindow.callsign; + // After Google Maps API loads... + $.getScript("https://maps.googleapis.com/maps/api/js?key=" + api_key).done(function() { + // Create a map instance + map = new google.maps.Map($('.openwebrx-map')[0], { + center : receiverPos, + zoom : 5, }); + + // Load and initialize day-and-night overlay + $.getScript("static/lib/nite-overlay.js").done(function() { + nite.init(map); + setInterval(function() { nite.refresh() }, 10000); // every 10s + }); + + // Load and initialize OWRX-specific map item managers + $.getScript('static/lib/GoogleMaps.js').done(function() { + // Process any accumulated updates + self.processUpdates(updateQueue); + updateQueue = []; + }); + + // Create map legend selectors + var $legend = $(".openwebrx-map-legend"); + self.setupLegendFilters($legend); + map.controls[google.maps.ControlPosition.LEFT_BOTTOM].push($legend[0]); + + // Create receiver marker + if (!receiverMarker) { + receiverMarker = new google.maps.Marker(); + receiverMarker.addListener('click', function() { + showReceiverInfoWindow(receiverMarker); + }); + } + + // Set receiver marker position, name, etc. + receiverMarker.setOptions({ + map : map, + position : receiverPos, + title : self.config['receiver_name'], + config : self.config + }); + }); + } +}; + +MapManager.prototype.processUpdates = function(updates) { + var self = this; + + if (typeof(GMarker) == 'undefined') { + updateQueue = updateQueue.concat(updates); + return; + } + + updates.forEach(function(update) { + switch (update.location.type) { + case 'latlon': + var marker = self.mman.find(update.callsign); + var markerClass = google.maps.Marker; + var aprsOptions = {} + + if (update.location.symbol) { + markerClass = GAprsMarker; + aprsOptions.symbol = update.location.symbol; + aprsOptions.course = update.location.course; + aprsOptions.speed = update.location.speed; + } + + // If new item, create a new marker for it + if (!marker) { + marker = new markerClass(); + self.mman.addType(update.mode); + self.mman.add(update.callsign, marker); + marker.addListener('click', function() { + showMarkerInfoWindow(update.callsign, marker.pos); + }); + } + + // Update marker attributes and age + marker.update(update); + + // Assign marker to map + marker.setMap(self.mman.isEnabled(update.mode)? map : undefined); + + // Apply marker options + marker.setMarkerOptions(aprsOptions); + + if (expectedCallsign && expectedCallsign == update.callsign) { + map.panTo(marker.pos); + showMarkerInfoWindow(update.callsign, marker.pos); + expectedCallsign = false; + } + + if (infoWindow && infoWindow.callsign && infoWindow.callsign == update.callsign) { + showMarkerInfoWindow(infoWindow.callsign, marker.pos); + } + break; + + case 'feature': + var marker = self.mman.find(update.callsign); + var options = {} + + // If no symbol or color supplied, use defaults by type + if (update.location.symbol) { + options.symbol = update.location.symbol; + } else { + options.symbol = self.mman.getSymbol(update.mode); + } + if (update.location.color) { + options.color = update.location.color; + } else { + options.color = self.mman.getColor(update.mode); + } + + // If new item, create a new marker for it + if (!marker) { + marker = new GFeatureMarker(); + self.mman.addType(update.mode); + self.mman.add(update.callsign, marker); + marker.addListener('click', function() { + showMarkerInfoWindow(update.callsign, marker.pos); + }); + } + + // Update marker attributes and age + marker.update(update); + + // Assign marker to map + marker.setMap(self.mman.isEnabled(update.mode)? map : undefined); + + // Apply marker options + marker.setMarkerOptions(options); + + if (expectedCallsign && expectedCallsign == update.callsign) { + map.panTo(marker.pos); + showMarkerInfoWindow(update.callsign, marker.pos); + expectedCallsign = false; + } + + if (infoWindow && infoWindow.callsign && infoWindow.callsign == update.callsign) { + showMarkerInfoWindow(infoWindow.callsign, marker.pos); + } + break; + + case 'locator': + var rectangle = self.lman.find(update.callsign); + + // If new item, create a new locator for it + if (!rectangle) { + rectangle = new GLocator(); + self.lman.add(update.callsign, rectangle); + rectangle.rect.addListener('click', function() { + showLocatorInfoWindow(rectangle.locator, rectangle.center); + }); + } + + // Update locator attributes, center, age + rectangle.update(update); + + // Assign locator to map and set its color + rectangle.setMap(self.lman.filter(rectangle)? map : undefined); + rectangle.setColor(self.lman.getColor(rectangle)); + + if (expectedLocator && expectedLocator == update.location.locator) { + map.panTo(rectangle.center); + showLocatorInfoWindow(expectedLocator, rectangle.center); + expectedLocator = false; + } + + if (infoWindow && infoWindow.locator && infoWindow.locator == update.location.locator) { + showLocatorInfoWindow(infoWindow.locator, rectangle.center); + } + break; } - delete infowindow.locator; - delete infowindow.callsign; - return infowindow; - } - - var infowindow; - var showLocatorInfoWindow = function(locator, pos) { - var infowindow = getInfoWindow(); - infowindow.locator = locator; - infowindow.setContent(locmanager.getInfoHTML(locator, pos, receiverMarker)); - infowindow.setPosition(pos); - infowindow.open(map); - }; - - var showMarkerInfoWindow = function(name, pos) { - var infowindow = getInfoWindow(); - var marker = markmanager.find(name); - - infowindow.callsign = name; - infowindow.setContent(marker.getInfoHTML(name, receiverMarker)); - infowindow.open(map, marker); - } - - var showReceiverInfoWindow = function(marker) { - var infowindow = getInfoWindow() - infowindow.setContent( - '

' + marker.config['receiver_name'] + '

' + - '
Receiver location
' - ); - infowindow.open(map, marker); - } - - // Fade out / remove positions after time - setInterval(function(){ - if (locmanager) locmanager.ageAll(); - if (markmanager) markmanager.ageAll(); - }, 1000); - - var setupLegendFilters = function($legend) { - $content = $legend.find('.content'); - $content.on('click', 'li', function() { - var $el = $(this); - $lis = $content.find('li'); - if ($lis.hasClass('disabled') && !$el.hasClass('disabled')) { - $lis.removeClass('disabled'); - locmanager.setFilter(map); - } else { - $el.removeClass('disabled'); - $lis.filter(function() { - return this != $el[0] - }).addClass('disabled'); - locmanager.setFilter(map, $el.data('selector')); - } - }); - - $content1 = $legend.find('.features'); - $content1.on('click', 'li', function() { - var $el = $(this); - var onoff = $el.hasClass('disabled'); - if (onoff) { - $el.removeClass('disabled'); - } else { - $el.addClass('disabled'); - } - markmanager.toggle(map, $el.data('selector'), onoff); - }); - } - -}); + }); +}; diff --git a/owrx/controllers/assets.py b/owrx/controllers/assets.py index d5d180e3..a11b0540 100644 --- a/owrx/controllers/assets.py +++ b/owrx/controllers/assets.py @@ -145,6 +145,9 @@ class CompiledAssetsController(GzipMixin, ModificationAwareController): "lib/jquery-3.2.1.min.js", "lib/chroma.min.js", "lib/Header.js", + "lib/MapLocators.js", + "lib/MapMarkers.js", + "lib/Map.js", "lib/Clock.js", "map.js", ],