Implementing separate aircraft markers.
This commit is contained in:
parent
33d84c3438
commit
4dea8c11ab
Binary file not shown.
|
After Width: | Height: | Size: 64 KiB |
|
|
@ -78,6 +78,25 @@ GAprsMarker.prototype.place = function() {
|
|||
}
|
||||
};
|
||||
|
||||
//
|
||||
// GoogleMaps-Specific AircraftMarker
|
||||
//
|
||||
|
||||
function GAircraftMarker() { $.extend(this, new AircraftMarker()); }
|
||||
GAircraftMarker.prototype = new GMarker();
|
||||
|
||||
GAircraftMarker.prototype.place = function() {
|
||||
// Project location and place symbol
|
||||
var div = this.div;
|
||||
if (div) {
|
||||
var point = this.getProjection().fromLatLngToDivPixel(this.position);
|
||||
if (point) {
|
||||
div.style.left = point.x - 36 + 'px';
|
||||
div.style.top = point.y - 36 + 'px';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// GoogleMaps-Specific SimpleMarker
|
||||
//
|
||||
|
|
|
|||
|
|
@ -66,6 +66,9 @@ function LFeatureMarker() { $.extend(this, new LMarker(), new FeatureMarker());
|
|||
// Leaflet-Specific AprsMarker
|
||||
function LAprsMarker () { $.extend(this, new LMarker(), new AprsMarker()); }
|
||||
|
||||
// Leaflet-Specific AircraftMarker
|
||||
function LAircraftMarker () { $.extend(this, new LMarker(), new AircraftMarker()); }
|
||||
|
||||
//
|
||||
// Leaflet-Specific Locator
|
||||
//
|
||||
|
|
|
|||
|
|
@ -390,8 +390,7 @@ FeatureMarker.prototype.getInfoHTML = function(name, receiverMarker = null) {
|
|||
|
||||
//
|
||||
// APRS Marker
|
||||
// Represents APRS transmitters, as well as AIS (vessels)
|
||||
// and HFDL (planes).
|
||||
// Represents APRS transmitters, as well as AIS (vessels).
|
||||
// Derived classes have to implement:
|
||||
// setMarkerOpacity()
|
||||
//
|
||||
|
|
@ -700,3 +699,198 @@ AprsMarker.prototype.getInfoHTML = function(name, receiverMarker = null) {
|
|||
+ commentString + weatherString + detailsString
|
||||
+ messageString + hopsString;
|
||||
};
|
||||
|
||||
//
|
||||
// Aircraft Marker
|
||||
// Represents aircraft reported by various aeronautic services,
|
||||
// such as HFDL, ACARS, VDL2, and ADSB.
|
||||
// Derived classes have to implement:
|
||||
// setMarkerOpacity()
|
||||
//
|
||||
|
||||
function AircraftMarker() {}
|
||||
|
||||
AircraftMarker.prototype = new Marker();
|
||||
|
||||
AircraftMarker.prototype.update = function(update) {
|
||||
this.lastseen = update.lastseen;
|
||||
this.mode = update.mode;
|
||||
this.comment = update.location.comment;
|
||||
// HFDL, ACARS, VDL2, ADSB
|
||||
this.altitude = update.location.altitude;
|
||||
this.aircraft = update.location.aircraft;
|
||||
this.destination = update.location.destination;
|
||||
this.origin = update.location.origin;
|
||||
this.flight = update.location.flight;
|
||||
this.icao = update.location.icao;
|
||||
this.vspeed = update.location.vspeed;
|
||||
this.squawk = update.location.squawk;
|
||||
this.rssi = update.location.rssi;
|
||||
this.msglog = update.location.msglog;
|
||||
|
||||
// Implementation-dependent function call
|
||||
this.setMarkerPosition(update.callsign, update.location.lat, update.location.lon);
|
||||
|
||||
// Age locator
|
||||
this.age(new Date().getTime() - update.lastseen);
|
||||
};
|
||||
|
||||
AircraftMarker.prototype.draw = function() {
|
||||
var div = this.div;
|
||||
var overlay = this.overlay;
|
||||
if (!div || !overlay) return;
|
||||
|
||||
if (this.symbol) {
|
||||
var tableId = this.symbol.table === '/' ? 0 : 1;
|
||||
div.style.background = 'url(static/gfx/adsb-72.png)';
|
||||
div.style['background-size'] = '576px 792px';
|
||||
div.style['background-position-x'] = -this.symbol.x * 72 + 'px';
|
||||
div.style['background-position-y'] = -this.symbol.y * 72 + 'px';
|
||||
}
|
||||
|
||||
// If aircraft is flying at a significant altitude...
|
||||
if (this.altitude >= 500) {
|
||||
// r = elevation, a = rotation, <x,y> = shadow offset
|
||||
var r = Math.round(this.altitude / 1000);
|
||||
var a = - Math.PI * (this.course? this.course - 45 : -45) / 180;
|
||||
var x = r * Math.cos(a);
|
||||
var y = r * Math.sin(a);
|
||||
div.style.filter = 'drop-shadow(' + x + 'px ' + y + 'px 0.5px rgba(0,0,0,0.5))';
|
||||
} else {
|
||||
div.style.filter = 'none';
|
||||
}
|
||||
|
||||
div.style.transform = 'scale(0.5)';
|
||||
|
||||
if (this.course) {
|
||||
div.style.transform += ' rotate(' + this.course + 'deg)';
|
||||
}
|
||||
|
||||
if (this.symbol && this.symbol.table !== '/' && this.symbol.table !== '\\') {
|
||||
overlay.style.display = 'block';
|
||||
overlay.style['background-position-x'] = -this.symbol.x * 72 + 'px';
|
||||
overlay.style['background-position-y'] = -this.symbol.y * 72 + 'px';
|
||||
} else {
|
||||
overlay.style.display = 'none';
|
||||
}
|
||||
|
||||
if (this.opacity) {
|
||||
div.style.opacity = this.opacity;
|
||||
} else {
|
||||
div.style.opacity = null;
|
||||
}
|
||||
|
||||
if (this.place) this.place();
|
||||
};
|
||||
|
||||
AircraftMarker.prototype.create = function() {
|
||||
var div = this.div = document.createElement('div');
|
||||
|
||||
div.style.position = 'absolute';
|
||||
div.style.cursor = 'pointer';
|
||||
div.style.width = '72px';
|
||||
div.style.height = '72px';
|
||||
|
||||
var overlay = this.overlay = document.createElement('div');
|
||||
overlay.style.width = '72px';
|
||||
overlay.style.height = '72px';
|
||||
overlay.style.background = 'url(static/gfx/adsb-72.png)';
|
||||
overlay.style['background-size'] = '576px 792px';
|
||||
overlay.style.display = 'none';
|
||||
|
||||
div.appendChild(overlay);
|
||||
|
||||
return div;
|
||||
};
|
||||
|
||||
AircraftMarker.prototype.getAnchorOffset = function() {
|
||||
return [0, -12];
|
||||
};
|
||||
|
||||
AircraftMarker.prototype.getInfoHTML = function(name, receiverMarker = null) {
|
||||
var timeString = moment(this.lastseen).fromNow();
|
||||
var commentString = '';
|
||||
var detailsString = '';
|
||||
var messageString = '';
|
||||
var distance = '';
|
||||
|
||||
if (this.comment) {
|
||||
commentString += '<div>' + Marker.makeListTitle('Comment') + '<div>' +
|
||||
this.comment + '</div></div>';
|
||||
}
|
||||
|
||||
if (this.msglog) {
|
||||
messageString += '<div>' + Marker.makeListTitle('Messages') +
|
||||
'<pre class="openwebrx-map-console">' +
|
||||
this.msglog.join('\n<hr>') + '</pre></div>';
|
||||
}
|
||||
|
||||
if (this.icao) {
|
||||
detailsString += Marker.makeListItem('ICAO', Marker.linkify(this.icao, modes_url));
|
||||
}
|
||||
|
||||
if (this.aircraft) {
|
||||
detailsString += Marker.makeListItem('Aircraft', Marker.linkify(this.aircraft, flight_url));
|
||||
}
|
||||
|
||||
if (this.squawk) {
|
||||
detailsString += Marker.makeListItem('Squawk', this.squawk);
|
||||
}
|
||||
|
||||
if (this.origin) {
|
||||
detailsString += Marker.makeListItem('Origin', this.origin);
|
||||
}
|
||||
|
||||
if (this.destination) {
|
||||
detailsString += Marker.makeListItem('Destination', this.destination);
|
||||
}
|
||||
|
||||
// Combine course and speed if both present
|
||||
if (this.course && this.speed) {
|
||||
detailsString += Marker.makeListItem('Course',
|
||||
Marker.degToCompass(this.course) + ' ' +
|
||||
this.speed.toFixed(1) + ' km/h'
|
||||
);
|
||||
} else {
|
||||
if (this.course) {
|
||||
detailsString += Marker.makeListItem('Course', Marker.degToCompass(this.course));
|
||||
}
|
||||
if (this.speed) {
|
||||
detailsString += Marker.makeListItem('Speed', this.speed.toFixed(1) + ' km/h');
|
||||
}
|
||||
}
|
||||
|
||||
// Combine altitude and vertical speed
|
||||
if (this.altitude) {
|
||||
var alt = this.altitude.toFixed(0) + ' m';
|
||||
if (this.vspeed > 0) alt += ' ↗' + this.vspeed + ' m/m';
|
||||
else if (this.vspeed < 0) alt += ' ↘' + (-this.vspeed) + ' m/m';
|
||||
detailsString += Marker.makeListItem('Altitude', alt);
|
||||
}
|
||||
|
||||
if (this.rssi) {
|
||||
detailsString += Marker.makeListItem('RSSI', this.rssi + ' dB');
|
||||
}
|
||||
|
||||
if (detailsString.length > 0) {
|
||||
detailsString = '<div>' + Marker.makeListTitle('Details') + detailsString + '</div>';
|
||||
}
|
||||
|
||||
if (receiverMarker) {
|
||||
distance = ' at ' + Marker.distanceKm(receiverMarker.position, this.position) + ' km';
|
||||
}
|
||||
|
||||
// Linkify title based on what it is (vessel, flight, mode-S code, or else)
|
||||
var url = modes_url;
|
||||
if (this.flight) {
|
||||
name = this.flight;
|
||||
url = this.flight.match(/^[A-Z]{3}[0-9]+[A-Z]*$/)? flight_url : null;
|
||||
} else if (this.aircraft) {
|
||||
name = this.aircraft;
|
||||
url = flight_url;
|
||||
}
|
||||
|
||||
return '<h3>' + Marker.linkify(name, url) + distance + '</h3>'
|
||||
+ '<div align="center">' + timeString + ' using ' + this.mode + '</div>'
|
||||
+ commentString + detailsString + messageString;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -160,13 +160,24 @@ MapManager.prototype.processUpdates = function(updates) {
|
|||
case 'latlon':
|
||||
var marker = self.mman.find(update.callsign);
|
||||
var markerClass = GSimpleMarker;
|
||||
var aprsOptions = {}
|
||||
var options = {}
|
||||
|
||||
switch(update.mode) {
|
||||
case 'HFDL': case 'VDL2': case 'ADSB': case 'ACARS':
|
||||
markerClass = GAircraftMarker;
|
||||
break;
|
||||
case 'APRS': case 'AIS':
|
||||
markerClass = GAprsMarker;
|
||||
break;
|
||||
}
|
||||
|
||||
options.color = update.location.color?
|
||||
update.location.color : self.mman.getColor(update.mode);
|
||||
|
||||
if (update.location.symbol) {
|
||||
markerClass = GAprsMarker;
|
||||
aprsOptions.symbol = update.location.symbol;
|
||||
aprsOptions.course = update.location.course;
|
||||
aprsOptions.speed = update.location.speed;
|
||||
options.symbol = update.location.symbol;
|
||||
options.course = update.location.course;
|
||||
options.speed = update.location.speed;
|
||||
}
|
||||
|
||||
// If new item, create a new marker for it
|
||||
|
|
@ -188,7 +199,7 @@ MapManager.prototype.processUpdates = function(updates) {
|
|||
marker.setMap(self.mman.isEnabled(update.mode)? map : undefined);
|
||||
|
||||
// Apply marker options
|
||||
marker.setMarkerOptions(aprsOptions);
|
||||
marker.setMarkerOptions(options);
|
||||
|
||||
if (expectedCallsign && expectedCallsign == update.callsign) {
|
||||
map.panTo(marker.position);
|
||||
|
|
@ -206,16 +217,10 @@ MapManager.prototype.processUpdates = function(updates) {
|
|||
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);
|
||||
}
|
||||
options.symbol = update.location.symbol?
|
||||
update.location.symbol : self.mman.getSymbol(update.mode);
|
||||
options.color = update.location.color?
|
||||
update.location.color : self.mman.getColor(update.mode);
|
||||
|
||||
// If new item, create a new marker for it
|
||||
if (!marker) {
|
||||
|
|
|
|||
|
|
@ -39,30 +39,30 @@ MODE_S_FORMATS = [
|
|||
# Aircraft categories
|
||||
#
|
||||
ADSB_CATEGORIES = {
|
||||
"A0": ("^", "/"), # No ADS-B emitter category information
|
||||
"A1": ("'", "/"), # Light (< 15500 lbs)
|
||||
"A2": ("'", "/"), # Small (15500 to 75000 lbs)
|
||||
"A3": ("^", "/"), # Large (75000 to 300000 lbs)
|
||||
"A4": ("^", "/"), # High vortex large (aircraft such as B-757)
|
||||
"A5": ("^", "/"), # Heavy (> 300000 lbs)
|
||||
"A6": ("^", "/"), # High performance (> 5g acceleration and 400 kts)
|
||||
"A7": ("X", "/"), # Rotorcraft, regardless of weight
|
||||
"B0": ("^", "/"), # No ADS-B emitter category information
|
||||
"B1": ("g", "/"), # Glider or sailplane, regardless of weight
|
||||
"B2": ("O", "/"), # Airship or balloon, regardless of weight
|
||||
"B3": ("g", "/"), # Parachutist / skydiver
|
||||
"B4": ("g", "/"), # Ultralight / hang-glider / paraglider
|
||||
"B5": ("^", "/"), # Reserved
|
||||
"B6": ("S", "\\"), # Unmanned aerial vehicle, regardless of weight
|
||||
"B7": ("S", "/"), # Space / trans-atmospheric vehicle
|
||||
"C0": ("D", "/"), # No ADS-B emitter category information
|
||||
"C1": ("f", "/"), # Surface vehicle – emergency vehicle
|
||||
"C2": ("u", "\\"), # Surface vehicle – service vehicle
|
||||
"C3": ("D", "/"), # Point obstacle (includes tethered balloons)
|
||||
"C4": ("D", "/"), # Cluster obstacle
|
||||
"C5": ("D", "/"), # Line obstacle
|
||||
"C6": ("D", "/"), # Reserved
|
||||
"C7": ("D", "/"), # Reserved
|
||||
"A0": (0, 0), # No ADS-B emitter category information
|
||||
"A1": (3, 0), # Light (< 15500 lbs)
|
||||
"A2": (5, 0), # Small (15500 to 75000 lbs)
|
||||
"A3": (4, 0), # Large (75000 to 300000 lbs)
|
||||
"A4": (0, 0), # High vortex large (aircraft such as B-757)
|
||||
"A5": (1, 7), # Heavy (> 300000 lbs)
|
||||
"A6": (7, 0), # High performance (> 5g acceleration and 400 kts)
|
||||
"A7": (6, 5), # Rotorcraft, regardless of weight
|
||||
"B0": (0, 0), # No ADS-B emitter category information
|
||||
"B1": (1, 6), # Glider or sailplane, regardless of weight
|
||||
"B2": (2, 0), # Airship or balloon, regardless of weight
|
||||
"B3": (10, 0), # Parachutist / skydiver
|
||||
"B4": (10, 0), # Ultralight / hang-glider / paraglider
|
||||
"B5": (0, 0), # Reserved
|
||||
"B6": (4, 3), # Unmanned aerial vehicle, regardless of weight
|
||||
"B7": (4, 5), # Space / trans-atmospheric vehicle
|
||||
"C0": (4, 8), # No ADS-B emitter category information
|
||||
"C1": (2, 8), # Surface vehicle – emergency vehicle
|
||||
"C2": (3, 8), # Surface vehicle – service vehicle
|
||||
"C3": (5, 8), # Point obstacle (includes tethered balloons)
|
||||
"C4": (6, 9), # Cluster obstacle
|
||||
"C5": (2, 8), # Line obstacle
|
||||
"C6": (2, 8), # Reserved
|
||||
"C7": (2, 8), # Reserved
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -83,11 +83,10 @@ class AircraftLocation(LatLngLocation):
|
|||
if "category" in self.data and self.data["category"] in ADSB_CATEGORIES:
|
||||
# Add APRS-like symbol by aircraft category
|
||||
cat = ADSB_CATEGORIES[self.data["category"]]
|
||||
res["symbol"] = getSymbolData(cat[0], cat[1])
|
||||
res["symbol"] = { "x": cat[0], "y": cat[1] }
|
||||
else:
|
||||
# Add APRS-like aircraft symbol (red or blue, depending on mode)
|
||||
mod = '/' if self.data["mode"]=="ADSB" else '\\'
|
||||
res["symbol"] = getSymbolData('^', mod)
|
||||
res["symbol"] = { "x": 0, "y": 0 }
|
||||
# Convert aircraft-specific data into APRS-like data
|
||||
for x in ["icao", "aircraft", "flight", "speed", "altitude", "course", "destination", "origin", "vspeed", "squawk", "rssi", "msglog"]:
|
||||
if x in self.data:
|
||||
|
|
|
|||
Loading…
Reference in New Issue