2015-02-22 12:51:58 +01:00
// -*- mode: javascript; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2015-01-07 18:35:32 +01:00
"use strict" ;
2013-05-21 22:28:16 +02:00
// Define our global variables
2016-07-02 13:55:38 +02:00
var OLMap = null ;
var StaticFeatures = new ol . Collection ( ) ;
2016-08-22 23:48:17 +02:00
var SiteCircleFeatures = new ol . Collection ( ) ;
2016-07-02 13:55:38 +02:00
var PlaneIconFeatures = new ol . Collection ( ) ;
var PlaneTrailFeatures = new ol . Collection ( ) ;
2013-05-21 22:28:16 +02:00
var Planes = { } ;
2015-01-06 21:15:25 +01:00
var PlanesOrdered = [ ] ;
2016-08-24 22:28:13 +02:00
var PlaneFilter = { } ;
2013-05-21 22:28:16 +02:00
var SelectedPlane = null ;
2016-08-19 21:43:20 +02:00
var SelectedAllPlanes = false ;
2017-01-18 23:14:53 +01:00
var HighlightedPlane = null ;
2015-01-22 15:17:12 +01:00
var FollowSelected = false ;
2017-01-31 18:07:39 +01:00
var infoBoxOriginalPosition = { } ;
2017-02-22 19:17:18 +01:00
var customAltitudeColors = true ;
2013-05-18 23:54:59 +02:00
2015-01-07 17:32:58 +01:00
var SpecialSquawks = {
'7500' : { cssClass : 'squawk7500' , markerColor : 'rgb(255, 85, 85)' , text : 'Aircraft Hijacking' } ,
'7600' : { cssClass : 'squawk7600' , markerColor : 'rgb(0, 255, 255)' , text : 'Radio Failure' } ,
'7700' : { cssClass : 'squawk7700' , markerColor : 'rgb(255, 255, 0)' , text : 'General Emergency' }
2015-01-06 21:15:25 +01:00
} ;
2013-05-09 16:59:26 +02:00
2013-05-25 10:56:32 +02:00
// Get current map settings
2015-10-27 00:03:34 +01:00
var CenterLat , CenterLon , ZoomLvl , MapType ;
2013-05-25 10:56:32 +02:00
2015-01-07 17:32:58 +01:00
var Dump1090Version = "unknown version" ;
var RefreshInterval = 1000 ;
2014-12-10 18:05:22 +01:00
2015-01-07 17:32:58 +01:00
var PlaneRowTemplate = null ;
2015-01-06 21:15:25 +01:00
2015-01-07 17:32:58 +01:00
var TrackedAircraft = 0 ;
2015-01-07 18:35:32 +01:00
var TrackedAircraftPositions = 0 ;
var TrackedHistorySize = 0 ;
var SitePosition = null ;
2015-01-06 21:15:25 +01:00
2015-01-07 19:39:19 +01:00
var ReceiverClock = null ;
2015-01-07 19:43:08 +01:00
2015-02-11 01:15:48 +01:00
var LastReceiverTimestamp = 0 ;
2015-01-07 19:43:08 +01:00
var StaleReceiverCount = 0 ;
var FetchPending = null ;
2015-01-13 20:10:55 +01:00
var MessageCountHistory = [ ] ;
2015-02-22 12:51:58 +01:00
var MessageRate = 0 ;
2015-01-13 20:10:55 +01:00
2015-01-11 13:02:25 +01:00
var NBSP = '\u00a0' ;
2017-01-23 21:02:45 +01:00
var layers ;
2017-01-26 23:32:45 +01:00
// piaware vs flightfeeder
var isFlightFeeder = false ;
2015-01-15 22:01:14 +01:00
function processReceiverUpdate ( data ) {
// Loop through all the planes in the data packet
var now = data . now ;
var acs = data . aircraft ;
// Detect stats reset
if ( MessageCountHistory . length > 0 && MessageCountHistory [ MessageCountHistory . length - 1 ] . messages > data . messages ) {
2015-08-30 18:16:40 +02:00
MessageCountHistory = [ { 'time' : MessageCountHistory [ MessageCountHistory . length - 1 ] . time ,
'messages' : 0 } ] ;
2015-01-15 22:01:14 +01:00
}
// Note the message count in the history
MessageCountHistory . push ( { 'time' : now , 'messages' : data . messages } ) ;
// .. and clean up any old values
if ( ( now - MessageCountHistory [ 0 ] . time ) > 30 )
MessageCountHistory . shift ( ) ;
for ( var j = 0 ; j < acs . length ; j ++ ) {
var ac = acs [ j ] ;
var hex = ac . hex ;
2016-09-07 21:20:42 +02:00
var squawk = ac . squawk ;
2015-01-15 22:01:14 +01:00
var plane = null ;
// Do we already have this plane object in Planes?
// If not make it.
2016-10-25 22:09:27 +02:00
if ( Planes [ hex ] ) {
2015-01-15 22:01:14 +01:00
plane = Planes [ hex ] ;
} else {
plane = new PlaneObject ( hex ) ;
2016-08-24 22:28:13 +02:00
plane . filter = PlaneFilter ;
2015-01-15 22:01:14 +01:00
plane . tr = PlaneRowTemplate . cloneNode ( true ) ;
2015-08-22 02:38:38 +02:00
2015-01-22 14:21:47 +01:00
if ( hex [ 0 ] === '~' ) {
// Non-ICAO address
plane . tr . cells [ 0 ] . textContent = hex . substring ( 1 ) ;
2015-01-22 23:19:17 +01:00
$ ( plane . tr ) . css ( 'font-style' , 'italic' ) ;
2015-08-30 18:16:40 +02:00
} else {
plane . tr . cells [ 0 ] . textContent = hex ;
2015-09-01 13:19:23 +02:00
}
// set flag image if available
if ( ShowFlags && plane . icaorange . flag _image !== null ) {
$ ( 'img' , plane . tr . cells [ 1 ] ) . attr ( 'src' , FlagPath + plane . icaorange . flag _image ) ;
$ ( 'img' , plane . tr . cells [ 1 ] ) . attr ( 'title' , plane . icaorange . country ) ;
} else {
$ ( 'img' , plane . tr . cells [ 1 ] ) . css ( 'display' , 'none' ) ;
2015-01-22 14:21:47 +01:00
}
2016-10-25 22:09:27 +02:00
plane . tr . addEventListener ( 'click' , function ( h , evt ) {
if ( evt . srcElement instanceof HTMLAnchorElement ) {
evt . stopPropagation ( ) ;
return ;
}
if ( ! $ ( "#map_container" ) . is ( ":visible" ) ) {
showMap ( ) ;
}
selectPlaneByHex ( h , false ) ;
adjustSelectedInfoBlockPosition ( ) ;
evt . preventDefault ( ) ;
} . bind ( undefined , hex ) ) ;
plane . tr . addEventListener ( 'dblclick' , function ( h , evt ) {
if ( ! $ ( "#map_container" ) . is ( ":visible" ) ) {
showMap ( ) ;
}
selectPlaneByHex ( h , true ) ;
adjustSelectedInfoBlockPosition ( ) ;
evt . preventDefault ( ) ;
} . bind ( undefined , hex ) ) ;
Planes [ hex ] = plane ;
2015-01-15 22:01:14 +01:00
PlanesOrdered . push ( plane ) ;
}
// Call the function update
plane . updateData ( now , ac ) ;
}
}
2013-05-21 22:28:16 +02:00
function fetchData ( ) {
2015-01-07 19:43:08 +01:00
if ( FetchPending !== null && FetchPending . state ( ) == 'pending' ) {
// don't double up on fetches, let the last one resolve
return ;
}
FetchPending = $ . ajax ( { url : 'data/aircraft.json' ,
timeout : 5000 ,
cache : false ,
dataType : 'json' } ) ;
FetchPending . done ( function ( data ) {
2015-01-06 00:20:03 +01:00
var now = data . now ;
2015-01-13 20:10:55 +01:00
2015-01-15 22:01:14 +01:00
processReceiverUpdate ( data ) ;
2015-01-07 02:19:05 +01:00
// update timestamps, visibility, history track for all planes - not only those updated
for ( var i = 0 ; i < PlanesOrdered . length ; ++ i ) {
var plane = PlanesOrdered [ i ] ;
2015-02-11 01:15:48 +01:00
plane . updateTick ( now , LastReceiverTimestamp ) ;
2015-01-07 02:19:05 +01:00
}
2019-11-03 17:00:53 +01:00
2016-08-19 21:43:20 +02:00
selectNewPlanes ( ) ;
2015-01-06 21:15:25 +01:00
refreshTableInfo ( ) ;
refreshSelected ( ) ;
2017-01-18 23:14:53 +01:00
refreshHighlighted ( ) ;
2019-11-03 17:00:53 +01:00
2015-01-07 19:39:19 +01:00
if ( ReceiverClock ) {
var rcv = new Date ( now * 1000 ) ;
ReceiverClock . render ( rcv . getUTCHours ( ) , rcv . getUTCMinutes ( ) , rcv . getUTCSeconds ( ) ) ;
}
2015-01-07 19:43:08 +01:00
// Check for stale receiver data
if ( LastReceiverTimestamp === now ) {
StaleReceiverCount ++ ;
if ( StaleReceiverCount > 5 ) {
$ ( "#update_error_detail" ) . text ( "The data from dump1090 hasn't been updated in a while. Maybe dump1090 is no longer running?" ) ;
$ ( "#update_error" ) . css ( 'display' , 'block' ) ;
}
2019-11-03 17:00:53 +01:00
} else {
2015-01-07 19:43:08 +01:00
StaleReceiverCount = 0 ;
LastReceiverTimestamp = now ;
$ ( "#update_error" ) . css ( 'display' , 'none' ) ;
}
2013-05-21 22:28:16 +02:00
} ) ;
2015-01-07 19:43:08 +01:00
FetchPending . fail ( function ( jqxhr , status , error ) {
$ ( "#update_error_detail" ) . text ( "AJAX call failed (" + status + ( error ? ( ": " + error ) : "" ) + "). Maybe dump1090 is no longer running?" ) ;
$ ( "#update_error" ) . css ( 'display' , 'block' ) ;
} ) ;
2013-05-09 16:59:26 +02:00
}
2015-01-15 22:01:14 +01:00
var PositionHistorySize = 0 ;
2013-05-21 22:28:16 +02:00
function initialize ( ) {
2015-01-22 15:33:42 +01:00
// Set page basics
2015-02-22 12:51:58 +01:00
document . title = PageName ;
2017-01-26 23:32:45 +01:00
flightFeederCheck ( ) ;
2015-01-22 15:33:42 +01:00
2015-01-06 21:15:25 +01:00
PlaneRowTemplate = document . getElementById ( "plane_row_template" ) ;
2017-01-19 23:21:55 +01:00
refreshClock ( ) ;
2015-01-15 23:23:15 +01:00
$ ( "#loader" ) . removeClass ( "hidden" ) ;
2018-05-09 16:20:45 +02:00
2018-05-09 16:33:26 +02:00
if ( ExtendedData || window . location . hash == '#extended' ) {
2018-05-09 16:20:45 +02:00
$ ( "#extendedData" ) . removeClass ( "hidden" ) ;
}
2016-08-18 22:48:57 +02:00
// Set up map/sidebar splitter
2018-07-31 00:51:18 +02:00
$ ( "#sidebar_container" ) . resizable ( {
handles : {
w : '#splitter'
} ,
minWidth : 350
} ) ;
// Set up datablock splitter
$ ( '#selected_infoblock' ) . resizable ( {
handles : {
s : '#splitter-infoblock'
} ,
containment : "#sidebar_container" ,
minHeight : 50
} ) ;
2016-08-18 22:48:57 +02:00
2018-07-31 23:12:03 +02:00
$ ( '#close-button' ) . on ( 'click' , function ( ) {
if ( SelectedPlane !== null ) {
var selectedPlane = Planes [ SelectedPlane ] ;
SelectedPlane = null ;
selectedPlane . selected = null ;
selectedPlane . clearLines ( ) ;
2019-11-03 17:00:53 +01:00
selectedPlane . updateMarker ( ) ;
2018-07-31 23:12:03 +02:00
refreshSelected ( ) ;
refreshHighlighted ( ) ;
$ ( '#selected_infoblock' ) . hide ( ) ;
}
} ) ;
2018-07-31 00:51:18 +02:00
// this is a little hacky, but the best, most consitent way of doing this. change the margin bottom of the table container to the height of the overlay
$ ( '#selected_infoblock' ) . on ( 'resize' , function ( ) {
$ ( '#sidebar_canvas' ) . css ( 'margin-bottom' , $ ( ' # selected _infoblock ').height() + ' px ' ) ;
} ) ;
// look at the window resize to resize the pop-up infoblock so it doesn't float off the bottom or go off the top
$ ( window ) . on ( 'resize' , function ( ) {
var topCalc = ( $ ( window ) . height ( ) - $ ( '#selected_infoblock' ) . height ( ) - 60 ) ;
2019-11-03 17:00:53 +01:00
// check if the top will be less than zero, which will be overlapping/off the screen, and set the top correctly.
2018-07-31 00:51:18 +02:00
if ( topCalc < 0 ) {
topCalc = 0 ;
$ ( '#selected_infoblock' ) . css ( 'height' , ( $ ( window ) . height ( ) - 60 ) + 'px' ) ;
}
$ ( '#selected_infoblock' ) . css ( 'top' , topCalc + 'px' ) ;
} ) ;
2016-08-31 22:45:29 +02:00
2019-11-03 17:00:53 +01:00
// to make the infoblock responsive
2018-07-31 00:51:18 +02:00
$ ( '#sidebar_container' ) . on ( 'resize' , function ( ) {
if ( $ ( '#sidebar_container' ) . width ( ) < 500 ) {
$ ( '#selected_infoblock' ) . addClass ( 'infoblock-container-small' ) ;
} else {
$ ( '#selected_infoblock' ) . removeClass ( 'infoblock-container-small' ) ;
}
} ) ;
2019-11-03 17:00:53 +01:00
2016-08-20 00:57:20 +02:00
// Set up event handlers for buttons
2016-08-18 22:48:57 +02:00
$ ( "#toggle_sidebar_button" ) . click ( toggleSidebarVisibility ) ;
2016-08-19 17:58:48 +02:00
$ ( "#expand_sidebar_button" ) . click ( expandSidebar ) ;
2016-08-20 00:57:20 +02:00
$ ( "#show_map_button" ) . click ( showMap ) ;
2016-08-19 17:58:48 +02:00
2016-08-20 00:57:20 +02:00
// Set initial element visibility
2016-08-19 17:58:48 +02:00
$ ( "#show_map_button" ) . hide ( ) ;
2016-08-20 00:37:43 +02:00
setColumnVisibility ( ) ;
2016-08-19 17:58:48 +02:00
2016-08-22 23:48:17 +02:00
// Initialize other controls
initializeUnitsSelector ( ) ;
2016-08-24 22:28:13 +02:00
// Set up altitude filter button event handlers and validation options
$ ( "#altitude_filter_form" ) . submit ( onFilterByAltitude ) ;
$ ( "#altitude_filter_form" ) . validate ( {
errorPlacement : function ( error , element ) {
return true ;
} ,
2019-11-03 17:00:53 +01:00
2016-08-24 22:28:13 +02:00
rules : {
minAltitude : {
number : true ,
min : - 99999 ,
max : 99999
} ,
maxAltitude : {
number : true ,
min : - 99999 ,
max : 99999
}
}
} ) ;
2017-02-22 19:17:18 +01:00
// check if the altitude color values are default to enable the altitude filter
if ( ColorByAlt . air . h . length === 3 && ColorByAlt . air . h [ 0 ] . alt === 2000 && ColorByAlt . air . h [ 0 ] . val === 20 && ColorByAlt . air . h [ 1 ] . alt === 10000 && ColorByAlt . air . h [ 1 ] . val === 140 && ColorByAlt . air . h [ 2 ] . alt === 40000 && ColorByAlt . air . h [ 2 ] . val === 300 ) {
customAltitudeColors = false ;
}
2016-08-24 22:28:13 +02:00
$ ( "#altitude_filter_reset_button" ) . click ( onResetAltitudeFilter ) ;
2017-01-23 21:02:45 +01:00
$ ( '#settingsCog' ) . on ( 'click' , function ( ) {
$ ( '#settings_infoblock' ) . toggle ( ) ;
} ) ;
2017-01-30 21:23:23 +01:00
$ ( '#settings_close' ) . on ( 'click' , function ( ) {
$ ( '#settings_infoblock' ) . hide ( ) ;
} ) ;
2017-01-26 20:38:47 +01:00
$ ( '#groundvehicle_filter' ) . on ( 'click' , function ( ) {
filterGroundVehicles ( true ) ;
refreshSelected ( ) ;
refreshHighlighted ( ) ;
refreshTableInfo ( ) ;
} ) ;
$ ( '#blockedmlat_filter' ) . on ( 'click' , function ( ) {
filterBlockedMLAT ( true ) ;
refreshSelected ( ) ;
refreshHighlighted ( ) ;
refreshTableInfo ( ) ;
} ) ;
2017-01-23 21:02:45 +01:00
$ ( '#grouptype_checkbox' ) . on ( 'click' , function ( ) {
if ( $ ( '#grouptype_checkbox' ) . hasClass ( 'settingsCheckboxChecked' ) ) {
2017-01-26 20:38:47 +01:00
sortByDistance ( ) ;
2017-01-23 21:02:45 +01:00
} else {
sortByDataSource ( ) ;
}
2019-11-03 17:00:53 +01:00
2017-01-23 21:02:45 +01:00
} ) ;
2017-02-10 21:41:48 +01:00
$ ( '#altitude_checkbox' ) . on ( 'click' , function ( ) {
toggleAltitudeChart ( true ) ;
} ) ;
2017-01-23 21:02:45 +01:00
$ ( '#selectall_checkbox' ) . on ( 'click' , function ( ) {
if ( $ ( '#selectall_checkbox' ) . hasClass ( 'settingsCheckboxChecked' ) ) {
deselectAllPlanes ( ) ;
} else {
selectAllPlanes ( ) ;
}
} )
2016-08-18 22:48:57 +02:00
// Force map to redraw if sidebar container is resized - use a timer to debounce
var mapResizeTimeout ;
$ ( "#sidebar_container" ) . on ( "resize" , function ( ) {
clearTimeout ( mapResizeTimeout ) ;
2016-08-20 01:45:39 +02:00
mapResizeTimeout = setTimeout ( updateMapSize , 10 ) ;
2016-08-18 22:48:57 +02:00
} ) ;
2017-01-26 20:38:47 +01:00
filterGroundVehicles ( false ) ;
filterBlockedMLAT ( false ) ;
2017-02-10 21:41:48 +01:00
toggleAltitudeChart ( false ) ;
2017-01-26 20:38:47 +01:00
2014-12-10 18:05:22 +01:00
// Get receiver metadata, reconfigure using it, then continue
// with initialization
2015-01-17 22:02:17 +01:00
$ . ajax ( { url : 'data/receiver.json' ,
timeout : 5000 ,
cache : false ,
dataType : 'json' } )
2014-12-10 18:05:22 +01:00
. done ( function ( data ) {
2014-12-10 22:34:05 +01:00
if ( typeof data . lat !== "undefined" ) {
2014-12-10 18:05:22 +01:00
SiteShow = true ;
2014-12-10 22:34:05 +01:00
SiteLat = data . lat ;
SiteLon = data . lon ;
2015-01-08 00:54:54 +01:00
DefaultCenterLat = data . lat ;
DefaultCenterLon = data . lon ;
2014-12-10 18:05:22 +01:00
}
2019-11-03 17:00:53 +01:00
2014-12-10 18:05:22 +01:00
Dump1090Version = data . version ;
RefreshInterval = data . refresh ;
2015-01-15 22:01:14 +01:00
PositionHistorySize = data . history ;
} )
2015-01-17 22:02:17 +01:00
2015-01-15 22:01:14 +01:00
. always ( function ( ) {
initialize _map ( ) ;
start _load _history ( ) ;
} ) ;
}
var CurrentHistoryFetch = null ;
2018-07-31 00:51:18 +02:00
var PositionHistoryBuffer = [ ] ;
2017-07-29 18:52:24 +02:00
var HistoryItemsReturned = 0 ;
2015-01-15 22:01:14 +01:00
function start _load _history ( ) {
2018-07-31 00:51:18 +02:00
if ( PositionHistorySize > 0 && window . location . hash != '#nohistory' ) {
$ ( "#loader_progress" ) . attr ( 'max' , PositionHistorySize ) ;
console . log ( "Starting to load history (" + PositionHistorySize + " items)" ) ;
//Load history items in parallel
for ( var i = 0 ; i < PositionHistorySize ; i ++ ) {
load _history _item ( i ) ;
}
2019-03-04 16:17:16 +01:00
} else {
// Nothing to load
end _load _history ( ) ;
2018-07-31 00:51:18 +02:00
}
2015-01-15 22:01:14 +01:00
}
function load _history _item ( i ) {
console . log ( "Loading history #" + i ) ;
2018-07-31 00:51:18 +02:00
$ ( "#loader_progress" ) . attr ( 'value' , i ) ;
2015-01-15 22:01:14 +01:00
$ . ajax ( { url : 'data/history_' + i + '.json' ,
timeout : 5000 ,
cache : false ,
dataType : 'json' } )
. done ( function ( data ) {
2018-07-31 00:51:18 +02:00
PositionHistoryBuffer . push ( data ) ;
HistoryItemsReturned ++ ;
$ ( "#loader_progress" ) . attr ( 'value' , HistoryItemsReturned ) ;
if ( HistoryItemsReturned == PositionHistorySize ) {
end _load _history ( ) ;
}
2014-12-10 18:05:22 +01:00
} )
2015-01-15 22:01:14 +01:00
. fail ( function ( jqxhr , status , error ) {
2018-07-31 00:51:18 +02:00
//Doesn't matter if it failed, we'll just be missing a data point
HistoryItemsReturned ++ ;
if ( HistoryItemsReturned == PositionHistorySize ) {
end _load _history ( ) ;
}
2015-01-15 22:01:14 +01:00
} ) ;
}
function end _load _history ( ) {
$ ( "#loader" ) . addClass ( "hidden" ) ;
console . log ( "Done loading history" ) ;
if ( PositionHistoryBuffer . length > 0 ) {
var now , last = 0 ;
// Sort history by timestamp
console . log ( "Sorting history" ) ;
PositionHistoryBuffer . sort ( function ( x , y ) { return ( x . now - y . now ) ; } ) ;
// Process history
for ( var h = 0 ; h < PositionHistoryBuffer . length ; ++ h ) {
now = PositionHistoryBuffer [ h ] . now ;
2017-07-29 20:18:56 +02:00
console . log ( "Applying history " + ( h + 1 ) + "/" + PositionHistoryBuffer . length + " at: " + now ) ;
2015-01-15 22:01:14 +01:00
processReceiverUpdate ( PositionHistoryBuffer [ h ] ) ;
// update track
console . log ( "Updating tracks at: " + now ) ;
for ( var i = 0 ; i < PlanesOrdered . length ; ++ i ) {
var plane = PlanesOrdered [ i ] ;
2019-07-27 17:50:41 +02:00
plane . updateTrack ( now , last ) ;
2015-01-15 22:01:14 +01:00
}
last = now ;
}
// Final pass to update all planes to their latest state
console . log ( "Final history cleanup pass" ) ;
for ( var i = 0 ; i < PlanesOrdered . length ; ++ i ) {
var plane = PlanesOrdered [ i ] ;
plane . updateTick ( now ) ;
}
2015-02-11 01:15:48 +01:00
LastReceiverTimestamp = last ;
2015-01-15 22:01:14 +01:00
}
PositionHistoryBuffer = null ;
console . log ( "Completing init" ) ;
refreshTableInfo ( ) ;
refreshSelected ( ) ;
2017-01-18 23:14:53 +01:00
refreshHighlighted ( ) ;
2015-01-15 22:01:14 +01:00
reaper ( ) ;
// Setup our timer to poll from the server.
window . setInterval ( fetchData , RefreshInterval ) ;
window . setInterval ( reaper , 60000 ) ;
2015-02-11 01:15:21 +01:00
// And kick off one refresh immediately.
fetchData ( ) ;
2014-12-10 18:05:22 +01:00
}
2016-07-24 17:13:04 +02:00
// Make a LineString with 'points'-number points
// that is a closed circle on the sphere such that the
// great circle distance from 'center' to each point is
// 'radius' meters
function make _geodesic _circle ( center , radius , points ) {
var angularDistance = radius / 6378137.0 ;
var lon1 = center [ 0 ] * Math . PI / 180.0 ;
var lat1 = center [ 1 ] * Math . PI / 180.0 ;
var geom = new ol . geom . LineString ( ) ;
for ( var i = 0 ; i <= points ; ++ i ) {
var bearing = i * 2 * Math . PI / points ;
var lat2 = Math . asin ( Math . sin ( lat1 ) * Math . cos ( angularDistance ) +
Math . cos ( lat1 ) * Math . sin ( angularDistance ) * Math . cos ( bearing ) ) ;
var lon2 = lon1 + Math . atan2 ( Math . sin ( bearing ) * Math . sin ( angularDistance ) * Math . cos ( lat1 ) ,
Math . cos ( angularDistance ) - Math . sin ( lat1 ) * Math . sin ( lat2 ) ) ;
lat2 = lat2 * 180.0 / Math . PI ;
lon2 = lon2 * 180.0 / Math . PI ;
geom . appendCoordinate ( [ lon2 , lat2 ] ) ;
}
return geom ;
}
2014-12-10 18:05:22 +01:00
// Initalizes the map and starts up our timers to call various functions
2015-01-15 22:01:14 +01:00
function initialize _map ( ) {
2015-01-08 00:54:54 +01:00
// Load stored map settings if present
2019-11-03 17:00:53 +01:00
CenterLat = DefaultCenterLat ;
CenterLon = DefaultCenterLon ;
ZoomLvl = DefaultZoomLvl ;
2016-07-02 22:12:31 +02:00
MapType = localStorage [ 'MapType' ] ;
2015-01-06 21:15:25 +01:00
2015-01-08 00:54:54 +01:00
// Set SitePosition, initialize sorting
2015-01-06 21:15:25 +01:00
if ( SiteShow && ( typeof SiteLat !== 'undefined' ) && ( typeof SiteLon !== 'undefined' ) ) {
2016-07-02 13:55:38 +02:00
SitePosition = [ SiteLon , SiteLat ] ;
2015-01-06 21:15:25 +01:00
sortByDistance ( ) ;
} else {
SitePosition = null ;
2016-09-12 23:06:25 +02:00
PlaneRowTemplate . cells [ 9 ] . style . display = 'none' ; // hide distance column
2015-01-07 02:19:05 +01:00
document . getElementById ( "distance" ) . style . display = 'none' ; // hide distance header
2015-01-06 21:15:25 +01:00
sortByAltitude ( ) ;
}
2015-09-01 13:19:23 +02:00
// Maybe hide flag info
if ( ! ShowFlags ) {
PlaneRowTemplate . cells [ 1 ] . style . display = 'none' ; // hide flag column
document . getElementById ( "flag" ) . style . display = 'none' ; // hide flag header
document . getElementById ( "infoblock_country" ) . style . display = 'none' ; // hide country row
}
2016-08-04 22:18:54 +02:00
// Initialize OL3
2015-10-26 13:59:38 +01:00
2017-01-23 21:02:45 +01:00
layers = createBaseLayers ( ) ;
2015-10-26 13:59:38 +01:00
2016-07-02 13:55:38 +02:00
var iconsLayer = new ol . layer . Vector ( {
2016-08-04 22:18:54 +02:00
name : 'ac_positions' ,
type : 'overlay' ,
2016-07-03 14:55:14 +02:00
title : 'Aircraft positions' ,
2016-07-02 19:45:03 +02:00
source : new ol . source . Vector ( {
features : PlaneIconFeatures ,
} )
2016-07-02 13:55:38 +02:00
} ) ;
2016-07-03 14:55:14 +02:00
layers . push ( new ol . layer . Group ( {
title : 'Overlays' ,
layers : [
new ol . layer . Vector ( {
2016-08-04 22:18:54 +02:00
name : 'site_pos' ,
type : 'overlay' ,
2016-07-03 14:55:14 +02:00
title : 'Site position and range rings' ,
source : new ol . source . Vector ( {
features : StaticFeatures ,
} )
} ) ,
new ol . layer . Vector ( {
2016-08-04 22:18:54 +02:00
name : 'ac_trail' ,
type : 'overlay' ,
2016-07-03 14:55:14 +02:00
title : 'Selected aircraft trail' ,
source : new ol . source . Vector ( {
features : PlaneTrailFeatures ,
} )
} ) ,
2016-07-03 15:54:36 +02:00
iconsLayer
2016-07-03 14:55:14 +02:00
]
} ) ) ;
2016-07-02 13:55:38 +02:00
2016-08-04 22:18:54 +02:00
var foundType = false ;
2017-02-03 17:50:37 +01:00
var baseCount = 0 ;
2016-08-04 22:18:54 +02:00
ol . control . LayerSwitcher . forEachRecursive ( layers , function ( lyr ) {
if ( ! lyr . get ( 'name' ) )
return ;
if ( lyr . get ( 'type' ) === 'base' ) {
2017-02-03 17:50:37 +01:00
baseCount ++ ;
2016-08-04 22:18:54 +02:00
if ( MapType === lyr . get ( 'name' ) ) {
foundType = true ;
lyr . setVisible ( true ) ;
} else {
lyr . setVisible ( false ) ;
}
lyr . on ( 'change:visible' , function ( evt ) {
if ( evt . target . getVisible ( ) ) {
MapType = localStorage [ 'MapType' ] = evt . target . get ( 'name' ) ;
}
} ) ;
} else if ( lyr . get ( 'type' ) === 'overlay' ) {
var visible = localStorage [ 'layer_' + lyr . get ( 'name' ) ] ;
if ( visible != undefined ) {
// javascript, why must you taunt me with gratuitous type problems
lyr . setVisible ( visible === "true" ) ;
}
lyr . on ( 'change:visible' , function ( evt ) {
localStorage [ 'layer_' + evt . target . get ( 'name' ) ] = evt . target . getVisible ( ) ;
} ) ;
}
} )
if ( ! foundType ) {
ol . control . LayerSwitcher . forEachRecursive ( layers , function ( lyr ) {
if ( foundType )
return ;
if ( lyr . get ( 'type' ) === 'base' ) {
lyr . setVisible ( true ) ;
foundType = true ;
}
} ) ;
}
OLMap = new ol . Map ( {
2016-07-02 13:55:38 +02:00
target : 'map_canvas' ,
2016-07-02 22:12:31 +02:00
layers : layers ,
2016-07-02 13:55:38 +02:00
view : new ol . View ( {
center : ol . proj . fromLonLat ( [ CenterLon , CenterLat ] ) ,
zoom : ZoomLvl
2016-07-02 18:09:16 +02:00
} ) ,
controls : [ new ol . control . Zoom ( ) ,
new ol . control . Rotate ( ) ,
2017-01-25 23:33:28 +01:00
new ol . control . Attribution ( { collapsed : true } ) ,
2017-02-03 17:50:37 +01:00
new ol . control . ScaleLine ( { units : DisplayUnits } )
2016-07-02 22:12:31 +02:00
] ,
2016-07-02 19:45:03 +02:00
loadTilesWhileAnimating : true ,
loadTilesWhileInteracting : true
2016-07-02 13:55:38 +02:00
} ) ;
2016-03-31 21:09:12 +02:00
2017-02-03 17:50:37 +01:00
if ( baseCount > 1 ) {
OLMap . addControl ( new ol . control . LayerSwitcher ( ) ) ;
}
2013-05-31 09:04:11 +02:00
// Listeners for newly created Map
2016-07-02 13:55:38 +02:00
OLMap . getView ( ) . on ( 'change:center' , function ( event ) {
var center = ol . proj . toLonLat ( OLMap . getView ( ) . getCenter ( ) , OLMap . getView ( ) . getProjection ( ) ) ;
localStorage [ 'CenterLon' ] = center [ 0 ]
localStorage [ 'CenterLat' ] = center [ 1 ]
2015-01-22 15:17:12 +01:00
if ( FollowSelected ) {
// On manual navigation, disable follow
var selected = Planes [ SelectedPlane ] ;
2018-07-31 00:51:18 +02:00
if ( typeof selected === 'undefined' ||
( Math . abs ( center [ 0 ] - selected . position [ 0 ] ) > 0.0001 &&
Math . abs ( center [ 1 ] - selected . position [ 1 ] ) > 0.0001 ) ) {
2015-01-22 15:17:12 +01:00
FollowSelected = false ;
2015-01-22 22:31:02 +01:00
refreshSelected ( ) ;
2017-01-18 23:14:53 +01:00
refreshHighlighted ( ) ;
2015-01-22 15:17:12 +01:00
}
}
} ) ;
2019-11-03 17:00:53 +01:00
2016-07-02 13:55:38 +02:00
OLMap . getView ( ) . on ( 'change:resolution' , function ( event ) {
2016-09-16 12:03:54 +02:00
ZoomLvl = localStorage [ 'ZoomLvl' ] = OLMap . getView ( ) . getZoom ( ) ;
for ( var plane in Planes ) {
Planes [ plane ] . updateMarker ( false ) ;
} ;
2015-01-22 15:17:12 +01:00
} ) ;
2016-03-31 21:09:12 +02:00
2016-07-02 19:11:05 +02:00
OLMap . on ( [ 'click' , 'dblclick' ] , function ( evt ) {
var hex = evt . map . forEachFeatureAtPixel ( evt . pixel ,
function ( feature , layer ) {
return feature . hex ;
} ,
null ,
function ( layer ) {
return ( layer === iconsLayer ) ;
} ,
null ) ;
if ( hex ) {
selectPlaneByHex ( hex , ( evt . type === 'dblclick' ) ) ;
2016-09-01 00:59:24 +02:00
adjustSelectedInfoBlockPosition ( ) ;
2016-07-02 19:11:05 +02:00
evt . stopPropagation ( ) ;
2016-08-30 22:22:34 +02:00
} else {
deselectAllPlanes ( ) ;
2016-07-02 19:11:05 +02:00
evt . stopPropagation ( ) ;
2016-07-02 18:11:33 +02:00
}
2015-10-27 00:03:34 +01:00
} ) ;
2017-01-18 23:14:53 +01:00
// show the hover box
OLMap . on ( 'pointermove' , function ( evt ) {
var hex = evt . map . forEachFeatureAtPixel ( evt . pixel ,
function ( feature , layer ) {
return feature . hex ;
} ,
null ,
function ( layer ) {
return ( layer === iconsLayer ) ;
} ,
null
) ;
if ( hex ) {
highlightPlaneByHex ( hex ) ;
} else {
removeHighlight ( ) ;
}
} )
2017-01-23 21:02:45 +01:00
// handle the layer settings pane checkboxes
OLMap . once ( 'postrender' , function ( e ) {
toggleLayer ( '#nexrad_checkbox' , 'nexrad' ) ;
toggleLayer ( '#sitepos_checkbox' , 'site_pos' ) ;
toggleLayer ( '#actrail_checkbox' , 'ac_trail' ) ;
toggleLayer ( '#acpositions_checkbox' , 'ac_positions' ) ;
} ) ;
2013-05-26 22:34:38 +02:00
// Add home marker if requested
2015-01-06 21:15:25 +01:00
if ( SitePosition ) {
2016-07-02 13:55:38 +02:00
var markerStyle = new ol . style . Style ( {
image : new ol . style . Circle ( {
radius : 7 ,
snapToPixel : false ,
fill : new ol . style . Fill ( { color : 'black' } ) ,
stroke : new ol . style . Stroke ( {
color : 'white' , width : 2
} )
} )
} ) ;
var feature = new ol . Feature ( new ol . geom . Point ( ol . proj . fromLonLat ( SitePosition ) ) ) ;
feature . setStyle ( markerStyle ) ;
StaticFeatures . push ( feature ) ;
2019-11-03 17:00:53 +01:00
2015-12-21 18:40:39 +01:00
if ( SiteCircles ) {
2016-08-22 23:48:17 +02:00
createSiteCircleFeatures ( ) ;
2015-12-21 18:40:39 +01:00
}
2013-05-26 22:34:38 +02:00
}
2015-12-21 18:42:05 +01:00
// Add terrain-limit rings. To enable this:
//
// create a panorama for your receiver location on heywhatsthat.com
//
// note the "view" value from the URL at the top of the panorama
// i.e. the XXXX in http://www.heywhatsthat.com/?view=XXXX
//
// fetch a json file from the API for the altitudes you want to see:
//
// wget -O /usr/share/dump1090-mutability/html/upintheair.json \
2015-12-23 11:10:05 +01:00
// 'http://www.heywhatsthat.com/api/upintheair.json?id=XXXX&refraction=0.25&alts=3048,9144'
2015-12-21 18:42:05 +01:00
//
// NB: altitudes are in _meters_, you can specify a list of altitudes
// kick off an ajax request that will add the rings when it's done
var request = $ . ajax ( { url : 'upintheair.json' ,
timeout : 5000 ,
cache : true ,
dataType : 'json' } ) ;
request . done ( function ( data ) {
2016-07-02 13:55:38 +02:00
var ringStyle = new ol . style . Style ( {
fill : null ,
stroke : new ol . style . Stroke ( {
color : '#000000' ,
width : 1
} )
} ) ;
2015-12-21 18:42:05 +01:00
for ( var i = 0 ; i < data . rings . length ; ++ i ) {
2016-07-02 13:55:38 +02:00
var geom = new ol . geom . LineString ( ) ;
2015-12-21 18:42:05 +01:00
var points = data . rings [ i ] . points ;
2016-07-02 13:55:38 +02:00
if ( points . length > 0 ) {
for ( var j = 0 ; j < points . length ; ++ j ) {
geom . appendCoordinate ( [ points [ j ] [ 1 ] , points [ j ] [ 0 ] ] ) ;
}
geom . appendCoordinate ( [ points [ 0 ] [ 1 ] , points [ 0 ] [ 0 ] ] ) ;
geom . transform ( 'EPSG:4326' , 'EPSG:3857' ) ;
var feature = new ol . Feature ( geom ) ;
feature . setStyle ( ringStyle ) ;
StaticFeatures . push ( feature ) ;
2015-12-21 18:42:05 +01:00
}
}
} ) ;
request . fail ( function ( jqxhr , status , error ) {
// no rings available, do nothing
} ) ;
2013-05-09 16:59:26 +02:00
}
2016-08-22 23:48:17 +02:00
function createSiteCircleFeatures ( ) {
// Clear existing circles first
SiteCircleFeatures . forEach ( function ( circleFeature ) {
2019-11-03 17:00:53 +01:00
StaticFeatures . remove ( circleFeature ) ;
2016-08-22 23:48:17 +02:00
} ) ;
SiteCircleFeatures . clear ( ) ;
2017-01-23 23:27:03 +01:00
var circleStyle = function ( distance ) {
return new ol . style . Style ( {
2016-08-22 23:48:17 +02:00
fill : null ,
stroke : new ol . style . Stroke ( {
color : '#000000' ,
width : 1
2017-01-23 23:27:03 +01:00
} ) ,
text : new ol . style . Text ( {
font : '10px Helvetica Neue, sans-serif' ,
fill : new ol . style . Fill ( { color : '#000' } ) ,
offsetY : - 8 ,
2017-01-25 01:10:06 +01:00
text : format _distance _long ( distance , DisplayUnits , 0 )
2017-01-23 23:27:03 +01:00
} )
} ) ;
} ;
2016-08-22 23:48:17 +02:00
var conversionFactor = 1000.0 ;
if ( DisplayUnits === "nautical" ) {
conversionFactor = 1852.0 ;
} else if ( DisplayUnits === "imperial" ) {
conversionFactor = 1609.0 ;
}
for ( var i = 0 ; i < SiteCirclesDistances . length ; ++ i ) {
var distance = SiteCirclesDistances [ i ] * conversionFactor ;
var circle = make _geodesic _circle ( SitePosition , distance , 360 ) ;
circle . transform ( 'EPSG:4326' , 'EPSG:3857' ) ;
var feature = new ol . Feature ( circle ) ;
2017-01-23 23:27:03 +01:00
feature . setStyle ( circleStyle ( distance ) ) ;
2016-08-22 23:48:17 +02:00
StaticFeatures . push ( feature ) ;
SiteCircleFeatures . push ( feature ) ;
}
}
2013-05-21 22:28:16 +02:00
// This looks for planes to reap out of the master Planes variable
function reaper ( ) {
2015-01-07 02:19:05 +01:00
//console.log("Reaping started..");
2015-01-06 21:15:25 +01:00
2016-09-07 21:20:42 +02:00
// Look for planes where we have seen no messages for >300 seconds
2015-01-06 21:15:25 +01:00
var newPlanes = [ ] ;
for ( var i = 0 ; i < PlanesOrdered . length ; ++ i ) {
var plane = PlanesOrdered [ i ] ;
2015-01-07 02:19:05 +01:00
if ( plane . seen > 300 ) {
2019-11-03 17:00:53 +01:00
// Reap it.
2015-01-07 02:19:05 +01:00
plane . tr . parentNode . removeChild ( plane . tr ) ;
plane . tr = null ;
2016-10-25 22:09:27 +02:00
delete Planes [ plane . icao ] ;
2015-01-07 02:19:05 +01:00
plane . destroy ( ) ;
2016-09-07 21:20:42 +02:00
} else {
2015-01-06 21:15:25 +01:00
// Keep it.
newPlanes . push ( plane ) ;
2016-09-07 21:20:42 +02:00
}
} ;
2015-01-06 21:15:25 +01:00
PlanesOrdered = newPlanes ;
refreshTableInfo ( ) ;
refreshSelected ( ) ;
2017-01-18 23:14:53 +01:00
refreshHighlighted ( ) ;
2015-01-07 18:18:33 +01:00
}
2015-02-20 11:42:29 +01:00
// Page Title update function
function refreshPageTitle ( ) {
2017-01-26 23:32:45 +01:00
if ( ! PlaneCountInTitle && ! MessageRateInTitle ) {
document . title = PageName ;
2015-02-22 12:51:58 +01:00
return ;
2017-01-26 23:32:45 +01:00
}
2015-02-22 12:51:58 +01:00
var subtitle = "" ;
if ( PlaneCountInTitle ) {
subtitle += TrackedAircraftPositions + '/' + TrackedAircraft ;
}
if ( MessageRateInTitle ) {
if ( subtitle ) subtitle += ' | ' ;
subtitle += MessageRate . toFixed ( 1 ) + '/s' ;
}
document . title = PageName + ' - ' + subtitle ;
2015-02-20 11:42:29 +01:00
}
2013-05-21 22:28:16 +02:00
// Refresh the detail window about the plane
function refreshSelected ( ) {
2015-02-22 12:51:58 +01:00
if ( MessageCountHistory . length > 1 ) {
var message _time _delta = MessageCountHistory [ MessageCountHistory . length - 1 ] . time - MessageCountHistory [ 0 ] . time ;
var message _count _delta = MessageCountHistory [ MessageCountHistory . length - 1 ] . messages - MessageCountHistory [ 0 ] . messages ;
if ( message _time _delta > 0 )
MessageRate = message _count _delta / message _time _delta ;
} else {
MessageRate = null ;
}
2015-02-20 11:42:29 +01:00
refreshPageTitle ( ) ;
2019-11-03 17:00:53 +01:00
2015-02-22 12:51:58 +01:00
var selected = false ;
2013-05-26 14:19:38 +02:00
if ( typeof SelectedPlane !== 'undefined' && SelectedPlane != "ICAO" && SelectedPlane != null ) {
2015-01-06 21:15:25 +01:00
selected = Planes [ SelectedPlane ] ;
}
2019-11-03 17:00:53 +01:00
2016-08-30 22:07:54 +02:00
$ ( '#dump1090_infoblock' ) . css ( 'display' , 'block' ) ;
$ ( '#dump1090_version' ) . text ( Dump1090Version ) ;
$ ( '#dump1090_total_ac' ) . text ( TrackedAircraft ) ;
$ ( '#dump1090_total_ac_positions' ) . text ( TrackedAircraftPositions ) ;
$ ( '#dump1090_total_history' ) . text ( TrackedHistorySize ) ;
if ( MessageRate !== null ) {
$ ( '#dump1090_message_rate' ) . text ( MessageRate . toFixed ( 1 ) ) ;
} else {
$ ( '#dump1090_message_rate' ) . text ( "n/a" ) ;
}
setSelectedInfoBlockVisibility ( ) ;
2015-02-22 12:51:58 +01:00
2016-08-30 22:07:54 +02:00
if ( ! selected ) {
2015-01-06 21:15:25 +01:00
return ;
}
2019-11-03 17:00:53 +01:00
2015-01-06 21:15:25 +01:00
if ( selected . flight !== null && selected . flight !== "" ) {
$ ( '#selected_callsign' ) . text ( selected . flight ) ;
2013-05-28 11:15:18 +02:00
} else {
2015-01-22 18:35:20 +01:00
$ ( '#selected_callsign' ) . text ( 'n/a' ) ;
2015-01-06 21:15:25 +01:00
}
2018-07-31 00:51:18 +02:00
$ ( '#selected_flightaware_link' ) . html ( getFlightAwareModeSLink ( selected . icao , selected . flight , "Visit Flight Page" ) ) ;
2015-02-24 22:51:30 +01:00
if ( selected . registration !== null ) {
$ ( '#selected_registration' ) . text ( selected . registration ) ;
} else {
2018-08-15 23:54:43 +02:00
$ ( '#selected_registration' ) . text ( "n/a" ) ;
2015-02-24 22:51:30 +01:00
}
if ( selected . icaotype !== null ) {
$ ( '#selected_icaotype' ) . text ( selected . icaotype ) ;
} else {
2018-08-15 22:41:47 +02:00
$ ( '#selected_icaotype' ) . text ( "n/a" ) ;
2015-02-24 22:51:30 +01:00
}
2017-01-19 21:55:48 +01:00
// Not using this logic for the redesigned info panel at the time, but leaving it in if/when adding it back
// var emerg = document.getElementById('selected_emergency');
// if (selected.squawk in SpecialSquawks) {
// emerg.className = SpecialSquawks[selected.squawk].cssClass;
// emerg.textContent = NBSP + 'Squawking: ' + SpecialSquawks[selected.squawk].text + NBSP ;
// } else {
// emerg.className = 'hidden';
// }
2015-01-06 21:15:25 +01:00
2018-07-31 00:51:18 +02:00
$ ( "#selected_altitude" ) . text ( format _altitude _long ( selected . altitude , selected . vert _rate , DisplayUnits ) ) ;
2015-01-06 21:15:25 +01:00
2018-08-08 18:37:26 +02:00
$ ( '#selected_onground' ) . text ( format _onground ( selected . altitude ) ) ;
2015-01-06 21:15:25 +01:00
if ( selected . squawk === null || selected . squawk === '0000' ) {
$ ( '#selected_squawk' ) . text ( 'n/a' ) ;
} else {
$ ( '#selected_squawk' ) . text ( selected . squawk ) ;
2013-05-28 11:15:18 +02:00
}
2019-11-03 17:00:53 +01:00
2018-07-31 00:51:18 +02:00
$ ( '#selected_speed' ) . text ( format _speed _long ( selected . gs , DisplayUnits ) ) ;
$ ( '#selected_ias' ) . text ( format _speed _long ( selected . ias , DisplayUnits ) ) ;
$ ( '#selected_tas' ) . text ( format _speed _long ( selected . tas , DisplayUnits ) ) ;
$ ( '#selected_vertical_rate' ) . text ( format _vert _rate _long ( selected . baro _rate , DisplayUnits ) ) ;
$ ( '#selected_vertical_rate_geo' ) . text ( format _vert _rate _long ( selected . geom _rate , DisplayUnits ) ) ;
2015-01-22 16:31:35 +01:00
$ ( '#selected_icao' ) . text ( selected . icao . toUpperCase ( ) ) ;
2015-01-23 20:17:07 +01:00
$ ( '#airframes_post_icao' ) . attr ( 'value' , selected . icao ) ;
2018-07-31 00:51:18 +02:00
$ ( '#selected_track' ) . text ( format _track _long ( selected . track ) ) ;
2015-01-06 21:15:25 +01:00
if ( selected . seen <= 1 ) {
$ ( '#selected_seen' ) . text ( 'now' ) ;
} else {
2015-02-10 22:49:37 +01:00
$ ( '#selected_seen' ) . text ( selected . seen . toFixed ( 1 ) + 's' ) ;
2015-01-06 21:15:25 +01:00
}
2015-09-01 13:19:23 +02:00
$ ( '#selected_country' ) . text ( selected . icaorange . country ) ;
if ( ShowFlags && selected . icaorange . flag _image !== null ) {
$ ( '#selected_flag' ) . removeClass ( 'hidden' ) ;
$ ( '#selected_flag img' ) . attr ( 'src' , FlagPath + selected . icaorange . flag _image ) ;
$ ( '#selected_flag img' ) . attr ( 'title' , selected . icaorange . country ) ;
} else {
$ ( '#selected_flag' ) . addClass ( 'hidden' ) ;
}
2015-08-30 18:16:40 +02:00
2015-01-07 18:18:33 +01:00
if ( selected . position === null ) {
2015-01-06 21:15:25 +01:00
$ ( '#selected_position' ) . text ( 'n/a' ) ;
2015-01-22 15:17:12 +01:00
$ ( '#selected_follow' ) . addClass ( 'hidden' ) ;
2015-01-06 21:15:25 +01:00
} else {
2019-11-03 17:00:53 +01:00
2015-01-06 21:15:25 +01:00
if ( selected . seen _pos > 1 ) {
2017-01-19 21:55:48 +01:00
$ ( '#selected_position' ) . text ( format _latlng ( selected . position ) ) ;
2015-01-06 21:15:25 +01:00
} else {
2017-01-19 21:55:48 +01:00
$ ( '#selected_position' ) . text ( format _latlng ( selected . position ) ) ;
2018-07-31 00:51:18 +02:00
}
2019-11-03 17:00:53 +01:00
2015-01-22 15:17:12 +01:00
$ ( '#selected_follow' ) . removeClass ( 'hidden' ) ;
2015-01-22 22:31:02 +01:00
if ( FollowSelected ) {
$ ( '#selected_follow' ) . css ( 'font-weight' , 'bold' ) ;
2016-07-02 15:44:14 +02:00
OLMap . getView ( ) . setCenter ( ol . proj . fromLonLat ( selected . position ) ) ;
2015-01-22 22:31:02 +01:00
} else {
$ ( '#selected_follow' ) . css ( 'font-weight' , 'normal' ) ;
}
2013-05-21 22:28:16 +02:00
}
2018-07-31 00:51:18 +02:00
if ( selected . getDataSource ( ) === "adsb_icao" ) {
$ ( '#selected_source' ) . text ( "ADS-B" ) ;
} else if ( selected . getDataSource ( ) === "tisb_trackfile" || selected . getDataSource ( ) === "tisb_icao" || selected . getDataSource ( ) === "tisb_other" ) {
$ ( '#selected_source' ) . text ( "TIS-B" ) ;
} else if ( selected . getDataSource ( ) === "mlat" ) {
$ ( '#selected_source' ) . text ( "MLAT" ) ;
} else {
$ ( '#selected_source' ) . text ( "Other" ) ;
}
$ ( '#selected_category' ) . text ( selected . category ? selected . category : "n/a" ) ;
2016-08-22 23:48:17 +02:00
$ ( '#selected_sitedist' ) . text ( format _distance _long ( selected . sitedist , DisplayUnits ) ) ;
2015-01-22 16:31:35 +01:00
$ ( '#selected_rssi' ) . text ( selected . rssi . toFixed ( 1 ) + ' dBFS' ) ;
2016-08-30 23:38:41 +02:00
$ ( '#selected_message_count' ) . text ( selected . messages ) ;
2018-07-31 00:51:18 +02:00
$ ( '#selected_photo_link' ) . html ( getFlightAwarePhotoLink ( selected . registration ) ) ;
2019-11-03 17:00:53 +01:00
2018-07-31 00:51:18 +02:00
$ ( '#selected_altitude_geom' ) . text ( format _altitude _long ( selected . alt _geom , selected . geom _rate , DisplayUnits ) ) ;
2017-06-15 23:36:23 +02:00
$ ( '#selected_mag_heading' ) . text ( format _track _long ( selected . mag _heading ) ) ;
$ ( '#selected_true_heading' ) . text ( format _track _long ( selected . true _heading ) ) ;
$ ( '#selected_ias' ) . text ( format _speed _long ( selected . ias , DisplayUnits ) ) ;
$ ( '#selected_tas' ) . text ( format _speed _long ( selected . tas , DisplayUnits ) ) ;
2017-06-16 00:42:05 +02:00
if ( selected . mach == null ) {
$ ( '#selected_mach' ) . text ( 'n/a' ) ;
} else {
$ ( '#selected_mach' ) . text ( selected . mach . toFixed ( 3 ) ) ;
}
if ( selected . roll == null ) {
$ ( '#selected_roll' ) . text ( 'n/a' ) ;
} else {
$ ( '#selected_roll' ) . text ( selected . roll . toFixed ( 1 ) ) ;
}
if ( selected . track _rate == null ) {
2018-07-31 00:51:18 +02:00
$ ( '#selected_trackrate' ) . text ( 'n/a' ) ;
2017-06-16 00:42:05 +02:00
} else {
2018-07-31 00:51:18 +02:00
$ ( '#selected_trackrate' ) . text ( selected . track _rate . toFixed ( 2 ) ) ;
2017-06-16 00:42:05 +02:00
}
2017-06-15 23:36:23 +02:00
$ ( '#selected_geom_rate' ) . text ( format _vert _rate _long ( selected . geom _rate , DisplayUnits ) ) ;
2018-03-08 22:41:29 +01:00
if ( selected . nav _qnh == null ) {
$ ( '#selected_nav_qnh' ) . text ( "n/a" ) ;
2017-06-15 23:36:23 +02:00
} else {
2018-03-08 22:41:29 +01:00
$ ( '#selected_nav_qnh' ) . text ( selected . nav _qnh . toFixed ( 1 ) + " hPa" ) ;
2017-06-15 23:36:23 +02:00
}
2018-03-08 22:41:29 +01:00
$ ( '#selected_nav_altitude' ) . text ( format _altitude _long ( selected . nav _altitude , 0 , DisplayUnits ) ) ;
$ ( '#selected_nav_heading' ) . text ( format _track _long ( selected . nav _heading ) ) ;
if ( selected . nav _modes == null ) {
$ ( '#selected_nav_modes' ) . text ( "n/a" ) ;
2017-06-16 11:40:22 +02:00
} else {
2018-03-08 22:41:29 +01:00
$ ( '#selected_nav_modes' ) . text ( selected . nav _modes . join ( ) ) ;
2018-07-31 19:17:27 +02:00
}
if ( selected . nic _baro == null ) {
$ ( '#selected_nic_baro' ) . text ( "n/a" ) ;
} else {
2018-08-01 01:25:11 +02:00
if ( selected . nic _baro == 1 ) {
$ ( '#selected_nic_baro' ) . text ( "cross-checked" ) ;
} else {
$ ( '#selected_nic_baro' ) . text ( "not cross-checked" ) ;
}
2018-07-31 19:17:27 +02:00
}
2018-08-02 20:04:44 +02:00
$ ( '#selected_nac_p' ) . text ( format _nac _p ( selected . nac _p ) ) ;
$ ( '#selected_nac_v' ) . text ( format _nac _v ( selected . nac _v ) ) ;
if ( selected . rc == null ) {
$ ( '#selected_rc' ) . text ( "n/a" ) ;
2018-08-02 20:32:05 +02:00
} else if ( selected . rc == 0 ) {
$ ( '#selected_rc' ) . text ( "unknown" ) ;
2018-07-31 19:17:27 +02:00
} else {
2018-08-17 18:31:12 +02:00
$ ( '#selected_rc' ) . text ( format _distance _short ( selected . rc , DisplayUnits ) ) ;
2018-07-31 19:17:27 +02:00
}
2018-08-02 20:04:44 +02:00
2018-08-01 01:25:11 +02:00
if ( selected . sil == null || selected . sil _type == null ) {
2018-07-31 19:17:27 +02:00
$ ( '#selected_sil' ) . text ( "n/a" ) ;
} else {
2018-08-01 01:25:11 +02:00
var sampleRate = "" ;
var silDesc = "" ;
if ( selected . sil _type == "perhour" ) {
sampleRate = " per flight hour" ;
} else if ( selected . sil _type == "persample" ) {
sampleRate = " per sample" ;
}
2019-11-03 17:00:53 +01:00
2018-08-01 01:25:11 +02:00
switch ( selected . sil ) {
case 0 :
silDesc = "> 1× 10<sup>-3</sup>" ;
break ;
case 1 :
silDesc = "≤ 1× 10<sup>-3</sup>" ;
break ;
case 2 :
silDesc = "≤ 1× 10<sup>-5</sup>" ;
break ;
case 3 :
silDesc = "≤ 1× 10<sup>-7</sup>" ;
break ;
default :
silDesc = "n/a" ;
sampleRate = "" ;
break ;
}
$ ( '#selected_sil' ) . html ( silDesc + sampleRate ) ;
2018-07-31 19:17:27 +02:00
}
2017-06-16 00:42:05 +02:00
if ( selected . version == null ) {
$ ( '#selected_version' ) . text ( 'none' ) ;
} else if ( selected . version == 0 ) {
$ ( '#selected_version' ) . text ( 'v0 (DO-260)' ) ;
} else if ( selected . version == 1 ) {
$ ( '#selected_version' ) . text ( 'v1 (DO-260A)' ) ;
} else if ( selected . version == 2 ) {
$ ( '#selected_version' ) . text ( 'v2 (DO-260B)' ) ;
} else {
$ ( '#selected_version' ) . text ( 'v' + selected . version ) ;
}
2018-07-31 00:51:18 +02:00
}
2015-01-06 21:15:25 +01:00
2017-01-18 23:14:53 +01:00
function refreshHighlighted ( ) {
// this is following nearly identical logic, etc, as the refreshSelected function, but doing less junk for the highlighted pane
var highlighted = false ;
if ( typeof HighlightedPlane !== 'undefined' && HighlightedPlane !== null ) {
highlighted = Planes [ HighlightedPlane ] ;
}
// no highlighted plane
if ( ! highlighted ) {
$ ( '#highlighted_infoblock' ) . hide ( ) ;
return ;
}
$ ( '#highlighted_infoblock' ) . show ( ) ;
2018-07-31 00:51:18 +02:00
// Get info box position and size
var infoBox = $ ( '#highlighted_infoblock' ) ;
var infoBoxPosition = infoBox . position ( ) ;
if ( typeof infoBoxOriginalPosition . top === 'undefined' ) {
infoBoxOriginalPosition . top = infoBoxPosition . top ;
infoBoxOriginalPosition . left = infoBoxPosition . left ;
} else {
infoBox . css ( "left" , infoBoxOriginalPosition . left ) ;
infoBox . css ( "top" , infoBoxOriginalPosition . top ) ;
infoBoxPosition = infoBox . position ( ) ;
}
var infoBoxExtent = getExtent ( infoBoxPosition . left , infoBoxPosition . top , infoBox . outerWidth ( ) , infoBox . outerHeight ( ) ) ;
// Get map size
var mapCanvas = $ ( '#map_canvas' ) ;
var mapExtent = getExtent ( 0 , 0 , mapCanvas . width ( ) , mapCanvas . height ( ) ) ;
var marker = highlighted . marker ;
var markerCoordinates = highlighted . marker . getGeometry ( ) . getCoordinates ( ) ;
var markerPosition = OLMap . getPixelFromCoordinate ( markerCoordinates ) ;
// Check for overlap
//FIXME TODO: figure out this/remove this check
if ( isPointInsideExtent ( markerPosition [ 0 ] , markerPosition [ 1 ] , infoBoxExtent ) || true ) {
// Array of possible new positions for info box
var candidatePositions = [ ] ;
candidatePositions . push ( { x : 40 , y : 80 } ) ;
candidatePositions . push ( { x : markerPosition [ 0 ] + 20 , y : markerPosition [ 1 ] + 60 } ) ;
// Find new position
for ( var i = 0 ; i < candidatePositions . length ; i ++ ) {
var candidatePosition = candidatePositions [ i ] ;
var candidateExtent = getExtent ( candidatePosition . x , candidatePosition . y , infoBox . outerWidth ( ) , infoBox . outerHeight ( ) ) ;
if ( ! isPointInsideExtent ( markerPosition [ 0 ] , markerPosition [ 1 ] , candidateExtent ) && isPointInsideExtent ( candidatePosition . x , candidatePosition . y , mapExtent ) ) {
// Found a new position that doesn't overlap marker - move box to that position
infoBox . css ( "left" , candidatePosition . x ) ;
infoBox . css ( "top" , candidatePosition . y ) ;
}
}
}
2017-01-18 23:14:53 +01:00
if ( highlighted . flight !== null && highlighted . flight !== "" ) {
$ ( '#highlighted_callsign' ) . text ( highlighted . flight ) ;
} else {
$ ( '#highlighted_callsign' ) . text ( 'n/a' ) ;
}
if ( highlighted . icaotype !== null ) {
$ ( '#higlighted_icaotype' ) . text ( highlighted . icaotype ) ;
} else {
2018-08-15 18:50:14 +02:00
$ ( '#higlighted_icaotype' ) . text ( "n/a" ) ;
2017-01-18 23:14:53 +01:00
}
2018-08-15 18:21:35 +02:00
if ( highlighted . getDataSource ( ) === "adsb_icao" ) {
$ ( '#highlighted_source' ) . text ( "ADS-B" ) ;
} else if ( highlighted . getDataSource ( ) === "tisb_trackfile" || highlighted . getDataSource ( ) === "tisb_icao" || highlighted . getDataSource ( ) === "tisb_other" ) {
$ ( '#highlighted_source' ) . text ( "TIS-B" ) ;
} else if ( highlighted . getDataSource ( ) === "mlat" ) {
$ ( '#highlighted_source' ) . text ( "MLAT" ) ;
} else {
$ ( '#highlighted_source' ) . text ( "Other" ) ;
}
if ( highlighted . registration !== null ) {
$ ( '#highlighted_registration' ) . text ( highlighted . registration ) ;
} else {
2018-08-15 23:54:43 +02:00
$ ( '#highlighted_registration' ) . text ( "n/a" ) ;
2018-08-15 18:21:35 +02:00
}
2017-01-18 23:14:53 +01:00
$ ( '#highlighted_speed' ) . text ( format _speed _long ( highlighted . speed , DisplayUnits ) ) ;
$ ( "#highlighted_altitude" ) . text ( format _altitude _long ( highlighted . altitude , highlighted . vert _rate , DisplayUnits ) ) ;
$ ( '#highlighted_icao' ) . text ( highlighted . icao . toUpperCase ( ) ) ;
}
2017-01-19 23:21:55 +01:00
function refreshClock ( ) {
$ ( '#clock_div' ) . text ( new Date ( ) . toLocaleString ( ) ) ;
var c = setTimeout ( refreshClock , 500 ) ;
}
2017-01-18 23:14:53 +01:00
function removeHighlight ( ) {
HighlightedPlane = null ;
refreshHighlighted ( ) ;
}
2015-01-07 18:18:33 +01:00
// Refreshes the larger table of all the planes
2015-01-06 21:15:25 +01:00
function refreshTableInfo ( ) {
2017-01-20 18:52:38 +01:00
var show _squawk _warning = false ;
TrackedAircraft = 0
TrackedAircraftPositions = 0
TrackedHistorySize = 0
$ ( ".altitudeUnit" ) . text ( get _unit _label ( "altitude" , DisplayUnits ) ) ;
$ ( ".speedUnit" ) . text ( get _unit _label ( "speed" , DisplayUnits ) ) ;
$ ( ".distanceUnit" ) . text ( get _unit _label ( "distance" , DisplayUnits ) ) ;
$ ( ".verticalRateUnit" ) . text ( get _unit _label ( "verticalRate" , DisplayUnits ) ) ;
for ( var i = 0 ; i < PlanesOrdered . length ; ++ i ) {
var tableplane = PlanesOrdered [ i ] ;
TrackedHistorySize += tableplane . history _size ;
if ( tableplane . seen >= 58 || tableplane . isFiltered ( ) ) {
tableplane . tr . className = "plane_table_row hidden" ;
} else {
TrackedAircraft ++ ;
var classes = "plane_table_row" ;
if ( tableplane . position !== null && tableplane . seen _pos < 60 ) {
++ TrackedAircraftPositions ;
2013-05-18 23:54:59 +02:00
}
2015-01-06 21:15:25 +01:00
2017-01-25 00:30:42 +01:00
if ( tableplane . getDataSource ( ) === "adsb_icao" ) {
2017-01-20 18:52:38 +01:00
classes += " vPosition" ;
2017-04-06 21:23:30 +02:00
} else if ( tableplane . getDataSource ( ) === "tisb_trackfile" || tableplane . getDataSource ( ) === "tisb_icao" || tableplane . getDataSource ( ) === "tisb_other" ) {
2017-01-20 18:52:38 +01:00
classes += " tisb" ;
} else if ( tableplane . getDataSource ( ) === "mlat" ) {
classes += " mlat" ;
} else {
classes += " other" ;
}
if ( tableplane . icao == SelectedPlane )
classes += " selected" ;
2019-11-03 17:00:53 +01:00
2017-01-20 18:52:38 +01:00
if ( tableplane . squawk in SpecialSquawks ) {
classes = classes + " " + SpecialSquawks [ tableplane . squawk ] . cssClass ;
show _squawk _warning = true ;
2019-11-03 17:00:53 +01:00
}
2017-01-20 18:52:38 +01:00
// ICAO doesn't change
if ( tableplane . flight ) {
tableplane . tr . cells [ 2 ] . innerHTML = getFlightAwareModeSLink ( tableplane . icao , tableplane . flight , tableplane . flight ) ;
2015-01-06 00:20:03 +01:00
} else {
2017-01-20 18:52:38 +01:00
tableplane . tr . cells [ 2 ] . innerHTML = "" ;
2015-01-06 00:20:03 +01:00
}
2017-01-20 18:52:38 +01:00
tableplane . tr . cells [ 3 ] . textContent = ( tableplane . registration !== null ? tableplane . registration : "" ) ;
tableplane . tr . cells [ 4 ] . textContent = ( tableplane . icaotype !== null ? tableplane . icaotype : "" ) ;
tableplane . tr . cells [ 5 ] . textContent = ( tableplane . squawk !== null ? tableplane . squawk : "" ) ;
tableplane . tr . cells [ 6 ] . innerHTML = format _altitude _brief ( tableplane . altitude , tableplane . vert _rate , DisplayUnits ) ;
2017-06-15 23:41:32 +02:00
tableplane . tr . cells [ 7 ] . textContent = format _speed _brief ( tableplane . gs , DisplayUnits ) ;
2017-01-20 18:52:38 +01:00
tableplane . tr . cells [ 8 ] . textContent = format _vert _rate _brief ( tableplane . vert _rate , DisplayUnits ) ;
tableplane . tr . cells [ 9 ] . textContent = format _distance _brief ( tableplane . sitedist , DisplayUnits ) ;
tableplane . tr . cells [ 10 ] . textContent = format _track _brief ( tableplane . track ) ;
tableplane . tr . cells [ 11 ] . textContent = tableplane . messages ;
tableplane . tr . cells [ 12 ] . textContent = tableplane . seen . toFixed ( 0 ) ;
tableplane . tr . cells [ 13 ] . textContent = ( tableplane . rssi !== null ? tableplane . rssi : "" ) ;
tableplane . tr . cells [ 14 ] . textContent = ( tableplane . position !== null ? tableplane . position [ 1 ] . toFixed ( 4 ) : "" ) ;
tableplane . tr . cells [ 15 ] . textContent = ( tableplane . position !== null ? tableplane . position [ 0 ] . toFixed ( 4 ) : "" ) ;
tableplane . tr . cells [ 16 ] . textContent = format _data _source ( tableplane . getDataSource ( ) ) ;
tableplane . tr . cells [ 17 ] . innerHTML = getAirframesModeSLink ( tableplane . icao ) ;
tableplane . tr . cells [ 18 ] . innerHTML = getFlightAwareModeSLink ( tableplane . icao , tableplane . flight ) ;
tableplane . tr . cells [ 19 ] . innerHTML = getFlightAwarePhotoLink ( tableplane . registration ) ;
tableplane . tr . className = classes ;
}
}
if ( show _squawk _warning ) {
$ ( "#SpecialSquawkWarning" ) . css ( 'display' , 'block' ) ;
} else {
$ ( "#SpecialSquawkWarning" ) . css ( 'display' , 'none' ) ;
}
2015-01-06 21:15:25 +01:00
2017-01-20 18:52:38 +01:00
resortTable ( ) ;
2013-05-18 23:54:59 +02:00
}
2015-01-06 21:15:25 +01:00
//
// ---- table sorting ----
//
2015-01-07 23:16:49 +01:00
function compareAlpha ( xa , ya ) {
2015-01-06 21:15:25 +01:00
if ( xa === ya )
2015-01-07 23:16:49 +01:00
return 0 ;
2015-01-06 21:15:25 +01:00
if ( xa < ya )
return - 1 ;
return 1 ;
}
2015-01-06 00:20:03 +01:00
2015-01-07 23:16:49 +01:00
function compareNumeric ( xf , yf ) {
2015-01-06 21:15:25 +01:00
if ( Math . abs ( xf - yf ) < 1e-9 )
2015-01-07 23:16:49 +01:00
return 0 ;
2015-01-06 21:15:25 +01:00
return xf - yf ;
2013-05-18 23:54:59 +02:00
}
2015-01-17 13:27:13 +01:00
function sortByICAO ( ) { sortBy ( 'icao' , compareAlpha , function ( x ) { return x . icao ; } ) ; }
function sortByFlight ( ) { sortBy ( 'flight' , compareAlpha , function ( x ) { return x . flight ; } ) ; }
2016-08-20 00:37:43 +02:00
function sortByRegistration ( ) { sortBy ( 'registration' , compareAlpha , function ( x ) { return x . registration ; } ) ; }
function sortByAircraftType ( ) { sortBy ( 'icaotype' , compareAlpha , function ( x ) { return x . icaotype ; } ) ; }
2015-01-17 13:27:13 +01:00
function sortBySquawk ( ) { sortBy ( 'squawk' , compareAlpha , function ( x ) { return x . squawk ; } ) ; }
function sortByAltitude ( ) { sortBy ( 'altitude' , compareNumeric , function ( x ) { return ( x . altitude == "ground" ? - 1e9 : x . altitude ) ; } ) ; }
2017-06-15 23:41:32 +02:00
function sortBySpeed ( ) { sortBy ( 'speed' , compareNumeric , function ( x ) { return x . gs ; } ) ; }
2016-08-20 00:37:43 +02:00
function sortByVerticalRate ( ) { sortBy ( 'vert_rate' , compareNumeric , function ( x ) { return x . vert _rate ; } ) ; }
2015-01-17 13:27:13 +01:00
function sortByDistance ( ) { sortBy ( 'sitedist' , compareNumeric , function ( x ) { return x . sitedist ; } ) ; }
function sortByTrack ( ) { sortBy ( 'track' , compareNumeric , function ( x ) { return x . track ; } ) ; }
function sortByMsgs ( ) { sortBy ( 'msgs' , compareNumeric , function ( x ) { return x . messages ; } ) ; }
function sortBySeen ( ) { sortBy ( 'seen' , compareNumeric , function ( x ) { return x . seen ; } ) ; }
2015-09-01 13:19:23 +02:00
function sortByCountry ( ) { sortBy ( 'country' , compareAlpha , function ( x ) { return x . icaorange . country ; } ) ; }
2016-08-20 00:37:43 +02:00
function sortByRssi ( ) { sortBy ( 'rssi' , compareNumeric , function ( x ) { return x . rssi } ) ; }
function sortByLatitude ( ) { sortBy ( 'lat' , compareNumeric , function ( x ) { return ( x . position !== null ? x . position [ 1 ] : null ) } ) ; }
function sortByLongitude ( ) { sortBy ( 'lon' , compareNumeric , function ( x ) { return ( x . position !== null ? x . position [ 0 ] : null ) } ) ; }
function sortByDataSource ( ) { sortBy ( 'data_source' , compareAlpha , function ( x ) { return x . getDataSource ( ) } ) ; }
2015-01-06 21:15:25 +01:00
2015-01-17 13:27:13 +01:00
var sortId = '' ;
var sortCompare = null ;
var sortExtract = null ;
var sortAscending = true ;
2015-01-06 21:15:25 +01:00
2015-01-17 13:27:13 +01:00
function sortFunction ( x , y ) {
var xv = x . _sort _value ;
var yv = y . _sort _value ;
2013-05-18 23:54:59 +02:00
2015-01-17 13:27:13 +01:00
// always sort missing values at the end, regardless of
// ascending/descending sort
2015-01-20 00:28:04 +01:00
if ( xv == null && yv == null ) return x . _sort _pos - y . _sort _pos ;
2015-01-17 13:27:13 +01:00
if ( xv == null ) return 1 ;
if ( yv == null ) return - 1 ;
2015-01-06 21:15:25 +01:00
2015-01-17 13:27:13 +01:00
var c = sortAscending ? sortCompare ( xv , yv ) : sortCompare ( yv , xv ) ;
if ( c !== 0 ) return c ;
return x . _sort _pos - y . _sort _pos ;
}
2015-01-06 21:15:25 +01:00
function resortTable ( ) {
2015-01-07 23:16:49 +01:00
// number the existing rows so we can do a stable sort
// regardless of whether sort() is stable or not.
2015-01-17 13:27:13 +01:00
// Also extract the sort comparison value.
2015-01-06 21:15:25 +01:00
for ( var i = 0 ; i < PlanesOrdered . length ; ++ i ) {
2015-01-07 23:16:49 +01:00
PlanesOrdered [ i ] . _sort _pos = i ;
2015-01-17 13:27:13 +01:00
PlanesOrdered [ i ] . _sort _value = sortExtract ( PlanesOrdered [ i ] ) ;
2015-01-06 21:15:25 +01:00
}
2015-01-17 13:27:13 +01:00
PlanesOrdered . sort ( sortFunction ) ;
2019-11-03 17:00:53 +01:00
2015-01-06 21:15:25 +01:00
var tbody = document . getElementById ( 'tableinfo' ) . tBodies [ 0 ] ;
for ( var i = 0 ; i < PlanesOrdered . length ; ++ i ) {
tbody . appendChild ( PlanesOrdered [ i ] . tr ) ;
}
}
2013-05-18 23:54:59 +02:00
2015-01-17 13:27:13 +01:00
function sortBy ( id , sc , se ) {
2017-01-23 21:02:45 +01:00
if ( id !== 'data_source' ) {
$ ( '#grouptype_checkbox' ) . removeClass ( 'settingsCheckboxChecked' ) ;
} else {
$ ( '#grouptype_checkbox' ) . addClass ( 'settingsCheckboxChecked' ) ;
}
2015-01-06 21:15:25 +01:00
if ( id === sortId ) {
sortAscending = ! sortAscending ;
2015-01-07 23:16:49 +01:00
PlanesOrdered . reverse ( ) ; // this correctly flips the order of rows that compare equal
2015-01-06 21:15:25 +01:00
} else {
sortAscending = true ;
}
2013-05-12 14:15:18 +02:00
2015-01-06 21:15:25 +01:00
sortId = id ;
2015-01-17 13:27:13 +01:00
sortCompare = sc ;
sortExtract = se ;
2015-01-06 21:15:25 +01:00
resortTable ( ) ;
2013-05-11 12:15:09 +02:00
}
2015-01-22 22:28:35 +01:00
function selectPlaneByHex ( hex , autofollow ) {
2015-01-06 21:15:25 +01:00
//console.log("select: " + hex);
2013-05-24 04:15:37 +02:00
// If SelectedPlane has something in it, clear out the selected
2016-08-19 21:43:20 +02:00
if ( SelectedAllPlanes ) {
deselectAllPlanes ( ) ;
}
2013-05-22 19:09:12 +02:00
if ( SelectedPlane != null ) {
2015-01-07 18:32:20 +01:00
Planes [ SelectedPlane ] . selected = false ;
2015-01-07 02:19:05 +01:00
Planes [ SelectedPlane ] . clearLines ( ) ;
Planes [ SelectedPlane ] . updateMarker ( ) ;
$ ( Planes [ SelectedPlane ] . tr ) . removeClass ( "selected" ) ;
2018-07-31 00:51:18 +02:00
// scroll the infoblock back to the top for the next plane to be selected
$ ( '.infoblock-container' ) . scrollTop ( 0 ) ;
2013-05-22 19:09:12 +02:00
}
2013-05-22 05:26:40 +02:00
2016-07-02 19:10:37 +02:00
// If we are clicking the same plane, we are deselecting it.
2016-08-19 21:43:20 +02:00
// (unless it was a doubleclick..)
2016-07-02 19:10:37 +02:00
if ( SelectedPlane === hex && ! autofollow ) {
2016-08-19 21:43:20 +02:00
hex = null ;
}
2015-01-07 02:19:05 +01:00
2016-08-19 21:43:20 +02:00
if ( hex !== null ) {
2013-05-24 04:15:37 +02:00
// Assign the new selected
SelectedPlane = hex ;
2015-01-07 18:32:20 +01:00
Planes [ SelectedPlane ] . selected = true ;
2015-01-07 02:19:05 +01:00
Planes [ SelectedPlane ] . updateLines ( ) ;
Planes [ SelectedPlane ] . updateMarker ( ) ;
2016-08-19 21:43:20 +02:00
$ ( Planes [ SelectedPlane ] . tr ) . addClass ( "selected" ) ;
2019-11-03 17:00:53 +01:00
} else {
2013-05-25 22:57:10 +02:00
SelectedPlane = null ;
2013-05-24 04:15:37 +02:00
}
2015-01-06 21:15:25 +01:00
2016-08-19 21:43:20 +02:00
if ( SelectedPlane !== null && autofollow ) {
FollowSelected = true ;
if ( OLMap . getView ( ) . getZoom ( ) < 8 )
OLMap . getView ( ) . setZoom ( 8 ) ;
} else {
FollowSelected = false ;
2019-11-03 17:00:53 +01:00
}
2015-01-23 00:12:41 +01:00
2016-08-19 21:43:20 +02:00
refreshSelected ( ) ;
2017-01-18 23:14:53 +01:00
refreshHighlighted ( ) ;
}
function highlightPlaneByHex ( hex ) {
if ( hex != null ) {
HighlightedPlane = hex ;
}
2016-08-19 21:43:20 +02:00
}
// loop through the planes and mark them as selected to show the paths for all planes
function selectAllPlanes ( ) {
2017-01-18 23:14:53 +01:00
HighlightedPlane = null ;
2016-08-19 21:43:20 +02:00
// if all planes are already selected, deselect them all
if ( SelectedAllPlanes ) {
deselectAllPlanes ( ) ;
} else {
// If SelectedPlane has something in it, clear out the selected
if ( SelectedPlane != null ) {
Planes [ SelectedPlane ] . selected = false ;
Planes [ SelectedPlane ] . clearLines ( ) ;
Planes [ SelectedPlane ] . updateMarker ( ) ;
$ ( Planes [ SelectedPlane ] . tr ) . removeClass ( "selected" ) ;
}
SelectedPlane = null ;
2016-09-15 13:38:11 +02:00
SelectedAllPlanes = true ;
2016-08-19 21:43:20 +02:00
for ( var key in Planes ) {
2016-08-24 22:28:13 +02:00
if ( Planes [ key ] . visible && ! Planes [ key ] . isFiltered ( ) ) {
2016-08-19 21:43:20 +02:00
Planes [ key ] . selected = true ;
Planes [ key ] . updateLines ( ) ;
Planes [ key ] . updateMarker ( ) ;
}
}
}
2017-01-23 21:02:45 +01:00
$ ( '#selectall_checkbox' ) . addClass ( 'settingsCheckboxChecked' ) ;
2016-08-19 21:43:20 +02:00
refreshSelected ( ) ;
2017-01-18 23:14:53 +01:00
refreshHighlighted ( ) ;
2016-08-19 21:43:20 +02:00
}
// on refreshes, try to find new planes and mark them as selected
function selectNewPlanes ( ) {
if ( SelectedAllPlanes ) {
for ( var key in Planes ) {
2016-08-24 22:28:13 +02:00
if ( ! Planes [ key ] . visible || Planes [ key ] . isFiltered ( ) ) {
2016-08-19 21:43:20 +02:00
Planes [ key ] . selected = false ;
2016-08-19 22:52:48 +02:00
Planes [ key ] . clearLines ( ) ;
2016-08-19 21:43:20 +02:00
Planes [ key ] . updateMarker ( ) ;
} else {
if ( Planes [ key ] . selected !== true ) {
Planes [ key ] . selected = true ;
Planes [ key ] . updateLines ( ) ;
Planes [ key ] . updateMarker ( ) ;
}
}
}
}
}
// deselect all the planes
function deselectAllPlanes ( ) {
for ( var key in Planes ) {
Planes [ key ] . selected = false ;
Planes [ key ] . clearLines ( ) ;
Planes [ key ] . updateMarker ( ) ;
$ ( Planes [ key ] . tr ) . removeClass ( "selected" ) ;
}
2017-01-23 21:02:45 +01:00
$ ( '#selectall_checkbox' ) . removeClass ( 'settingsCheckboxChecked' ) ;
2016-08-19 21:43:20 +02:00
SelectedPlane = null ;
SelectedAllPlanes = false ;
refreshSelected ( ) ;
2017-01-18 23:14:53 +01:00
refreshHighlighted ( ) ;
2015-01-22 15:17:12 +01:00
}
function toggleFollowSelected ( ) {
FollowSelected = ! FollowSelected ;
2016-07-02 15:44:14 +02:00
if ( FollowSelected && OLMap . getView ( ) . getZoom ( ) < 8 )
OLMap . getView ( ) . setZoom ( 8 ) ;
2015-01-23 00:12:41 +01:00
refreshSelected ( ) ;
2013-05-09 16:59:26 +02:00
}
2013-05-30 19:32:36 +02:00
function resetMap ( ) {
2015-01-08 00:54:54 +01:00
// Reset localStorage values and map settings
localStorage [ 'CenterLat' ] = CenterLat = DefaultCenterLat ;
localStorage [ 'CenterLon' ] = CenterLon = DefaultCenterLon ;
localStorage [ 'ZoomLvl' ] = ZoomLvl = DefaultZoomLvl ;
// Set and refresh
2016-07-02 15:44:14 +02:00
OLMap . getView ( ) . setZoom ( ZoomLvl ) ;
OLMap . getView ( ) . setCenter ( ol . proj . fromLonLat ( [ CenterLon , CenterLat ] ) ) ;
2019-11-03 17:00:53 +01:00
2015-01-22 22:35:59 +01:00
selectPlaneByHex ( null , false ) ;
2013-05-30 19:32:36 +02:00
}
2016-08-18 22:48:57 +02:00
function updateMapSize ( ) {
OLMap . updateSize ( ) ;
}
function toggleSidebarVisibility ( e ) {
e . preventDefault ( ) ;
$ ( "#sidebar_container" ) . toggle ( ) ;
2016-09-16 13:40:06 +02:00
$ ( "#expand_sidebar_control" ) . toggle ( ) ;
2016-08-18 22:48:57 +02:00
$ ( "#toggle_sidebar_button" ) . toggleClass ( "show_sidebar" ) ;
$ ( "#toggle_sidebar_button" ) . toggleClass ( "hide_sidebar" ) ;
updateMapSize ( ) ;
}
2016-08-19 17:58:48 +02:00
function expandSidebar ( e ) {
e . preventDefault ( ) ;
$ ( "#map_container" ) . hide ( )
2016-09-16 13:40:06 +02:00
$ ( "#toggle_sidebar_control" ) . hide ( ) ;
2016-08-19 17:58:48 +02:00
$ ( "#splitter" ) . hide ( ) ;
2016-08-20 00:57:20 +02:00
$ ( "#sudo_buttons" ) . hide ( ) ;
2016-08-19 17:58:48 +02:00
$ ( "#show_map_button" ) . show ( ) ;
$ ( "#sidebar_container" ) . width ( "100%" ) ;
2016-08-20 00:37:43 +02:00
setColumnVisibility ( ) ;
2016-08-30 22:07:54 +02:00
setSelectedInfoBlockVisibility ( ) ;
2016-08-19 17:58:48 +02:00
updateMapSize ( ) ;
}
function showMap ( ) {
$ ( "#map_container" ) . show ( )
2016-09-16 13:40:06 +02:00
$ ( "#toggle_sidebar_control" ) . show ( ) ;
2016-08-19 17:58:48 +02:00
$ ( "#splitter" ) . show ( ) ;
2016-08-20 00:57:20 +02:00
$ ( "#sudo_buttons" ) . show ( ) ;
2016-08-19 17:58:48 +02:00
$ ( "#show_map_button" ) . hide ( ) ;
2016-09-13 00:20:42 +02:00
$ ( "#sidebar_container" ) . width ( "470px" ) ;
2016-08-20 00:37:43 +02:00
setColumnVisibility ( ) ;
2016-08-30 22:07:54 +02:00
setSelectedInfoBlockVisibility ( ) ;
2019-11-03 17:00:53 +01:00
updateMapSize ( ) ;
2016-08-19 17:58:48 +02:00
}
function showColumn ( table , columnId , visible ) {
var index = $ ( columnId ) . index ( ) ;
if ( index >= 0 ) {
var cells = $ ( table ) . find ( "td:nth-child(" + ( index + 1 ) . toString ( ) + ")" ) ;
if ( visible ) {
cells . show ( ) ;
} else {
cells . hide ( ) ;
}
}
}
2016-08-20 00:37:43 +02:00
function setColumnVisibility ( ) {
var mapIsVisible = $ ( "#map_container" ) . is ( ":visible" ) ;
var infoTable = $ ( "#tableinfo" ) ;
showColumn ( infoTable , "#registration" , ! mapIsVisible ) ;
2019-11-03 17:00:53 +01:00
showColumn ( infoTable , "#aircraft_type" , ! mapIsVisible ) ;
2016-08-20 00:37:43 +02:00
showColumn ( infoTable , "#vert_rate" , ! mapIsVisible ) ;
showColumn ( infoTable , "#rssi" , ! mapIsVisible ) ;
showColumn ( infoTable , "#lat" , ! mapIsVisible ) ;
showColumn ( infoTable , "#lon" , ! mapIsVisible ) ;
showColumn ( infoTable , "#data_source" , ! mapIsVisible ) ;
2016-08-23 01:15:06 +02:00
showColumn ( infoTable , "#airframes_mode_s_link" , ! mapIsVisible ) ;
showColumn ( infoTable , "#flightaware_mode_s_link" , ! mapIsVisible ) ;
2016-08-23 17:41:58 +02:00
showColumn ( infoTable , "#flightaware_photo_link" , ! mapIsVisible ) ;
2016-08-20 00:37:43 +02:00
}
2016-08-22 23:48:17 +02:00
2016-08-30 22:07:54 +02:00
function setSelectedInfoBlockVisibility ( ) {
var mapIsVisible = $ ( "#map_container" ) . is ( ":visible" ) ;
var planeSelected = ( typeof SelectedPlane !== 'undefined' && SelectedPlane != null && SelectedPlane != "ICAO" ) ;
if ( planeSelected && mapIsVisible ) {
$ ( '#selected_infoblock' ) . show ( ) ;
2018-07-31 00:51:18 +02:00
$ ( '#sidebar_canvas' ) . css ( 'margin-bottom' , $ ( '#selected_infoblock' ) . height ( ) + 'px' ) ;
2016-08-30 22:07:54 +02:00
}
else {
$ ( '#selected_infoblock' ) . hide ( ) ;
2018-07-31 00:51:18 +02:00
$ ( '#sidebar_canvas' ) . css ( 'margin-bottom' , 0 ) ;
2018-07-31 23:12:03 +02:00
}
2016-08-30 22:07:54 +02:00
}
2016-09-01 00:59:24 +02:00
// Reposition selected plane info box if it overlaps plane marker
function adjustSelectedInfoBlockPosition ( ) {
if ( typeof Planes === 'undefined' || typeof SelectedPlane === 'undefined' || Planes === null ) {
return ;
}
var selectedPlane = Planes [ SelectedPlane ] ;
if ( selectedPlane === undefined || selectedPlane === null || selectedPlane . marker === undefined || selectedPlane . marker === null ) {
return ;
}
try {
// Get marker position
var marker = selectedPlane . marker ;
var markerCoordinates = selectedPlane . marker . getGeometry ( ) . getCoordinates ( ) ;
2018-07-31 00:51:18 +02:00
var markerPosition = OLMap . getPixelFromCoordinate ( markerCoordinates ) ;
2019-11-03 17:00:53 +01:00
2016-09-01 00:59:24 +02:00
// Get map size
var mapCanvas = $ ( '#map_canvas' ) ;
var mapExtent = getExtent ( 0 , 0 , mapCanvas . width ( ) , mapCanvas . height ( ) ) ;
// Check for overlap
if ( isPointInsideExtent ( markerPosition [ 0 ] , markerPosition [ 1 ] , infoBoxExtent ) ) {
// Array of possible new positions for info box
var candidatePositions = [ ] ;
2017-02-06 19:23:21 +01:00
candidatePositions . push ( { x : 40 , y : 60 } ) ;
candidatePositions . push ( { x : 40 , y : markerPosition [ 1 ] + 80 } ) ;
2016-09-01 00:59:24 +02:00
// Find new position
for ( var i = 0 ; i < candidatePositions . length ; i ++ ) {
var candidatePosition = candidatePositions [ i ] ;
2016-09-01 23:15:03 +02:00
var candidateExtent = getExtent ( candidatePosition . x , candidatePosition . y , infoBox . outerWidth ( ) , infoBox . outerHeight ( ) ) ;
2016-09-01 00:59:24 +02:00
if ( ! isPointInsideExtent ( markerPosition [ 0 ] , markerPosition [ 1 ] , candidateExtent ) && isPointInsideExtent ( candidatePosition . x , candidatePosition . y , mapExtent ) ) {
// Found a new position that doesn't overlap marker - move box to that position
infoBox . css ( "left" , candidatePosition . x ) ;
infoBox . css ( "top" , candidatePosition . y ) ;
return ;
}
}
}
2019-11-03 17:00:53 +01:00
}
2016-09-01 00:59:24 +02:00
catch ( e ) { }
}
function getExtent ( x , y , width , height ) {
return {
xMin : x ,
yMin : y ,
xMax : x + width - 1 ,
yMax : y + height - 1 ,
} ;
}
function isPointInsideExtent ( x , y , extent ) {
return x >= extent . xMin && x <= extent . xMax && y >= extent . yMin && y <= extent . yMax ;
}
2016-08-22 23:48:17 +02:00
function initializeUnitsSelector ( ) {
// Get display unit preferences from local storage
if ( ! localStorage . getItem ( 'displayUnits' ) ) {
localStorage [ 'displayUnits' ] = "nautical" ;
}
var displayUnits = localStorage [ 'displayUnits' ] ;
DisplayUnits = displayUnits ;
2017-01-30 18:58:29 +01:00
setAltitudeLegend ( displayUnits ) ;
2016-08-22 23:48:17 +02:00
// Initialize drop-down
var unitsSelector = $ ( "#units_selector" ) ;
unitsSelector . val ( displayUnits ) ;
unitsSelector . on ( "change" , onDisplayUnitsChanged ) ;
}
function onDisplayUnitsChanged ( e ) {
2017-04-26 01:28:57 +02:00
var displayUnits = e . target . value ;
2016-08-22 23:48:17 +02:00
// Save display units to local storage
localStorage [ 'displayUnits' ] = displayUnits ;
DisplayUnits = displayUnits ;
2017-01-30 18:58:29 +01:00
setAltitudeLegend ( displayUnits ) ;
2016-08-24 22:28:13 +02:00
// Update filters
updatePlaneFilter ( ) ;
2016-08-22 23:48:17 +02:00
// Refresh data
refreshTableInfo ( ) ;
refreshSelected ( ) ;
2017-01-18 23:14:53 +01:00
refreshHighlighted ( ) ;
2016-08-22 23:48:17 +02:00
// Redraw range rings
2016-09-12 23:06:25 +02:00
if ( SitePosition !== null && SitePosition !== undefined && SiteCircles ) {
2016-08-22 23:48:17 +02:00
createSiteCircleFeatures ( ) ;
}
// Reset map scale line units
OLMap . getControls ( ) . forEach ( function ( control ) {
if ( control instanceof ol . control . ScaleLine ) {
control . setUnits ( displayUnits ) ;
}
} ) ;
}
2016-08-23 01:15:06 +02:00
2017-01-30 18:58:29 +01:00
function setAltitudeLegend ( units ) {
if ( units === 'metric' ) {
$ ( '#altitude_chart_button' ) . addClass ( 'altitudeMeters' ) ;
} else {
$ ( '#altitude_chart_button' ) . removeClass ( 'altitudeMeters' ) ;
}
}
2016-08-24 22:28:13 +02:00
function onFilterByAltitude ( e ) {
e . preventDefault ( ) ;
updatePlaneFilter ( ) ;
refreshTableInfo ( ) ;
var selectedPlane = Planes [ SelectedPlane ] ;
if ( selectedPlane !== undefined && selectedPlane !== null && selectedPlane . isFiltered ( ) ) {
SelectedPlane = null ;
selectedPlane . selected = false ;
selectedPlane . clearLines ( ) ;
2019-11-03 17:00:53 +01:00
selectedPlane . updateMarker ( ) ;
2016-08-24 22:28:13 +02:00
refreshSelected ( ) ;
2017-01-18 23:14:53 +01:00
refreshHighlighted ( ) ;
2016-08-24 22:28:13 +02:00
}
}
2017-01-26 20:38:47 +01:00
function filterGroundVehicles ( switchFilter ) {
if ( typeof localStorage [ 'groundVehicleFilter' ] === 'undefined' ) {
localStorage [ 'groundVehicleFilter' ] = 'not_filtered' ;
}
var groundFilter = localStorage [ 'groundVehicleFilter' ] ;
if ( switchFilter === true ) {
groundFilter = ( groundFilter === 'not_filtered' ) ? 'filtered' : 'not_filtered' ;
}
if ( groundFilter === 'not_filtered' ) {
$ ( '#groundvehicle_filter' ) . addClass ( 'settingsCheckboxChecked' ) ;
} else {
$ ( '#groundvehicle_filter' ) . removeClass ( 'settingsCheckboxChecked' ) ;
}
localStorage [ 'groundVehicleFilter' ] = groundFilter ;
PlaneFilter . groundVehicles = groundFilter ;
}
function filterBlockedMLAT ( switchFilter ) {
if ( typeof localStorage [ 'blockedMLATFilter' ] === 'undefined' ) {
localStorage [ 'blockedMLATFilter' ] = 'not_filtered' ;
}
var blockedMLATFilter = localStorage [ 'blockedMLATFilter' ] ;
if ( switchFilter === true ) {
blockedMLATFilter = ( blockedMLATFilter === 'not_filtered' ) ? 'filtered' : 'not_filtered' ;
}
if ( blockedMLATFilter === 'not_filtered' ) {
$ ( '#blockedmlat_filter' ) . addClass ( 'settingsCheckboxChecked' ) ;
} else {
$ ( '#blockedmlat_filter' ) . removeClass ( 'settingsCheckboxChecked' ) ;
}
localStorage [ 'blockedMLATFilter' ] = blockedMLATFilter ;
PlaneFilter . blockedMLAT = blockedMLATFilter ;
}
2017-02-10 21:41:48 +01:00
function toggleAltitudeChart ( switchToggle ) {
if ( typeof localStorage [ 'altitudeChart' ] === 'undefined' ) {
localStorage [ 'altitudeChart' ] = 'show' ;
}
var altitudeChartDisplay = localStorage [ 'altitudeChart' ] ;
if ( switchToggle === true ) {
altitudeChartDisplay = ( altitudeChartDisplay === 'show' ) ? 'hidden' : 'show' ;
}
2017-02-22 19:17:18 +01:00
// if you're using custom colors always hide the chart
if ( customAltitudeColors === true ) {
altitudeChartDisplay = 'hidden' ;
// also hide the control option
$ ( '#altitude_chart_container' ) . hide ( ) ;
}
2017-02-10 21:41:48 +01:00
if ( altitudeChartDisplay === 'show' ) {
$ ( '#altitude_checkbox' ) . addClass ( 'settingsCheckboxChecked' ) ;
$ ( '#altitude_chart' ) . show ( ) ;
} else {
$ ( '#altitude_checkbox' ) . removeClass ( 'settingsCheckboxChecked' ) ;
$ ( '#altitude_chart' ) . hide ( ) ;
}
localStorage [ 'altitudeChart' ] = altitudeChartDisplay ;
}
2016-08-24 22:28:13 +02:00
function onResetAltitudeFilter ( e ) {
$ ( "#altitude_filter_min" ) . val ( "" ) ;
$ ( "#altitude_filter_max" ) . val ( "" ) ;
updatePlaneFilter ( ) ;
refreshTableInfo ( ) ;
}
function updatePlaneFilter ( ) {
var minAltitude = parseFloat ( $ ( "#altitude_filter_min" ) . val ( ) . trim ( ) ) ;
var maxAltitude = parseFloat ( $ ( "#altitude_filter_max" ) . val ( ) . trim ( ) ) ;
if ( minAltitude === NaN ) {
minAltitude = - Infinity ;
}
if ( maxAltitude === NaN ) {
maxAltitude = Infinity ;
}
PlaneFilter . minAltitude = minAltitude ;
PlaneFilter . maxAltitude = maxAltitude ;
PlaneFilter . altitudeUnits = DisplayUnits ;
}
2016-08-30 23:38:41 +02:00
function getFlightAwareIdentLink ( ident , linkText ) {
2016-08-23 01:15:06 +02:00
if ( ident !== null && ident !== "" ) {
2016-08-30 23:38:41 +02:00
if ( ! linkText ) {
linkText = ident ;
}
return "<a target=\"_blank\" href=\"https://flightaware.com/live/flight/" + ident . trim ( ) + "\">" + linkText + "</a>" ;
2016-08-23 01:15:06 +02:00
}
return "" ;
}
2016-09-13 01:10:36 +02:00
function getFlightAwareModeSLink ( code , ident , linkText ) {
2016-09-07 21:20:42 +02:00
if ( code !== null && code . length > 0 && code [ 0 ] !== '~' && code !== "000000" ) {
2016-08-30 23:38:41 +02:00
if ( ! linkText ) {
linkText = "FlightAware: " + code . toUpperCase ( ) ;
}
2016-09-13 01:10:36 +02:00
var linkHtml = "<a target=\"_blank\" href=\"https://flightaware.com/live/modes/" + code ;
if ( ident !== null && ident !== "" ) {
linkHtml += "/ident/" + ident . trim ( ) ;
}
linkHtml += "/redirect\">" + linkText + "</a>" ;
return linkHtml ;
2016-08-23 01:15:06 +02:00
}
return "" ;
}
2016-08-23 17:41:58 +02:00
function getFlightAwarePhotoLink ( registration ) {
if ( registration !== null && registration !== "" ) {
2018-08-08 23:41:34 +02:00
return "<a target=\"_blank\" href=\"https://flightaware.com/photos/aircraft/" + registration . replace ( /[^0-9a-z]/ig , '' ) + "\">See Photos</a>" ;
2016-08-23 17:41:58 +02:00
}
2019-11-03 17:00:53 +01:00
return "" ;
2016-08-23 17:41:58 +02:00
}
2016-08-23 01:15:06 +02:00
function getAirframesModeSLink ( code ) {
2016-09-07 21:20:42 +02:00
if ( code !== null && code . length > 0 && code [ 0 ] !== '~' && code !== "000000" ) {
2016-08-23 01:15:06 +02:00
return "<a href=\"http://www.airframes.org/\" onclick=\"$('#airframes_post_icao').attr('value','" + code + "'); document.getElementById('horrible_hack').submit.call(document.getElementById('airframes_post')); return false;\">Airframes.org: " + code . toUpperCase ( ) + "</a>" ;
}
2019-11-03 17:00:53 +01:00
return "" ;
2016-08-23 01:15:06 +02:00
}
2017-01-23 21:02:45 +01:00
// takes in an elemnt jQuery path and the OL3 layer name and toggles the visibility based on clicking it
function toggleLayer ( element , layer ) {
// set initial checked status
2019-11-03 17:00:53 +01:00
ol . control . LayerSwitcher . forEachRecursive ( layers , function ( lyr ) {
2017-01-23 21:02:45 +01:00
if ( lyr . get ( 'name' ) === layer && lyr . getVisible ( ) ) {
$ ( element ) . addClass ( 'settingsCheckboxChecked' ) ;
}
} ) ;
$ ( element ) . on ( 'click' , function ( ) {
var visible = false ;
if ( $ ( element ) . hasClass ( 'settingsCheckboxChecked' ) ) {
visible = true ;
}
2019-11-03 17:00:53 +01:00
ol . control . LayerSwitcher . forEachRecursive ( layers , function ( lyr ) {
2017-01-23 21:02:45 +01:00
if ( lyr . get ( 'name' ) === layer ) {
if ( visible ) {
lyr . setVisible ( false ) ;
$ ( element ) . removeClass ( 'settingsCheckboxChecked' ) ;
} else {
lyr . setVisible ( true ) ;
$ ( element ) . addClass ( 'settingsCheckboxChecked' ) ;
}
}
} ) ;
} ) ;
}
2017-01-26 23:32:45 +01:00
// check status.json if it has a serial number for a flightfeeder
function flightFeederCheck ( ) {
$ . ajax ( '/status.json' , {
success : function ( data ) {
2017-02-10 19:18:13 +01:00
if ( data . type === "flightfeeder" ) {
2017-01-26 23:32:45 +01:00
isFlightFeeder = true ;
updatePiAwareOrFlightFeeder ( ) ;
}
}
} )
}
// updates the page to replace piaware with flightfeeder references
function updatePiAwareOrFlightFeeder ( ) {
if ( isFlightFeeder ) {
$ ( '.piAwareLogo' ) . hide ( ) ;
$ ( '.flightfeederLogo' ) . show ( ) ;
2019-07-16 21:11:19 +02:00
PageName = 'FlightFeeder SkyAware' ;
2017-01-26 23:32:45 +01:00
} else {
$ ( '.flightfeederLogo' ) . hide ( ) ;
$ ( '.piAwareLogo' ) . show ( ) ;
2019-07-16 21:11:19 +02:00
PageName = 'PiAware SkyAware' ;
2017-01-26 23:32:45 +01:00
}
refreshPageTitle ( ) ;
}