Finished refactoring maps.
This commit is contained in:
parent
f6afd5fe8c
commit
7dc8f910d5
|
|
@ -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);
|
||||
});
|
||||
};
|
||||
|
|
@ -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
|
||||
});
|
||||
};
|
||||
|
|
@ -564,53 +564,3 @@ AprsMarker.prototype.getInfoHTML = function(name, receiverMarker = null) {
|
|||
+ ( this.band ? ' on ' + this.band : '' ) + '</div>'
|
||||
+ 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();
|
||||
657
htdocs/map.js
657
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(
|
||||
'<h3>' + marker.config['receiver_name'] + '</h3>' +
|
||||
'<div>Receiver Location</div>'
|
||||
);
|
||||
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(
|
||||
'<h3>' + marker.config['receiver_name'] + '</h3>' +
|
||||
'<div>Receiver location</div>'
|
||||
);
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
],
|
||||
|
|
|
|||
Loading…
Reference in New Issue