2019-07-31 19:37:00 +02:00
// Some global variables are defined in early.js
// early.js takes care of getting some history files while the html page and
// some javascript libraries are still loading, hopefully speeding up loading
2019-07-26 15:21:08 +02:00
2019-08-04 10:02:47 +02:00
"use strict" ;
2019-07-26 15:21:08 +02:00
// Define our global variables
var OLMap = null ;
2019-08-20 16:39:30 +02:00
var center = [ 50 , 10 ] ;
2019-07-26 15:21:08 +02:00
var StaticFeatures = new ol . Collection ( ) ;
var SiteCircleFeatures = new ol . Collection ( ) ;
var PlaneIconFeatures = new ol . Collection ( ) ;
2019-08-05 18:05:33 +02:00
var trailGroup = new ol . Collection ( ) ;
2019-08-20 14:30:26 +02:00
var iconsLayer ;
var iconCache = { } ;
2019-07-26 15:21:08 +02:00
var Planes = { } ;
var PlanesOrdered = [ ] ;
var PlaneFilter = { } ;
var SelectedPlane = null ;
var SelectedAllPlanes = false ;
var HighlightedPlane = null ;
var FollowSelected = false ;
var infoBoxOriginalPosition = { } ;
var customAltitudeColors = true ;
var loadtime = "loadtime" ;
2019-07-31 18:14:04 +02:00
var mapResizeTimeout ;
var HistoryItemsReturned = 0 ;
2019-07-26 15:21:08 +02:00
var refresh ;
2019-08-02 19:11:46 +02:00
var scaleFactor ;
var debug = false ;
2019-08-04 17:08:39 +02:00
var debugAll = false ;
2019-08-03 17:28:43 +02:00
var fragment ;
2019-08-05 13:26:22 +02:00
var grouptype _checkbox ;
2019-08-08 18:23:51 +02:00
var multiSelect = false ;
2019-08-19 20:02:05 +02:00
var uat _data = null ;
2019-08-05 13:26:22 +02:00
2019-07-26 15:21:08 +02: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' }
} ;
// Get current map settings
2019-08-07 17:47:18 +02:00
var CenterLat , CenterLon , ZoomLvl , ZoomLvlCache , MapType _tar1090 ;
2019-07-26 15:21:08 +02:00
var PlaneRowTemplate = null ;
var TrackedAircraft = 0 ;
var TrackedAircraftPositions = 0 ;
var TrackedHistorySize = 0 ;
var SitePosition = null ;
2019-08-04 10:02:47 +02:00
// timestamps
var now = 0 , last = 0 , uat _now = 0 , uat _last = 0 ;
2019-07-26 15:21:08 +02:00
var StaleReceiverCount = 0 ;
var FetchPending = null ;
2019-07-29 19:51:41 +02:00
var FetchPendingUAT = null ;
2019-07-26 15:21:08 +02:00
var MessageCountHistory = [ ] ;
var MessageRate = 0 ;
var NBSP = '\u00a0' ;
var layers ;
// piaware vs flightfeeder
var isFlightFeeder = false ;
2019-07-31 18:14:04 +02:00
// this will be needed later, get it right when the script is loaded
$ . getJSON ( "db/aircraft_types/icao_aircraft_types.json" )
. done ( function ( typeLookupData ) {
_aircraft _type _cache = typeLookupData ;
} )
2019-08-04 14:28:01 +02:00
function processReceiverUpdate ( data , init ) {
2019-07-29 19:51:41 +02:00
2019-08-04 10:02:47 +02:00
// update now and last
2019-08-04 14:28:01 +02:00
var uat = false ;
if ( data . uat _978 == "true" ) {
uat = true ;
2019-08-04 10:02:47 +02:00
uat _last = uat _now ;
uat _now = data . now ;
} else {
last = now ;
now = data . now ;
}
2019-07-26 15:21:08 +02:00
// Loop through all the planes in the data packet
var acs = data . aircraft ;
2019-08-02 19:11:46 +02:00
if ( ! uat && ! init ) {
2019-07-29 19:51:41 +02:00
// Detect stats reset
if ( MessageCountHistory . length > 0 && MessageCountHistory [ MessageCountHistory . length - 1 ] . messages > data . messages ) {
MessageCountHistory = [ { 'time' : MessageCountHistory [ MessageCountHistory . length - 1 ] . time ,
'messages' : 0 } ] ;
}
// 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 ( ) ;
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 ;
}
}
2019-07-26 15:21:08 +02:00
for ( var j = 0 ; j < acs . length ; j ++ ) {
var ac = acs [ j ] ;
var hex = ac . hex ;
var plane = null ;
// Do we already have this plane object in Planes?
// If not make it.
2019-08-04 21:10:13 +02:00
if ( uat && ac . type && ac . type . substring ( 0 , 4 ) == "tisb" ) {
// drop non ADS-B planes from UAT (TIS-B)
continue ;
}
2019-07-26 15:21:08 +02:00
if ( Planes [ hex ] ) {
plane = Planes [ hex ] ;
} else if ( ac . messages < 4 ) {
continue ;
} else {
plane = new PlaneObject ( hex ) ;
plane . filter = PlaneFilter ;
2019-08-02 19:11:46 +02:00
if ( ! init )
2019-07-31 15:07:26 +02:00
setupPlane ( hex , plane ) ;
2019-07-26 15:21:08 +02:00
Planes [ hex ] = plane ;
PlanesOrdered . push ( plane ) ;
}
// Call the function update
2019-08-04 21:10:13 +02:00
if ( uat ) {
2019-08-05 13:26:22 +02:00
if ( ac . seen < 58 )
2019-08-04 21:10:13 +02:00
plane . dataSource = "uat" ;
else
plane . dataSource = "other" ;
2019-08-04 14:28:01 +02:00
plane . updateData ( uat _now , ac , init ) ;
2019-08-04 21:10:13 +02:00
} else {
2019-08-04 14:28:01 +02:00
plane . updateData ( now , ac , init ) ;
2019-08-04 21:10:13 +02:00
}
2019-07-26 15:21:08 +02:00
}
}
2019-07-31 15:07:26 +02:00
function setupPlane ( hex , plane ) {
plane . tr = PlaneRowTemplate . cloneNode ( true ) ;
if ( hex [ 0 ] === '~' ) {
// Non-ICAO address
plane . tr . cells [ 0 ] . textContent = hex . substring ( 1 ) ;
$ ( plane . tr ) . css ( 'font-style' , 'italic' ) ;
} else {
plane . tr . cells [ 0 ] . textContent = hex ;
}
// 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' ) ;
}
2019-08-03 17:28:43 +02:00
plane . clickListener = function ( h , evt ) {
2019-07-31 15:07:26 +02:00
if ( evt . srcElement instanceof HTMLAnchorElement ) {
evt . stopPropagation ( ) ;
return ;
}
if ( ! $ ( "#map_container" ) . is ( ":visible" ) ) {
showMap ( ) ;
}
selectPlaneByHex ( h , false ) ;
adjustSelectedInfoBlockPosition ( ) ;
evt . preventDefault ( ) ;
2019-08-03 17:28:43 +02:00
} . bind ( undefined , hex ) ;
2019-07-31 15:07:26 +02:00
2019-08-03 17:28:43 +02:00
plane . dblclickListener = function ( h , evt ) {
2019-07-31 15:07:26 +02:00
if ( ! $ ( "#map_container" ) . is ( ":visible" ) ) {
showMap ( ) ;
}
selectPlaneByHex ( h , true ) ;
adjustSelectedInfoBlockPosition ( ) ;
evt . preventDefault ( ) ;
2019-08-03 17:28:43 +02:00
} . bind ( undefined , hex ) ;
plane . tr . addEventListener ( 'click' , plane . clickListener ) ;
plane . tr . addEventListener ( 'dblclick' , plane . dblclickListener ) ;
2019-07-31 15:07:26 +02:00
}
2019-07-26 15:21:08 +02:00
function fetchData ( ) {
2019-08-20 16:39:30 +02:00
localStorage [ 'CenterLon' ] = center [ 0 ] ;
localStorage [ 'CenterLat' ] = center [ 1 ] ;
2019-08-04 20:03:46 +02:00
if ( FetchPending != null && FetchPending . state ( ) == 'pending' ) {
// don't double up on fetches, let the last one resolve
return ;
}
if ( FetchPendingUAT != null && FetchPendingUAT . state ( ) == 'pending' ) {
2019-07-26 15:21:08 +02:00
// don't double up on fetches, let the last one resolve
return ;
}
2019-07-29 19:51:41 +02:00
if ( enable _uat ) {
2019-07-30 15:56:56 +02:00
FetchPendingUAT = $ . ajax ( { url : 'chunks/978.json' ,
2019-08-19 20:02:05 +02:00
timeout : 2000 ,
2019-07-29 19:51:41 +02:00
cache : false ,
dataType : 'json' } ) ;
2019-08-04 14:28:01 +02:00
$ . when ( FetchPendingUAT ) . done ( function ( data ) {
2019-08-19 20:02:05 +02:00
uat _data = data ;
2019-08-04 14:28:01 +02:00
} ) ;
2019-07-29 19:51:41 +02:00
}
2019-07-26 15:21:08 +02:00
FetchPending = $ . ajax ( { url : 'data/aircraft.json' ,
timeout : 5000 ,
cache : false ,
dataType : 'json' } ) ;
FetchPending . done ( function ( data ) {
2019-08-01 17:59:39 +02:00
if ( data == null )
return ;
2019-07-26 15:21:08 +02:00
// experimental stuff
/ *
var browserNow = ( new Date ( ) ) . getTime ( ) ;
var diff = browserNow - now * 1000 ;
var delay = RefreshInterval ;
if ( diff > - 100 )
delay = Math . max ( RefreshInterval * 1.3 - diff , 100 ) ;
window . setTimeout ( fetchData , delay ) ;
2019-08-04 10:02:47 +02:00
if ( ( now - last ) * 1000 > 1.5 * RefreshInterval || ( now - last ) * 1000 < 0.5 * RefreshInterval )
2019-07-26 15:21:08 +02:00
console . log ( "We missed a beat: aircraft.json" ) ;
2019-08-04 10:02:47 +02:00
console . log ( ( ( now - last ) * 1000 ) . toFixed ( 0 ) + " " + diff + " " + delay + " " + now ) ;
2019-07-29 13:45:54 +02:00
* /
2019-07-26 15:21:08 +02:00
2019-08-19 20:02:05 +02:00
if ( uat _data && uat _data . now > uat _now ) {
processReceiverUpdate ( uat _data ) ;
uat _data = null ;
}
if ( data . now > now ) {
processReceiverUpdate ( data ) ;
}
2019-07-26 15:21:08 +02:00
2019-07-29 13:45:54 +02: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 ] ;
2019-08-04 10:02:47 +02:00
if ( plane . dataSource == "uat" )
plane . updateTick ( uat _now , uat _last ) ;
else
plane . updateTick ( now , last ) ;
2019-07-29 13:45:54 +02:00
}
2019-08-19 20:02:05 +02:00
selectNewPlanes ( ) ;
2019-07-26 15:21:08 +02:00
2019-08-20 14:30:26 +02:00
2019-07-26 15:21:08 +02:00
refreshSelected ( ) ;
refreshHighlighted ( ) ;
2019-08-17 20:10:14 +02:00
refreshTableInfo ( ) ;
2019-08-19 20:02:05 +02:00
refreshClock ( new Date ( now * 1000 ) ) ;
2019-07-26 15:21:08 +02:00
// Check for stale receiver data
2019-08-04 10:02:47 +02:00
if ( last == now ) {
2019-07-26 15:21:08 +02:00
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-08-04 10:02:47 +02:00
} else {
2019-07-26 15:21:08 +02:00
StaleReceiverCount = 0 ;
$ ( "#update_error" ) . css ( 'display' , 'none' ) ;
}
2019-08-04 14:28:01 +02:00
2019-07-26 15:21:08 +02: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' ) ;
fetchData ( ) ;
} ) ;
}
2019-07-31 18:14:04 +02:00
// this function is called from index.html on body load
// kicks off the whole rabbit hole
function initialize ( ) {
2019-07-31 19:37:00 +02:00
$ . when ( configureReceiver ) . done ( function ( ) {
2019-08-02 21:10:05 +02:00
configureReceiver = null ;
2019-07-31 18:14:04 +02:00
// Initialize stuff
init _page ( ) ;
2019-07-31 19:37:00 +02:00
// Wait for history item downloads and append them to the buffer
push _history ( ) ;
2019-07-26 15:21:08 +02:00
} ) ;
2019-07-31 18:14:04 +02:00
2019-07-26 15:21:08 +02:00
}
2019-07-31 15:07:26 +02:00
2019-07-31 18:14:04 +02:00
function init _page ( ) {
2019-07-26 15:21:08 +02:00
// Set page basics
document . title = PageName ;
2019-07-31 15:07:26 +02:00
//flightFeederCheck();
2019-07-26 15:21:08 +02:00
PlaneRowTemplate = document . getElementById ( "plane_row_template" ) ;
2019-07-29 13:45:54 +02:00
$ ( '#clock_div' ) . text ( new Date ( ) . toLocaleString ( ) ) ;
2019-07-26 15:21:08 +02:00
$ ( "#loader" ) . removeClass ( "hidden" ) ;
if ( ExtendedData || window . location . hash == '#extended' ) {
$ ( "#extendedData" ) . removeClass ( "hidden" ) ;
}
// Set up map/sidebar splitter
$ ( "#sidebar_container" ) . resizable ( {
handles : {
w : '#splitter'
} ,
minWidth : 350
} ) ;
// Set up datablock splitter
$ ( '#selected_infoblock' ) . resizable ( {
handles : {
s : '#splitter-infoblock'
} ,
containment : "#sidebar_container" ,
minHeight : 50
} ) ;
$ ( '#close-button' ) . on ( 'click' , function ( ) {
2019-08-20 16:39:30 +02:00
if ( SelectedPlane ) {
SelectedPlane . selected = null ;
SelectedPlane . clearLines ( ) ;
SelectedPlane . updateMarker ( ) ;
2019-07-26 15:21:08 +02:00
SelectedPlane = null ;
refreshSelected ( ) ;
refreshHighlighted ( ) ;
$ ( '#selected_infoblock' ) . hide ( ) ;
}
} ) ;
// 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 ( ) {
2019-08-12 18:09:58 +02:00
var topCalc = ( $ ( window ) . height ( ) - $ ( '#selected_infoblock' ) . height ( ) - 25 ) ;
2019-07-26 15:21:08 +02:00
// check if the top will be less than zero, which will be overlapping/off the screen, and set the top correctly.
if ( topCalc < 0 ) {
topCalc = 0 ;
2019-08-12 18:09:58 +02:00
$ ( '#selected_infoblock' ) . css ( 'height' , ( $ ( window ) . height ( ) - 25 ) + 'px' ) ;
2019-07-26 15:21:08 +02:00
}
$ ( '#selected_infoblock' ) . css ( 'top' , topCalc + 'px' ) ;
} ) ;
2019-08-12 18:09:58 +02:00
/ *
2019-07-26 15:21:08 +02:00
// to make the infoblock responsive
$ ( '#sidebar_container' ) . on ( 'resize' , function ( ) {
2019-07-31 15:07:26 +02:00
if ( $ ( '#sidebar_container' ) . width ( ) < 600 ) {
2019-07-26 15:21:08 +02:00
$ ( '#selected_infoblock' ) . addClass ( 'infoblock-container-small' ) ;
} else {
$ ( '#selected_infoblock' ) . removeClass ( 'infoblock-container-small' ) ;
}
} ) ;
2019-08-08 19:14:32 +02:00
* /
2019-07-26 15:21:08 +02:00
// Set up event handlers for buttons
$ ( "#toggle_sidebar_button" ) . click ( toggleSidebarVisibility ) ;
$ ( "#expand_sidebar_button" ) . click ( expandSidebar ) ;
$ ( "#show_map_button" ) . click ( showMap ) ;
// Set initial element visibility
$ ( "#show_map_button" ) . hide ( ) ;
setColumnVisibility ( ) ;
// Initialize other controls
initializeUnitsSelector ( ) ;
// Set up altitude filter button event handlers and validation options
$ ( "#altitude_filter_form" ) . submit ( onFilterByAltitude ) ;
// 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 ;
}
$ ( "#altitude_filter_reset_button" ) . click ( onResetAltitudeFilter ) ;
$ ( '#settingsCog' ) . on ( 'click' , function ( ) {
$ ( '#settings_infoblock' ) . toggle ( ) ;
} ) ;
$ ( '#settings_close' ) . on ( 'click' , function ( ) {
$ ( '#settings_infoblock' ) . hide ( ) ;
} ) ;
$ ( '#groundvehicle_filter' ) . on ( 'click' , function ( ) {
filterGroundVehicles ( true ) ;
refreshSelected ( ) ;
refreshHighlighted ( ) ;
refreshTableInfo ( ) ;
} ) ;
$ ( '#blockedmlat_filter' ) . on ( 'click' , function ( ) {
filterBlockedMLAT ( true ) ;
refreshSelected ( ) ;
refreshHighlighted ( ) ;
refreshTableInfo ( ) ;
} ) ;
$ ( '#grouptype_checkbox' ) . on ( 'click' , function ( ) {
if ( $ ( '#grouptype_checkbox' ) . hasClass ( 'settingsCheckboxChecked' ) ) {
sortByDistance ( ) ;
} else {
sortByDataSource ( ) ;
}
} ) ;
$ ( '#altitude_checkbox' ) . on ( 'click' , function ( ) {
toggleAltitudeChart ( true ) ;
} ) ;
2019-08-04 17:08:39 +02:00
$ ( '#debugAll_checkbox' ) . on ( 'click' , function ( ) {
toggleDebugAll ( ) ;
} ) ;
if ( localStorage [ 'debugAll' ] === "true" ) {
debugAll = true ;
$ ( '#debugAll_checkbox' ) . addClass ( 'settingsCheckboxChecked' ) ;
} else {
debugAll = false ;
$ ( '#debugAll_checkbox' ) . removeClass ( 'settingsCheckboxChecked' ) ;
}
2019-08-04 16:46:55 +02:00
$ ( '#debug_checkbox' ) . on ( 'click' , function ( ) {
toggleDebug ( ) ;
} ) ;
if ( localStorage [ 'debug' ] === "true" ) {
debug = true ;
$ ( '#debug_checkbox' ) . addClass ( 'settingsCheckboxChecked' ) ;
} else {
debug = false ;
$ ( '#debug_checkbox' ) . removeClass ( 'settingsCheckboxChecked' ) ;
}
2019-07-26 15:21:08 +02:00
$ ( '#selectall_checkbox' ) . on ( 'click' , function ( ) {
if ( $ ( '#selectall_checkbox' ) . hasClass ( 'settingsCheckboxChecked' ) ) {
deselectAllPlanes ( ) ;
} else {
selectAllPlanes ( ) ;
}
} )
2019-08-19 18:13:58 +02:00
$ ( '#mapdim_checkbox' ) . on ( 'click' , function ( ) {
toggleMapDim ( ) ;
} ) ;
2019-07-26 15:21:08 +02:00
// Force map to redraw if sidebar container is resized - use a timer to debounce
$ ( "#sidebar_container" ) . on ( "resize" , function ( ) {
clearTimeout ( mapResizeTimeout ) ;
mapResizeTimeout = setTimeout ( updateMapSize , 10 ) ;
} ) ;
filterGroundVehicles ( false ) ;
filterBlockedMLAT ( false ) ;
toggleAltitudeChart ( false ) ;
}
2019-07-31 18:14:04 +02:00
2019-07-31 19:37:00 +02:00
function push _history ( ) {
2019-07-31 22:48:58 +02:00
$ ( "#loader_progress" ) . attr ( 'max' , nHistoryItems * 2 ) ;
for ( var i = 0 ; i < nHistoryItems ; i ++ ) {
2019-07-31 19:37:00 +02:00
push _history _item ( i ) ;
2019-07-31 18:14:04 +02:00
}
2019-08-18 10:32:31 +02:00
if ( ! nHistoryItems ) {
parse _history ( ) ;
}
2019-07-31 18:14:04 +02:00
}
2019-07-26 15:21:08 +02:00
2019-07-31 19:37:00 +02:00
function push _history _item ( i ) {
2019-07-26 15:21:08 +02:00
2019-07-31 18:14:04 +02:00
$ . when ( deferHistory [ i ] )
2019-07-29 19:51:41 +02:00
. done ( function ( json ) {
2019-07-26 15:21:08 +02:00
2019-07-31 18:14:04 +02:00
if ( HistoryChunks ) {
for ( var i in json . files ) {
PositionHistoryBuffer . push ( json . files [ i ] ) ;
}
} else {
2019-07-31 19:37:00 +02:00
PositionHistoryBuffer . push ( json ) ;
2019-07-26 15:21:08 +02:00
}
2019-07-31 18:14:04 +02:00
$ ( "#loader_progress" ) . attr ( 'value' , HistoryItemsReturned ) ;
2019-07-26 15:21:08 +02:00
HistoryItemsReturned ++ ;
2019-07-31 22:48:58 +02:00
if ( HistoryItemsReturned == nHistoryItems ) {
2019-07-31 19:37:00 +02:00
parse _history ( ) ;
2019-07-26 15:21:08 +02:00
}
} )
. fail ( function ( jqxhr , status , error ) {
2019-07-31 18:14:04 +02:00
2019-07-26 15:21:08 +02:00
//Doesn't matter if it failed, we'll just be missing a data point
$ ( "#loader_progress" ) . attr ( 'value' , HistoryItemsReturned ) ;
//console.log(error);
HistoryItemsReturned ++ ;
2019-07-31 22:48:58 +02:00
if ( HistoryItemsReturned == nHistoryItems ) {
2019-07-31 19:37:00 +02:00
parse _history ( ) ;
2019-07-26 15:21:08 +02:00
}
} ) ;
}
2019-07-31 18:14:04 +02:00
2019-07-31 19:37:00 +02:00
function parse _history ( ) {
2019-07-31 18:14:04 +02:00
console . timeEnd ( "Downloaded History" ) ;
2019-07-31 19:37:00 +02:00
console . time ( "Loaded aircraft tracks from History" ) ;
2019-07-26 15:21:08 +02:00
$ ( "#loader" ) . addClass ( "hidden" ) ;
2019-08-02 21:10:05 +02:00
for ( i in deferHistory )
deferHistory [ i ] = null ;
2019-07-31 19:37:00 +02:00
initialize _map ( ) ;
2019-07-26 15:21:08 +02:00
if ( PositionHistoryBuffer . length > 0 ) {
// Sort history by timestamp
2019-08-08 23:35:58 +02:00
console . log ( "Sorting history: " + PositionHistoryBuffer . length ) ;
2019-08-04 19:38:03 +02:00
PositionHistoryBuffer . sort ( function ( x , y ) { return ( y . now - x . now ) ; } ) ;
2019-07-26 15:21:08 +02:00
// Process history
2019-08-04 19:38:03 +02:00
var data ;
var h = 0 ;
var pruneInt = Math . floor ( PositionHistoryBuffer . length / 5 ) ;
while ( data = PositionHistoryBuffer . pop ( ) ) {
2019-08-01 11:37:03 +02:00
// process new data
2019-08-04 19:38:03 +02:00
if ( PositionHistoryBuffer . length < 10 )
2019-08-04 14:28:01 +02:00
processReceiverUpdate ( data , false ) ;
2019-08-04 19:38:03 +02:00
else
processReceiverUpdate ( data , true ) ;
2019-07-26 15:21:08 +02:00
2019-08-01 11:37:03 +02:00
// update aircraft tracks
2019-08-04 14:28:01 +02:00
if ( data . uat _978 != "true" ) {
2019-08-01 11:37:03 +02:00
for ( var i = 0 ; i < PlanesOrdered . length ; ++ i ) {
var plane = PlanesOrdered [ i ] ;
2019-08-03 20:26:12 +02:00
if ( plane . dataSource == "uat" )
2019-08-01 11:37:03 +02:00
plane . updateTrack ( uat _now , uat _last ) ;
else
plane . updateTrack ( now , last ) ;
}
2019-07-26 15:21:08 +02:00
}
2019-08-01 11:37:03 +02:00
// prune aircraft list
2019-08-04 19:38:03 +02:00
if ( h ++ % pruneInt == pruneInt - 1 ) {
2019-08-01 11:37:03 +02:00
2019-08-09 17:27:57 +02:00
console . log ( "Applied history " + h + " from: "
2019-08-01 11:37:03 +02:00
+ ( new Date ( now * 1000 ) ) . toLocaleTimeString ( ) ) ;
2019-07-31 20:57:22 +02:00
2019-08-03 18:06:35 +02:00
reaper ( ) ;
2019-07-26 15:21:08 +02:00
}
}
// Final pass to update all planes to their latest state
console . log ( "Final history cleanup pass" ) ;
2019-08-05 12:32:28 +02:00
for ( var i in PlanesOrdered ) {
2019-07-26 15:21:08 +02:00
var plane = PlanesOrdered [ i ] ;
2019-08-05 12:32:28 +02:00
if ( plane . position && SitePosition )
plane . sitedist = ol . sphere . getDistance ( SitePosition , plane . position ) ;
2019-08-04 10:02:47 +02:00
if ( plane . dataSource == "uat" )
plane . updateTick ( uat _now , uat _last , true ) ;
else
plane . updateTick ( now , last , true ) ;
2019-07-26 15:21:08 +02:00
}
2019-07-31 15:07:26 +02:00
for ( var i in PlanesOrdered )
setupPlane ( PlanesOrdered [ i ] . icao , PlanesOrdered [ i ] ) ;
2019-07-26 15:21:08 +02:00
}
PositionHistoryBuffer = null ;
2019-07-31 19:37:00 +02:00
console . timeEnd ( "Loaded aircraft tracks from History" ) ;
2019-07-26 15:21:08 +02:00
console . log ( "Completing init" ) ;
refreshTableInfo ( ) ;
refreshSelected ( ) ;
refreshHighlighted ( ) ;
// Setup our timer to poll from the server.
window . setInterval ( fetchData , RefreshInterval ) ;
window . setInterval ( reaper , 60000 ) ;
2019-08-18 13:26:51 +02:00
if ( enable _pf _data ) {
2019-08-20 16:39:30 +02:00
window . setInterval ( fetchPfData , RefreshInterval * 10.314 ) ;
2019-08-18 13:26:51 +02:00
}
2019-07-26 15:21:08 +02:00
// And kick off one refresh immediately.
fetchData ( ) ;
}
// 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 ;
2019-07-26 21:53:00 +02:00
var geom ;
2019-07-26 15:21:08 +02:00
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 ;
2019-07-26 21:53:00 +02:00
if ( ! geom )
geom = new ol . geom . LineString ( [ [ lon2 , lat2 ] ] ) ;
else
geom . appendCoordinate ( [ lon2 , lat2 ] ) ;
2019-07-26 15:21:08 +02:00
}
return geom ;
}
// Initalizes the map and starts up our timers to call various functions
function initialize _map ( ) {
2019-07-31 19:37:00 +02:00
if ( receiverJson && receiverJson . lat != null ) {
SiteShow = true ;
SiteLat = receiverJson . lat ;
SiteLon = receiverJson . lon ;
DefaultCenterLat = receiverJson . lat ;
DefaultCenterLon = receiverJson . lon ;
}
2019-07-26 15:21:08 +02:00
// Load stored map settings if present
2019-08-20 16:39:30 +02:00
center [ 0 ] = CenterLat = Number ( localStorage [ 'CenterLat' ] ) || DefaultCenterLat ;
center [ 1 ] = CenterLon = Number ( localStorage [ 'CenterLon' ] ) || DefaultCenterLon ;
2019-07-26 15:21:08 +02:00
ZoomLvl = Number ( localStorage [ 'ZoomLvl' ] ) || DefaultZoomLvl ;
2019-08-02 19:11:46 +02:00
ZoomLvlCache = ZoomLvl ;
2019-08-07 17:47:18 +02:00
MapType _tar1090 = localStorage [ 'MapType_tar1090' ] ;
2019-07-26 15:21:08 +02:00
// Set SitePosition, initialize sorting
if ( SiteShow && ( typeof SiteLat !== 'undefined' ) && ( typeof SiteLon !== 'undefined' ) ) {
SitePosition = [ SiteLon , SiteLat ] ;
sortByDistance ( ) ;
} else {
SitePosition = null ;
PlaneRowTemplate . cells [ 9 ] . style . display = 'none' ; // hide distance column
document . getElementById ( "distance" ) . style . display = 'none' ; // hide distance header
sortByAltitude ( ) ;
}
// 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
}
// Initialize OL3
layers = createBaseLayers ( ) ;
2019-08-20 14:30:26 +02:00
iconsLayer = new ol . layer . Vector ( {
2019-07-26 15:21:08 +02:00
name : 'ac_positions' ,
type : 'overlay' ,
title : 'Aircraft positions' ,
source : new ol . source . Vector ( {
features : PlaneIconFeatures ,
2019-08-17 20:10:14 +02:00
} ) ,
2019-07-26 15:21:08 +02:00
} ) ;
2019-08-05 18:05:33 +02:00
layers . push (
new ol . layer . Vector ( {
name : 'site_pos' ,
type : 'overlay' ,
title : 'Site position and range rings' ,
source : new ol . source . Vector ( {
features : StaticFeatures ,
} )
} ) ) ;
layers . push (
new ol . layer . Group ( {
name : 'ac_trail' ,
title : 'Aircraft trails' ,
type : 'overlay' ,
layers : trailGroup ,
} )
) ;
2019-07-26 15:21:08 +02:00
2019-08-05 18:05:33 +02:00
layers . push ( iconsLayer ) ;
2019-07-26 15:21:08 +02:00
var foundType = false ;
var baseCount = 0 ;
ol . control . LayerSwitcher . forEachRecursive ( layers , function ( lyr ) {
if ( ! lyr . get ( 'name' ) )
return ;
if ( lyr . get ( 'type' ) === 'base' ) {
baseCount ++ ;
2019-08-07 17:47:18 +02:00
if ( MapType _tar1090 === lyr . get ( 'name' ) ) {
2019-07-26 15:21:08 +02:00
foundType = true ;
lyr . setVisible ( true ) ;
} else {
lyr . setVisible ( false ) ;
}
lyr . on ( 'change:visible' , function ( evt ) {
if ( evt . target . getVisible ( ) ) {
2019-08-07 17:47:18 +02:00
MapType _tar1090 = localStorage [ 'MapType_tar1090' ] = evt . target . get ( 'name' ) ;
2019-07-26 15:21:08 +02:00
}
} ) ;
} 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 ( {
target : 'map_canvas' ,
layers : layers ,
view : new ol . View ( {
center : ol . proj . fromLonLat ( [ CenterLon , CenterLat ] ) ,
zoom : ZoomLvl
} ) ,
2019-08-19 00:35:49 +02:00
controls : [ new ol . control . Zoom ( { delta : 1 , } ) ,
2019-07-26 15:21:08 +02:00
new ol . control . Rotate ( ) ,
new ol . control . Attribution ( { collapsed : true } ) ,
new ol . control . ScaleLine ( { units : DisplayUnits } )
] ,
loadTilesWhileAnimating : true ,
loadTilesWhileInteracting : true
} ) ;
if ( baseCount > 1 ) {
OLMap . addControl ( new ol . control . LayerSwitcher ( ) ) ;
}
// Listeners for newly created Map
OLMap . getView ( ) . on ( 'change:center' , function ( event ) {
2019-08-20 16:39:30 +02:00
center = ol . proj . toLonLat ( OLMap . getView ( ) . getCenter ( ) , OLMap . getView ( ) . getProjection ( ) ) ;
2019-07-26 15:21:08 +02:00
if ( FollowSelected ) {
// On manual navigation, disable follow
2019-08-20 16:39:30 +02:00
if ( ! SelectedPlane ||
( Math . abs ( center [ 0 ] - SelectedPlane . position [ 0 ] ) > 0.0001 &&
Math . abs ( center [ 1 ] - SelectedPlane . position [ 1 ] ) > 0.0001 ) ) {
2019-07-26 15:21:08 +02:00
FollowSelected = false ;
refreshSelected ( ) ;
refreshHighlighted ( ) ;
}
}
} ) ;
2019-08-02 19:11:46 +02:00
scaleFactor = 1.2 * Math . max ( 0.2 , Math . min ( 1.2 , 0.15 * Math . pow ( 1.25 , ZoomLvl ) ) ) ;
2019-07-26 15:21:08 +02:00
OLMap . getView ( ) . on ( 'change:resolution' , function ( event ) {
2019-08-02 19:11:46 +02:00
ZoomLvl = localStorage [ 'ZoomLvl' ] = OLMap . getView ( ) . getZoom ( ) ;
// small zoomstep, no need to change aircraft scaling
if ( Math . abs ( ZoomLvl - ZoomLvlCache ) < 0.3 )
return ;
ZoomLvlCache = ZoomLvl ;
scaleFactor = 1.2 * Math . max ( 0.2 , Math . min ( 1.2 , 0.15 * Math . pow ( 1.25 , ZoomLvl ) ) ) ;
2019-08-15 21:46:27 +02:00
for ( var i in PlanesOrdered ) {
var plane = PlanesOrdered [ i ] ;
if ( plane . markerIcon ) {
plane . scaleCache = scaleFactor * plane . baseScale ;
plane . markerIcon . setScale ( plane . scaleCache ) ;
}
2019-08-02 19:11:46 +02:00
}
2019-07-26 15:21:08 +02:00
} ) ;
OLMap . on ( [ 'click' , 'dblclick' ] , function ( evt ) {
var hex = evt . map . forEachFeatureAtPixel ( evt . pixel ,
function ( feature , layer ) {
return feature . hex ;
} ,
2019-07-26 21:53:00 +02:00
{ layerFilter : function ( layer ) {
2019-07-26 15:21:08 +02:00
return ( layer === iconsLayer ) ;
2019-07-26 21:53:00 +02:00
} } ) ;
2019-07-26 15:21:08 +02:00
if ( hex ) {
selectPlaneByHex ( hex , ( evt . type === 'dblclick' ) ) ;
adjustSelectedInfoBlockPosition ( ) ;
evt . stopPropagation ( ) ;
} else {
deselectAllPlanes ( ) ;
evt . stopPropagation ( ) ;
}
} ) ;
// show the hover box
OLMap . on ( 'pointermove' , function ( evt ) {
var hex = evt . map . forEachFeatureAtPixel ( evt . pixel ,
function ( feature , layer ) {
return feature . hex ;
} ,
2019-07-26 21:53:00 +02:00
{ layerFilter : function ( layer ) {
2019-07-26 15:21:08 +02:00
return ( layer === iconsLayer ) ;
2019-07-26 21:53:00 +02:00
} }
2019-07-26 15:21:08 +02:00
) ;
if ( hex ) {
highlightPlaneByHex ( hex ) ;
} else {
removeHighlight ( ) ;
}
} )
// 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' ) ;
} ) ;
// Add home marker if requested
if ( SitePosition ) {
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 ) ;
if ( SiteCircles ) {
createSiteCircleFeatures ( ) ;
}
}
2019-08-19 18:13:58 +02:00
if ( localStorage [ 'MapDim' ] === "true" ) {
const maps = layers [ 0 ] . getLayersArray ( ) ;
for ( const i in maps ) {
maps [ i ] . dimKey = maps [ i ] . on ( 'postcompose' , dim ) ;
}
$ ( '#mapdim_checkbox' ) . addClass ( 'settingsCheckboxChecked' ) ;
}
2019-07-26 15:21:08 +02: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 \
// 'http://www.heywhatsthat.com/api/upintheair.json?id=XXXX&refraction=0.25&alts=3048,9144'
//
// 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 ) {
for ( var i = 0 ; i < data . rings . length ; ++ i ) {
2019-07-26 21:53:00 +02:00
var geom = null ;
2019-07-26 15:21:08 +02:00
var points = data . rings [ i ] . points ;
2019-08-14 11:06:37 +02:00
var altitude = ( 3.28084 * data . rings [ i ] . alt ) . toFixed ( 0 ) ;
var color = range _outline _color ;
if ( range _outline _colored _by _altitude ) {
var colorArr = altitudeColor ( altitude ) ;
2019-08-19 20:02:05 +02:00
color = 'hsl(' + colorArr [ 0 ] . toFixed ( 0 ) + ',' + colorArr [ 1 ] . toFixed ( 0 ) + '%,' + colorArr [ 2 ] . toFixed ( 0 ) + '%)' ;
2019-08-14 11:06:37 +02:00
}
var ringStyle = new ol . style . Style ( {
fill : null ,
stroke : new ol . style . Stroke ( {
color : color ,
width : range _outline _width ,
} )
} ) ;
2019-07-26 15:21:08 +02:00
if ( points . length > 0 ) {
2019-08-02 19:11:46 +02:00
geom = new ol . geom . LineString ( [ [ points [ 0 ] [ 1 ] , points [ 0 ] [ 0 ] ] ] ) ;
2019-07-26 15:21:08 +02:00
for ( var j = 0 ; j < points . length ; ++ j ) {
2019-07-26 21:53:00 +02:00
geom . appendCoordinate ( [ points [ j ] [ 1 ] , points [ j ] [ 0 ] ] ) ;
2019-07-26 15:21:08 +02:00
}
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 ) ;
}
}
} ) ;
request . fail ( function ( jqxhr , status , error ) {
// no rings available, do nothing
} ) ;
}
function createSiteCircleFeatures ( ) {
// Clear existing circles first
SiteCircleFeatures . forEach ( function ( circleFeature ) {
StaticFeatures . remove ( circleFeature ) ;
} ) ;
SiteCircleFeatures . clear ( ) ;
var circleStyle = function ( distance ) {
return new ol . style . Style ( {
fill : null ,
stroke : new ol . style . Stroke ( {
color : '#000000' ,
width : 1
} ) ,
text : new ol . style . Text ( {
font : '10px Helvetica Neue, sans-serif' ,
fill : new ol . style . Fill ( { color : '#000' } ) ,
offsetY : - 8 ,
text : format _distance _long ( distance , DisplayUnits , 0 )
} )
} ) ;
} ;
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 ) ;
feature . setStyle ( circleStyle ( distance ) ) ;
StaticFeatures . push ( feature ) ;
SiteCircleFeatures . push ( feature ) ;
}
}
// This looks for planes to reap out of the master Planes variable
function reaper ( ) {
//console.log("Reaping started..");
// Look for planes where we have seen no messages for >300 seconds
var newPlanes = [ ] ;
2019-08-03 17:28:43 +02:00
var plane ;
while ( plane = PlanesOrdered . pop ( ) ) {
2019-08-04 10:02:47 +02:00
plane . seen = now - plane . last _message _time ;
2019-07-30 19:59:17 +02:00
if ( plane . seen > 600 ) {
2019-07-26 15:21:08 +02:00
// Reap it.
2019-08-03 18:06:35 +02:00
//console.log("Removed " + plane.icao);
2019-07-26 15:21:08 +02:00
plane . destroy ( ) ;
2019-08-03 18:06:35 +02:00
delete Planes [ plane . icao ] ;
2019-07-26 15:21:08 +02:00
} else {
// Keep it.
newPlanes . push ( plane ) ;
}
} ;
PlanesOrdered = newPlanes ;
}
// Page Title update function
function refreshPageTitle ( ) {
if ( ! PlaneCountInTitle && ! MessageRateInTitle ) {
document . title = PageName ;
return ;
}
var subtitle = "" ;
if ( PlaneCountInTitle ) {
subtitle += TrackedAircraftPositions + '/' + TrackedAircraft ;
}
if ( MessageRateInTitle ) {
if ( subtitle ) subtitle += ' | ' ;
subtitle += MessageRate . toFixed ( 1 ) + '/s' ;
}
document . title = PageName + ' - ' + subtitle ;
}
// Refresh the detail window about the plane
function refreshSelected ( ) {
refreshPageTitle ( ) ;
$ ( '#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 ( ) ;
2019-08-20 16:39:30 +02:00
if ( ! SelectedPlane ) {
2019-07-26 15:21:08 +02:00
return ;
}
2019-08-20 16:39:30 +02:00
const selected = SelectedPlane ;
2019-07-26 15:21:08 +02:00
2019-08-20 16:39:30 +02:00
if ( selected . flight && selected . flight . replace ( / /g , '' ) ) {
2019-07-26 15:21:08 +02:00
$ ( '#selected_callsign' ) . text ( selected . flight ) ;
} else {
$ ( '#selected_callsign' ) . text ( 'n/a' ) ;
}
2019-08-17 21:49:19 +02:00
$ ( '#selected_flightaware_link' ) . html ( getFlightAwareModeSLink ( selected . icao , selected . flight ? selected . flight : selected . registration , "Visit Flight Page" ) ) ;
2019-07-26 15:21:08 +02:00
2019-08-20 16:39:30 +02:00
if ( selected . registration ) {
2019-07-26 15:21:08 +02:00
$ ( '#selected_registration' ) . text ( selected . registration ) ;
} else {
$ ( '#selected_registration' ) . text ( "n/a" ) ;
}
2019-08-20 16:39:30 +02:00
if ( selected . icaoType ) {
2019-08-18 13:26:51 +02:00
$ ( '#selected_icaotype' ) . text ( selected . icaoType ) ;
2019-07-26 15:21:08 +02:00
} else {
$ ( '#selected_icaotype' ) . text ( "n/a" ) ;
}
// 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';
// }
$ ( "#selected_altitude" ) . text ( format _altitude _long ( selected . altitude , selected . vert _rate , DisplayUnits ) ) ;
$ ( '#selected_onground' ) . text ( format _onground ( selected . altitude ) ) ;
if ( selected . squawk === null || selected . squawk === '0000' ) {
$ ( '#selected_squawk' ) . text ( 'n/a' ) ;
} else {
$ ( '#selected_squawk' ) . text ( selected . squawk ) ;
}
$ ( '#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 ) ) ;
$ ( '#selected_icao' ) . text ( selected . icao . toUpperCase ( ) ) ;
2019-08-18 14:07:20 +02:00
$ ( '#selected_pf_info' ) . text ( ( selected . pfRoute ? selected . pfRoute : "" ) + " " + ( selected . pfFlightno ? selected . pfFlightno : "" ) ) ;
2019-07-26 15:21:08 +02:00
$ ( '#airframes_post_icao' ) . attr ( 'value' , selected . icao ) ;
$ ( '#selected_track' ) . text ( format _track _long ( selected . track ) ) ;
if ( selected . seen <= 1 ) {
$ ( '#selected_seen' ) . text ( 'now' ) ;
} else {
$ ( '#selected_seen' ) . text ( selected . seen . toFixed ( 1 ) + 's' ) ;
}
$ ( '#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' ) ;
}
if ( selected . position === null ) {
$ ( '#selected_position' ) . text ( 'n/a' ) ;
$ ( '#selected_follow' ) . addClass ( 'hidden' ) ;
} else {
2019-08-03 20:26:12 +02:00
if ( selected . seen _pos > - 1 ) {
2019-07-26 15:21:08 +02:00
$ ( '#selected_position' ) . text ( format _latlng ( selected . position ) ) ;
} else {
$ ( '#selected_position' ) . text ( format _latlng ( selected . position ) ) ;
}
$ ( '#selected_follow' ) . removeClass ( 'hidden' ) ;
if ( FollowSelected ) {
$ ( '#selected_follow' ) . css ( 'font-weight' , 'bold' ) ;
OLMap . getView ( ) . setCenter ( ol . proj . fromLonLat ( selected . position ) ) ;
} else {
$ ( '#selected_follow' ) . css ( 'font-weight' , 'normal' ) ;
}
}
2019-08-05 08:37:26 +02:00
$ ( '#selected_source' ) . text ( format _data _source ( selected . getDataSource ( ) ) ) ;
2019-07-26 15:21:08 +02:00
$ ( '#selected_category' ) . text ( selected . category ? selected . category : "n/a" ) ;
$ ( '#selected_sitedist' ) . text ( format _distance _long ( selected . sitedist , DisplayUnits ) ) ;
$ ( '#selected_rssi' ) . text ( selected . rssi . toFixed ( 1 ) + ' dBFS' ) ;
$ ( '#selected_message_count' ) . text ( selected . messages ) ;
$ ( '#selected_photo_link' ) . html ( getFlightAwarePhotoLink ( selected . registration ) ) ;
$ ( '#selected_altitude_geom' ) . text ( format _altitude _long ( selected . alt _geom , selected . geom _rate , DisplayUnits ) ) ;
$ ( '#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 ) ) ;
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 ) {
$ ( '#selected_trackrate' ) . text ( 'n/a' ) ;
} else {
$ ( '#selected_trackrate' ) . text ( selected . track _rate . toFixed ( 2 ) ) ;
}
$ ( '#selected_geom_rate' ) . text ( format _vert _rate _long ( selected . geom _rate , DisplayUnits ) ) ;
if ( selected . nav _qnh == null ) {
$ ( '#selected_nav_qnh' ) . text ( "n/a" ) ;
} else {
$ ( '#selected_nav_qnh' ) . text ( selected . nav _qnh . toFixed ( 1 ) + " hPa" ) ;
}
$ ( '#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" ) ;
} else {
$ ( '#selected_nav_modes' ) . text ( selected . nav _modes . join ( ) ) ;
}
if ( selected . nic _baro == null ) {
$ ( '#selected_nic_baro' ) . text ( "n/a" ) ;
} else {
if ( selected . nic _baro == 1 ) {
$ ( '#selected_nic_baro' ) . text ( "cross-checked" ) ;
} else {
$ ( '#selected_nic_baro' ) . text ( "not cross-checked" ) ;
}
}
$ ( '#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" ) ;
} else if ( selected . rc == 0 ) {
$ ( '#selected_rc' ) . text ( "unknown" ) ;
} else {
$ ( '#selected_rc' ) . text ( format _distance _short ( selected . rc , DisplayUnits ) ) ;
}
if ( selected . sil == null || selected . sil _type == null ) {
$ ( '#selected_sil' ) . text ( "n/a" ) ;
} else {
var sampleRate = "" ;
var silDesc = "" ;
if ( selected . sil _type == "perhour" ) {
sampleRate = " per flight hour" ;
} else if ( selected . sil _type == "persample" ) {
sampleRate = " per sample" ;
}
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 ) ;
}
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 ) ;
}
}
function refreshHighlighted ( ) {
// this is following nearly identical logic, etc, as the refreshSelected function, but doing less junk for the highlighted pane
var highlighted = false ;
2019-07-31 09:30:50 +02:00
if ( ! HighlightedPlane || ! ( highlighted = Planes [ HighlightedPlane ] ) ) {
2019-07-26 15:21:08 +02:00
$ ( '#highlighted_infoblock' ) . hide ( ) ;
return ;
}
$ ( '#highlighted_infoblock' ) . show ( ) ;
// 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 ;
2019-07-31 09:30:50 +02:00
var geom ;
var markerCoordinates ;
if ( ! marker || ! ( geom = marker . getGeometry ( ) ) || ! ( markerCoordinates = geom . getCoordinates ( ) ) ) {
$ ( '#highlighted_infoblock' ) . hide ( ) ;
return ;
}
2019-07-26 15:21:08 +02:00
var markerPosition = OLMap . getPixelFromCoordinate ( markerCoordinates ) ;
// Check for overlap
//FIXME TODO: figure out this/remove this check
2019-07-31 09:30:50 +02:00
if ( true || isPointInsideExtent ( markerPosition [ 0 ] , markerPosition [ 1 ] , infoBoxExtent ) ) {
2019-07-26 15:21:08 +02:00
// 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 ) ;
}
}
}
if ( highlighted . flight !== null && highlighted . flight !== "" ) {
$ ( '#highlighted_callsign' ) . text ( highlighted . flight ) ;
} else {
$ ( '#highlighted_callsign' ) . text ( 'n/a' ) ;
}
2019-08-18 13:26:51 +02:00
if ( highlighted . icaoType !== null ) {
$ ( '#highlighted_icaotype' ) . text ( highlighted . icaoType ) ;
2019-07-26 15:21:08 +02:00
} else {
2019-08-18 13:26:51 +02:00
$ ( '#highlighted_icaotype' ) . text ( "n/a" ) ;
2019-07-26 15:21:08 +02:00
}
2019-08-05 08:37:26 +02:00
$ ( '#highlighted_source' ) . text ( format _data _source ( highlighted . getDataSource ( ) ) ) ;
2019-07-26 15:21:08 +02:00
if ( highlighted . registration !== null ) {
$ ( '#highlighted_registration' ) . text ( highlighted . registration ) ;
} else {
$ ( '#highlighted_registration' ) . text ( "n/a" ) ;
}
$ ( '#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 ( ) ) ;
$ ( '#highlighted_rssi' ) . text ( highlighted . rssi . toFixed ( 1 ) + ' dBFS' ) ;
}
2019-07-29 13:45:54 +02:00
function refreshClock ( now _date ) {
var hhmm = now _date . getHours ( ) . toString ( ) . padStart ( 2 , '0' ) + ":" + now _date . getMinutes ( ) . toString ( ) . padStart ( 2 , '0' ) ;
var hms = hhmm + ":" + now _date . getSeconds ( ) . toString ( ) . padStart ( 2 , '0' ) ;
$ ( '#clock_div' ) . text ( hms + " " + now _date . toDateString ( ) ) ;
2019-07-26 15:21:08 +02:00
}
function removeHighlight ( ) {
HighlightedPlane = null ;
refreshHighlighted ( ) ;
}
// Refreshes the larger table of all the planes
function refreshTableInfo ( ) {
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" ;
2019-08-05 08:37:26 +02:00
if ( tableplane . position != null && tableplane . seen _pos < 60 ) {
2019-07-26 15:21:08 +02:00
++ TrackedAircraftPositions ;
}
2019-08-03 20:26:12 +02:00
if ( tableplane . dataSource == "uat" ) {
2019-07-29 19:51:41 +02:00
classes += " uat" ;
2019-08-05 08:37:26 +02:00
} else if ( tableplane . dataSource == "adsb" ) {
2019-07-26 15:21:08 +02:00
classes += " vPosition" ;
2019-08-05 08:37:26 +02:00
} else if ( tableplane . dataSource == "tisb" ) {
2019-07-26 15:21:08 +02:00
classes += " tisb" ;
2019-08-05 08:37:26 +02:00
} else if ( tableplane . dataSource == "mlat" ) {
2019-07-26 15:21:08 +02:00
classes += " mlat" ;
} else {
classes += " other" ;
}
2019-08-08 23:35:58 +02:00
if ( tableplane . selected && ! SelectedAllPlanes )
2019-07-26 15:21:08 +02:00
classes += " selected" ;
if ( tableplane . squawk in SpecialSquawks ) {
classes = classes + " " + SpecialSquawks [ tableplane . squawk ] . cssClass ;
show _squawk _warning = true ;
}
// ICAO doesn't change
2019-07-31 10:58:02 +02:00
if ( tableplane . flight && tableplane . flight _cache != tableplane . flight ) {
2019-07-26 15:21:08 +02:00
tableplane . tr . cells [ 2 ] . innerHTML = getFlightAwareModeSLink ( tableplane . icao , tableplane . flight , tableplane . flight ) ;
2019-07-30 22:45:36 +02:00
tableplane . tr . cells [ 18 ] . innerHTML = getFlightAwareModeSLink ( tableplane . icao , tableplane . flight ) ;
tableplane . flight _cache = tableplane . flight ;
}
tableplane . tr . cells [ 3 ] . textContent = ( tableplane . registration != null ? tableplane . registration : "" ) ;
2019-08-18 13:26:51 +02:00
tableplane . tr . cells [ 4 ] . textContent = ( tableplane . icaoType != null ? tableplane . icaoType : "" ) ;
2019-07-30 22:45:36 +02:00
tableplane . tr . cells [ 5 ] . textContent = ( tableplane . squawk != null ? tableplane . squawk : "" ) ;
tableplane . tr . cells [ 6 ] . textContent = format _altitude _brief ( tableplane . altitude , tableplane . vert _rate , DisplayUnits ) ;
2019-07-26 15:21:08 +02:00
tableplane . tr . cells [ 7 ] . textContent = format _speed _brief ( tableplane . gs , DisplayUnits ) ;
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 ) ;
2019-07-30 22:45:36 +02:00
tableplane . tr . cells [ 13 ] . textContent = ( tableplane . rssi != null ? tableplane . rssi . toFixed ( 1 ) : "" ) ;
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 ) : "" ) ;
2019-07-26 15:21:08 +02:00
tableplane . tr . cells [ 16 ] . textContent = format _data _source ( tableplane . getDataSource ( ) ) ;
2019-08-03 17:28:43 +02:00
if ( false && tableplane . icao _cache !== tableplane . icao ) {
2019-07-30 22:45:36 +02:00
tableplane . tr . cells [ 17 ] . innerHTML = getAirframesModeSLink ( tableplane . icao ) ;
tableplane . icao _cache = tableplane . icao ;
}
2019-08-18 00:04:07 +02:00
tableplane . tr . cells [ 17 ] . textContent = tableplane . baseMarkerKey ;
2019-07-30 22:45:36 +02:00
if ( tableplane . registration _cache !== tableplane . registration ) {
tableplane . tr . cells [ 19 ] . innerHTML = getFlightAwarePhotoLink ( tableplane . registration ) ;
tableplane . registration _cache = tableplane . registration ;
2019-07-31 10:58:02 +02:00
if ( ! tableplane . flight ) {
var label = tableplane . registration != null ? tableplane . registration : tableplane . icao . toUpperCase ( ) ;
2019-08-17 21:49:19 +02:00
tableplane . tr . cells [ 2 ] . innerHTML = getFlightAwareModeSLink ( tableplane . icao , tableplane . registration , label ) ;
tableplane . tr . cells [ 18 ] . innerHTML = getFlightAwareModeSLink ( tableplane . icao , tableplane . registration ) ;
2019-07-31 10:58:02 +02:00
}
2019-07-30 22:45:36 +02:00
}
2019-07-26 15:21:08 +02:00
tableplane . tr . className = classes ;
}
}
if ( show _squawk _warning ) {
$ ( "#SpecialSquawkWarning" ) . css ( 'display' , 'block' ) ;
} else {
$ ( "#SpecialSquawkWarning" ) . css ( 'display' , 'none' ) ;
}
resortTable ( ) ;
}
//
// ---- table sorting ----
//
function compareAlpha ( xa , ya ) {
if ( xa === ya )
return 0 ;
if ( xa < ya )
return - 1 ;
return 1 ;
}
2019-08-16 22:15:30 +02:00
function compareBeta ( xa , ya ) {
if ( xa === ya )
return 0 ;
if ( sortAscending && xa < ya )
return - 1 ;
if ( ! sortAscending && ( xa . replace ( / /g , "" ) . split ( "" ) . reverse ( ) . join ( "" ) > ya . replace ( / /g , "" ) . split ( "" ) . reverse ( ) . join ( "" ) ) )
return - 1 ;
return 1 ;
}
2019-07-26 15:21:08 +02:00
function compareNumeric ( xf , yf ) {
if ( Math . abs ( xf - yf ) < 1e-9 )
return 0 ;
return xf - yf ;
}
function sortByICAO ( ) { sortBy ( 'icao' , compareAlpha , function ( x ) { return x . icao ; } ) ; }
2019-08-16 22:15:30 +02:00
function sortByFlight ( ) { sortBy ( 'flight' , compareBeta , function ( x ) { return x . flight ? x . flight : x . registration ; } ) ; }
2019-07-26 15:21:08 +02:00
function sortByRegistration ( ) { sortBy ( 'registration' , compareAlpha , function ( x ) { return x . registration ; } ) ; }
2019-08-18 13:26:51 +02:00
function sortByAircraftType ( ) { sortBy ( 'icaoType' , compareAlpha , function ( x ) { return x . icaoType ; } ) ; }
2019-07-26 15:21:08 +02: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 ) ; } ) ; }
function sortBySpeed ( ) { sortBy ( 'speed' , compareNumeric , function ( x ) { return x . gs ; } ) ; }
function sortByVerticalRate ( ) { sortBy ( 'vert_rate' , compareNumeric , function ( x ) { return x . vert _rate ; } ) ; }
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 ; } ) ; }
function sortByCountry ( ) { sortBy ( 'country' , compareAlpha , function ( x ) { return x . icaorange . country ; } ) ; }
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 ) } ) ; }
2019-07-31 20:18:44 +02:00
function sortByDataSource ( ) { sortBy ( 'data_source' , compareNumeric , function ( x ) { return x . getDataSourceNumber ( ) } ) ; }
2019-08-18 00:04:07 +02:00
function sortByBaseMarkerKey ( ) { sortBy ( 'base_marker_key' , compareAlpha , function ( x ) { return x . baseMarkerKey ; } ) ; }
2019-07-26 15:21:08 +02:00
var sortId = '' ;
var sortCompare = null ;
var sortExtract = null ;
var sortAscending = true ;
function sortFunction ( x , y ) {
var xv = x . _sort _value ;
var yv = y . _sort _value ;
// always sort missing values at the end, regardless of
// ascending/descending sort
if ( xv == null && yv == null ) return x . _sort _pos - y . _sort _pos ;
if ( xv == null ) return 1 ;
if ( yv == null ) return - 1 ;
var c = sortAscending ? sortCompare ( xv , yv ) : sortCompare ( yv , xv ) ;
if ( c !== 0 ) return c ;
return x . _sort _pos - y . _sort _pos ;
}
function resortTable ( ) {
2019-08-05 13:26:22 +02:00
// presort by dataSource
if ( sortId == "sitedist" ) {
PlanesOrdered . sort ( function ( x , y ) {
return ( x . getDataSourceNumber ( ) - y . getDataSourceNumber ( ) ) ;
} ) ;
}
// or distance
if ( sortId == "data_source" ) {
PlanesOrdered . sort ( function ( x , y ) {
return ( x . sitedist - y . sitedist ) ;
} ) ;
}
2019-07-26 15:21:08 +02:00
// number the existing rows so we can do a stable sort
// regardless of whether sort() is stable or not.
// Also extract the sort comparison value.
for ( var i = 0 ; i < PlanesOrdered . length ; ++ i ) {
PlanesOrdered [ i ] . _sort _pos = i ;
PlanesOrdered [ i ] . _sort _value = sortExtract ( PlanesOrdered [ i ] ) ;
}
PlanesOrdered . sort ( sortFunction ) ;
var tbody = document . getElementById ( 'tableinfo' ) . tBodies [ 0 ] ;
2019-08-03 17:28:43 +02:00
fragment = document . createDocumentFragment ( ) ;
2019-07-26 15:21:08 +02:00
for ( var i = 0 ; i < PlanesOrdered . length ; ++ i ) {
2019-07-30 22:45:36 +02:00
fragment . appendChild ( PlanesOrdered [ i ] . tr ) ;
2019-07-26 15:21:08 +02:00
}
2019-07-30 22:45:36 +02:00
tbody . appendChild ( fragment ) ;
2019-07-26 15:21:08 +02:00
}
function sortBy ( id , sc , se ) {
2019-08-05 13:26:22 +02:00
if ( id != 'data_source' && grouptype _checkbox ) {
2019-07-26 15:21:08 +02:00
$ ( '#grouptype_checkbox' ) . removeClass ( 'settingsCheckboxChecked' ) ;
2019-08-05 13:26:22 +02:00
grouptype _checkbox = false ;
} else if ( id == 'data_source' && ! grouptype _checkbox ) {
2019-07-26 15:21:08 +02:00
$ ( '#grouptype_checkbox' ) . addClass ( 'settingsCheckboxChecked' ) ;
2019-08-05 13:26:22 +02:00
grouptype _checkbox = true ;
2019-07-26 15:21:08 +02:00
}
if ( id === sortId ) {
sortAscending = ! sortAscending ;
PlanesOrdered . reverse ( ) ; // this correctly flips the order of rows that compare equal
} else {
sortAscending = true ;
}
sortId = id ;
sortCompare = sc ;
sortExtract = se ;
resortTable ( ) ;
}
function selectPlaneByHex ( hex , autofollow ) {
//console.log("select: " + hex);
// If SelectedPlane has something in it, clear out the selected
if ( SelectedAllPlanes ) {
deselectAllPlanes ( ) ;
}
2019-08-08 18:23:51 +02:00
// already selected plane
2019-08-20 16:39:30 +02:00
var oldPlane = SelectedPlane ;
2019-08-08 18:23:51 +02:00
// plane to be selected
var newPlane = Planes [ hex ] ;
if ( ! multiSelect && oldPlane ) {
oldPlane . selected = false ;
oldPlane . clearLines ( ) ;
oldPlane . updateMarker ( ) ;
$ ( oldPlane . tr ) . removeClass ( "selected" ) ;
2019-07-26 15:21:08 +02:00
// scroll the infoblock back to the top for the next plane to be selected
2019-08-08 18:23:51 +02:00
//$('.infoblock-container').scrollTop(0);
}
// multiSelect deselect
if ( multiSelect && newPlane . selected && ! autofollow ) {
newPlane . selected = false ;
newPlane . clearLines ( ) ;
newPlane . updateMarker ( ) ;
$ ( newPlane . tr ) . removeClass ( "selected" ) ;
newPlane = null ;
2019-07-26 15:21:08 +02:00
}
// If we are clicking the same plane, we are deselecting it.
// (unless it was a doubleclick..)
2019-08-08 18:23:51 +02:00
if ( oldPlane == newPlane && ! autofollow ) {
newPlane = null ;
2019-07-26 15:21:08 +02:00
}
2019-08-08 18:23:51 +02:00
if ( newPlane ) {
2019-07-26 15:21:08 +02:00
// Assign the new selected
2019-08-20 16:39:30 +02:00
SelectedPlane = newPlane ;
2019-08-08 18:23:51 +02:00
newPlane . selected = true ;
newPlane . updateLines ( ) ;
newPlane . updateMarker ( ) ;
$ ( newPlane . tr ) . addClass ( "selected" ) ;
newPlane . logSel ( newPlane . history _size ) ;
2019-08-20 16:39:30 +02:00
//console.log(newPlane.baseMarkerKey);
2019-08-08 18:23:51 +02:00
} else {
2019-07-26 15:21:08 +02:00
SelectedPlane = null ;
}
2019-08-08 18:23:51 +02:00
if ( newPlane && autofollow ) {
2019-07-26 15:21:08 +02:00
FollowSelected = true ;
if ( OLMap . getView ( ) . getZoom ( ) < 8 )
OLMap . getView ( ) . setZoom ( 8 ) ;
} else {
FollowSelected = false ;
2019-08-08 18:23:51 +02:00
}
2019-07-26 15:21:08 +02:00
refreshSelected ( ) ;
refreshHighlighted ( ) ;
}
function highlightPlaneByHex ( hex ) {
if ( hex != null ) {
HighlightedPlane = hex ;
}
}
// loop through the planes and mark them as selected to show the paths for all planes
function selectAllPlanes ( ) {
HighlightedPlane = null ;
// 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 ) {
2019-08-20 16:39:30 +02:00
SelectedPlane . selected = false ;
SelectedPlane . clearLines ( ) ;
SelectedPlane . updateMarker ( ) ;
$ ( SelectedPlane . tr ) . removeClass ( "selected" ) ;
2019-07-26 15:21:08 +02:00
}
SelectedPlane = null ;
SelectedAllPlanes = true ;
for ( var key in Planes ) {
if ( Planes [ key ] . visible && ! Planes [ key ] . isFiltered ( ) ) {
Planes [ key ] . selected = true ;
Planes [ key ] . updateLines ( ) ;
Planes [ key ] . updateMarker ( ) ;
}
}
}
$ ( '#selectall_checkbox' ) . addClass ( 'settingsCheckboxChecked' ) ;
refreshSelected ( ) ;
refreshHighlighted ( ) ;
}
// on refreshes, try to find new planes and mark them as selected
function selectNewPlanes ( ) {
if ( SelectedAllPlanes ) {
2019-08-19 20:02:05 +02:00
for ( var key in PlanesOrdered ) {
if ( ! PlanesOrdered [ key ] . visible || PlanesOrdered [ key ] . isFiltered ( ) ) {
if ( PlanesOrdered [ key ] . selected ) {
PlanesOrdered [ key ] . selected = false ;
PlanesOrdered [ key ] . clearLines ( ) ;
2019-07-26 15:21:08 +02:00
}
2019-08-19 20:02:05 +02:00
} else if ( PlanesOrdered [ key ] . selected !== true ) {
PlanesOrdered [ key ] . selected = true ;
PlanesOrdered [ key ] . updateLines ( ) ;
2019-07-26 15:21:08 +02:00
}
}
}
}
// 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" ) ;
}
$ ( '#selectall_checkbox' ) . removeClass ( 'settingsCheckboxChecked' ) ;
SelectedPlane = null ;
SelectedAllPlanes = false ;
refreshSelected ( ) ;
refreshHighlighted ( ) ;
}
function toggleFollowSelected ( ) {
FollowSelected = ! FollowSelected ;
if ( FollowSelected && OLMap . getView ( ) . getZoom ( ) < 8 )
OLMap . getView ( ) . setZoom ( 8 ) ;
refreshSelected ( ) ;
}
function resetMap ( ) {
// Reset localStorage values and map settings
localStorage [ 'CenterLat' ] = CenterLat = DefaultCenterLat ;
localStorage [ 'CenterLon' ] = CenterLon = DefaultCenterLon ;
localStorage [ 'ZoomLvl' ] = ZoomLvl = DefaultZoomLvl ;
// Set and refresh
OLMap . getView ( ) . setZoom ( ZoomLvl ) ;
OLMap . getView ( ) . setCenter ( ol . proj . fromLonLat ( [ CenterLon , CenterLat ] ) ) ;
selectPlaneByHex ( null , false ) ;
}
function updateMapSize ( ) {
OLMap . updateSize ( ) ;
}
function toggleSidebarVisibility ( e ) {
e . preventDefault ( ) ;
$ ( "#sidebar_container" ) . toggle ( ) ;
$ ( "#expand_sidebar_control" ) . toggle ( ) ;
$ ( "#toggle_sidebar_button" ) . toggleClass ( "show_sidebar" ) ;
$ ( "#toggle_sidebar_button" ) . toggleClass ( "hide_sidebar" ) ;
updateMapSize ( ) ;
}
function expandSidebar ( e ) {
e . preventDefault ( ) ;
$ ( "#map_container" ) . hide ( )
$ ( "#toggle_sidebar_control" ) . hide ( ) ;
$ ( "#splitter" ) . hide ( ) ;
$ ( "#sudo_buttons" ) . hide ( ) ;
$ ( "#show_map_button" ) . show ( ) ;
$ ( "#sidebar_container" ) . width ( "100%" ) ;
setColumnVisibility ( ) ;
setSelectedInfoBlockVisibility ( ) ;
updateMapSize ( ) ;
}
function showMap ( ) {
$ ( "#map_container" ) . show ( )
$ ( "#toggle_sidebar_control" ) . show ( ) ;
$ ( "#splitter" ) . show ( ) ;
$ ( "#sudo_buttons" ) . show ( ) ;
$ ( "#show_map_button" ) . hide ( ) ;
$ ( "#sidebar_container" ) . width ( "470px" ) ;
setColumnVisibility ( ) ;
setSelectedInfoBlockVisibility ( ) ;
updateMapSize ( ) ;
}
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 ( ) ;
}
}
}
function setColumnVisibility ( ) {
var mapIsVisible = $ ( "#map_container" ) . is ( ":visible" ) ;
var infoTable = $ ( "#tableinfo" ) ;
showColumn ( infoTable , "#registration" , ! mapIsVisible ) ;
showColumn ( infoTable , "#aircraft_type" , ! mapIsVisible ) ;
showColumn ( infoTable , "#vert_rate" , ! mapIsVisible ) ;
showColumn ( infoTable , "#track" , ! mapIsVisible ) ;
showColumn ( infoTable , "#lat" , ! mapIsVisible ) ;
showColumn ( infoTable , "#lon" , ! mapIsVisible ) ;
showColumn ( infoTable , "#data_source" , ! mapIsVisible ) ;
2019-08-18 00:04:07 +02:00
showColumn ( infoTable , "#base_marker_key" , ! mapIsVisible ) ;
2019-07-26 15:21:08 +02:00
showColumn ( infoTable , "#flightaware_mode_s_link" , ! mapIsVisible ) ;
showColumn ( infoTable , "#flightaware_photo_link" , ! mapIsVisible ) ;
}
function setSelectedInfoBlockVisibility ( ) {
var mapIsVisible = $ ( "#map_container" ) . is ( ":visible" ) ;
2019-08-20 16:39:30 +02:00
if ( SelectedPlane && mapIsVisible ) {
2019-07-26 15:21:08 +02:00
$ ( '#selected_infoblock' ) . show ( ) ;
2019-08-12 18:09:58 +02:00
$ ( '#sidebar_canvas' ) . css ( 'margin-bottom' , $ ( '#selected_infoblock' ) . height ( ) + 'px' ) ;
2019-07-26 15:21:08 +02:00
}
else {
$ ( '#selected_infoblock' ) . hide ( ) ;
2019-08-12 18:09:58 +02:00
$ ( '#sidebar_canvas' ) . css ( 'margin-bottom' , 0 ) ;
2019-07-26 15:21:08 +02:00
}
}
// Reposition selected plane info box if it overlaps plane marker
function adjustSelectedInfoBlockPosition ( ) {
2019-08-20 16:39:30 +02:00
return ; // this function is probably obsolete
if ( ! SelectedPlane || ! SelectedPlane . marker ) {
2019-07-26 15:21:08 +02:00
return ;
}
2019-08-20 16:39:30 +02:00
// Get marker position
var marker = SelectedPlane . marker ;
var markerCoordinates = SelectedPlane . marker . getGeometry ( ) . getCoordinates ( ) ;
var markerPosition = OLMap . getPixelFromCoordinate ( markerCoordinates ) ;
2019-07-26 15:21:08 +02:00
2019-08-20 16:39:30 +02:00
// Get map size
var mapCanvas = $ ( '#map_canvas' ) ;
var mapExtent = getExtent ( 0 , 0 , mapCanvas . width ( ) , mapCanvas . height ( ) ) ;
2019-07-26 15:21:08 +02:00
2019-08-20 16:39:30 +02:00
// Check for overlap
if ( isPointInsideExtent ( markerPosition [ 0 ] , markerPosition [ 1 ] , infoBoxExtent ) ) {
// Array of possible new positions for info box
var candidatePositions = [ ] ;
candidatePositions . push ( { x : 40 , y : 60 } ) ;
candidatePositions . push ( { x : 40 , y : markerPosition [ 1 ] + 80 } ) ;
2019-07-26 15:21:08 +02:00
2019-08-20 16:39:30 +02:00
// 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 ) ;
return ;
2019-07-26 15:21:08 +02:00
}
}
2019-08-20 16:39:30 +02:00
}
2019-07-26 15:21:08 +02:00
}
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 ;
}
function initializeUnitsSelector ( ) {
// Get display unit preferences from local storage
if ( ! localStorage . getItem ( 'displayUnits' ) ) {
localStorage [ 'displayUnits' ] = "nautical" ;
}
var displayUnits = localStorage [ 'displayUnits' ] ;
DisplayUnits = displayUnits ;
setAltitudeLegend ( displayUnits ) ;
// Initialize drop-down
var unitsSelector = $ ( "#units_selector" ) ;
unitsSelector . val ( displayUnits ) ;
unitsSelector . on ( "change" , onDisplayUnitsChanged ) ;
}
function onDisplayUnitsChanged ( e ) {
var displayUnits = e . target . value ;
// Save display units to local storage
localStorage [ 'displayUnits' ] = displayUnits ;
DisplayUnits = displayUnits ;
setAltitudeLegend ( displayUnits ) ;
// Update filters
updatePlaneFilter ( ) ;
// Refresh data
refreshSelected ( ) ;
refreshHighlighted ( ) ;
2019-08-19 20:02:05 +02:00
refreshTableInfo ( ) ;
2019-07-26 15:21:08 +02:00
// Redraw range rings
if ( SitePosition !== null && SitePosition !== undefined && SiteCircles ) {
createSiteCircleFeatures ( ) ;
}
// Reset map scale line units
OLMap . getControls ( ) . forEach ( function ( control ) {
if ( control instanceof ol . control . ScaleLine ) {
control . setUnits ( displayUnits ) ;
}
} ) ;
}
function setAltitudeLegend ( units ) {
if ( units === 'metric' ) {
$ ( '#altitude_chart_button' ) . addClass ( 'altitudeMeters' ) ;
} else {
$ ( '#altitude_chart_button' ) . removeClass ( 'altitudeMeters' ) ;
}
}
function onFilterByAltitude ( e ) {
e . preventDefault ( ) ;
2019-07-31 18:14:04 +02:00
2019-07-26 15:21:08 +02:00
updatePlaneFilter ( ) ;
refreshTableInfo ( ) ;
2019-08-20 16:39:30 +02:00
if ( SelectedPlane && SelectedPlane . isFiltered ( ) ) {
SelectedPlane . selected = false ;
SelectedPlane . clearLines ( ) ;
SelectedPlane . updateMarker ( ) ;
2019-07-26 15:21:08 +02:00
SelectedPlane = null ;
refreshSelected ( ) ;
refreshHighlighted ( ) ;
}
}
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 ;
}
2019-08-04 17:08:39 +02:00
function toggleDebugAll ( ) {
if ( localStorage [ 'debugAll' ] === "true" ) {
debugAll = false ;
localStorage [ 'debugAll' ] = "false" ;
$ ( '#debugAll_checkbox' ) . removeClass ( 'settingsCheckboxChecked' ) ;
} else {
debugAll = true ;
localStorage [ 'debugAll' ] = "true" ;
$ ( '#debugAll_checkbox' ) . addClass ( 'settingsCheckboxChecked' ) ;
}
}
2019-08-04 16:46:55 +02:00
function toggleDebug ( ) {
if ( localStorage [ 'debug' ] === "true" ) {
debug = false ;
localStorage [ 'debug' ] = "false" ;
$ ( '#debug_checkbox' ) . removeClass ( 'settingsCheckboxChecked' ) ;
} else {
debug = true ;
localStorage [ 'debug' ] = "true" ;
$ ( '#debug_checkbox' ) . addClass ( 'settingsCheckboxChecked' ) ;
}
2019-08-05 18:05:33 +02:00
for ( var i in PlanesOrdered ) {
2019-08-05 18:56:41 +02:00
PlanesOrdered [ i ] . remakeTrail ( ) ;
2019-08-05 18:05:33 +02:00
}
2019-08-04 16:46:55 +02:00
}
2019-08-19 18:13:58 +02:00
function dim ( evt ) {
const dim = 0.3 ;
const contrast = 0.1 ;
evt . context . globalCompositeOperation = 'multiply' ;
if ( evt . context . globalCompositeOperation == 'multiply' ) {
evt . context . fillStyle = 'rgba(0,0,0,' + dim + ')' ;
evt . context . fillRect ( 0 , 0 , evt . context . canvas . width , evt . context . canvas . height ) ;
}
evt . context . globalCompositeOperation = 'overlay' ;
if ( evt . context . globalCompositeOperation == 'overlay' ) {
evt . context . fillStyle = 'rgba(0,0,0,' + contrast + ')' ;
evt . context . fillRect ( 0 , 0 , evt . context . canvas . width , evt . context . canvas . height ) ;
}
evt . context . globalCompositeOperation = 'source-over' ;
}
function toggleMapDim ( ) {
const maps = layers [ 0 ] . getLayersArray ( ) ;
if ( localStorage [ 'MapDim' ] === "true" ) {
localStorage [ 'MapDim' ] = "false" ;
for ( const i in maps ) {
ol . Observable . unByKey ( maps [ i ] . dimKey ) ;
}
$ ( '#mapdim_checkbox' ) . removeClass ( 'settingsCheckboxChecked' ) ;
} else {
localStorage [ 'MapDim' ] = "true" ;
for ( const i in maps ) {
maps [ i ] . dimKey = maps [ i ] . on ( 'postcompose' , dim ) ;
}
$ ( '#mapdim_checkbox' ) . addClass ( 'settingsCheckboxChecked' ) ;
}
2019-08-20 14:30:26 +02:00
OLMap . render ( ) ;
2019-08-19 18:13:58 +02:00
}
2019-07-26 15:21:08 +02:00
function toggleAltitudeChart ( switchToggle ) {
if ( typeof localStorage [ 'altitudeChart' ] === 'undefined' ) {
localStorage [ 'altitudeChart' ] = 'show' ;
}
var altitudeChartDisplay = localStorage [ 'altitudeChart' ] ;
if ( switchToggle === true ) {
altitudeChartDisplay = ( altitudeChartDisplay === 'show' ) ? 'hidden' : 'show' ;
}
// if you're using custom colors always hide the chart
if ( customAltitudeColors === true ) {
altitudeChartDisplay = 'hidden' ;
// also hide the control option
$ ( '#altitude_chart_container' ) . hide ( ) ;
}
if ( altitudeChartDisplay === 'show' ) {
$ ( '#altitude_checkbox' ) . addClass ( 'settingsCheckboxChecked' ) ;
$ ( '#altitude_chart' ) . show ( ) ;
} else {
$ ( '#altitude_checkbox' ) . removeClass ( 'settingsCheckboxChecked' ) ;
$ ( '#altitude_chart' ) . hide ( ) ;
}
localStorage [ 'altitudeChart' ] = altitudeChartDisplay ;
}
2019-07-30 19:59:17 +02:00
function followRandomPlane ( ) {
var this _one = null ;
do {
this _one = PlanesOrdered [ Math . floor ( Math . random ( ) * PlanesOrdered . length ) ] ;
2019-08-06 21:49:57 +02:00
} while ( this _one . isFiltered ( ) || ! this _one . position || ( now - this _one . position _time > 30 ) ) ;
2019-07-30 19:59:17 +02:00
//console.log(this_one.icao);
selectPlaneByHex ( this _one . icao , true ) ;
}
2019-08-08 18:23:51 +02:00
function toggleMultiSelect ( ) {
if ( multiSelect ) {
multiSelect = false ;
deselectAllPlanes ( ) ;
} else {
multiSelect = true ;
}
}
2019-07-30 19:59:17 +02:00
2019-07-26 15:21:08 +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 ( ) ) ;
2019-07-31 18:14:04 +02:00
if ( minAltitude < - 1e6 || minAltitude > 1e6 || isNaN ( minAltitude ) )
minAltitude = - 1e6 ;
if ( maxAltitude < - 1e6 || maxAltitude > 1e6 || isNaN ( maxAltitude ) )
maxAltitude = 1e6 ;
2019-07-26 15:21:08 +02:00
PlaneFilter . minAltitude = minAltitude ;
PlaneFilter . maxAltitude = maxAltitude ;
PlaneFilter . altitudeUnits = DisplayUnits ;
}
function getFlightAwareIdentLink ( ident , linkText ) {
if ( ident !== null && ident !== "" ) {
if ( ! linkText ) {
linkText = ident ;
}
return "<a target=\"_blank\" href=\"https://flightaware.com/live/flight/" + ident . trim ( ) + "\">" + linkText + "</a>" ;
}
return "" ;
}
function getFlightAwareModeSLink ( code , ident , linkText ) {
if ( code !== null && code . length > 0 && code [ 0 ] !== '~' && code !== "000000" ) {
if ( ! linkText ) {
linkText = "FlightAware: " + code . toUpperCase ( ) ;
}
var linkHtml = "<a target=\"_blank\" href=\"https://flightaware.com/live/modes/" + code ;
2019-07-31 10:58:02 +02:00
if ( ident != null && ident !== "" ) {
2019-07-26 15:21:08 +02:00
linkHtml += "/ident/" + ident . trim ( ) ;
}
linkHtml += "/redirect\">" + linkText + "</a>" ;
return linkHtml ;
}
return "" ;
}
function getFlightAwarePhotoLink ( registration ) {
if ( registration !== null && registration !== "" ) {
return "<a target=\"_blank\" href=\"https://flightaware.com/photos/aircraft/" + registration . replace ( /[^0-9a-z]/ig , '' ) + "\">See Photos</a>" ;
}
return "" ;
}
function getAirframesModeSLink ( code ) {
if ( code !== null && code . length > 0 && code [ 0 ] !== '~' && code !== "000000" ) {
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>" ;
}
return "" ;
}
// 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
ol . control . LayerSwitcher . forEachRecursive ( layers , function ( lyr ) {
if ( lyr . get ( 'name' ) === layer && lyr . getVisible ( ) ) {
$ ( element ) . addClass ( 'settingsCheckboxChecked' ) ;
}
} ) ;
$ ( element ) . on ( 'click' , function ( ) {
var visible = false ;
if ( $ ( element ) . hasClass ( 'settingsCheckboxChecked' ) ) {
visible = true ;
}
ol . control . LayerSwitcher . forEachRecursive ( layers , function ( lyr ) {
if ( lyr . get ( 'name' ) === layer ) {
if ( visible ) {
lyr . setVisible ( false ) ;
$ ( element ) . removeClass ( 'settingsCheckboxChecked' ) ;
} else {
lyr . setVisible ( true ) ;
$ ( element ) . addClass ( 'settingsCheckboxChecked' ) ;
}
}
} ) ;
} ) ;
}
// check status.json if it has a serial number for a flightfeeder
function flightFeederCheck ( ) {
$ . ajax ( '/status.json' , {
success : function ( data ) {
if ( data . type === "flightfeeder" ) {
isFlightFeeder = true ;
updatePiAwareOrFlightFeeder ( ) ;
}
}
} )
}
// updates the page to replace piaware with flightfeeder references
function updatePiAwareOrFlightFeeder ( ) {
if ( isFlightFeeder ) {
$ ( '.piAwareLogo' ) . hide ( ) ;
$ ( '.flightfeederLogo' ) . show ( ) ;
2019-07-29 13:45:54 +02:00
PageName = 'FlightFeeder SkyAware' ;
2019-07-26 15:21:08 +02:00
} else {
$ ( '.flightfeederLogo' ) . hide ( ) ;
$ ( '.piAwareLogo' ) . show ( ) ;
2019-07-29 13:45:54 +02:00
PageName = 'PiAware SkyAware' ;
2019-07-26 15:21:08 +02:00
}
refreshPageTitle ( ) ;
}
2019-08-18 13:26:51 +02:00
function fetchPfData ( ) {
2019-08-19 00:35:49 +02:00
for ( const i in pf _data ) {
const req = $ . ajax ( { url : pf _data [ i ] ,
2019-08-18 13:26:51 +02:00
timeout : 3000 ,
cache : false ,
2019-08-19 00:35:49 +02:00
dataType : 'json' } ) ;
$ . when ( req ) . done ( function ( data ) {
2019-08-18 13:26:51 +02:00
for ( const i in PlanesOrdered ) {
const plane = PlanesOrdered [ i ] ;
const ac = data . aircraft [ plane . icao . toUpperCase ( ) ] ;
if ( ! ac ) {
continue ;
}
plane . pfRoute = ac . route ;
plane . pfMach = ac . mach ;
plane . pfFlightno = ac . flightno ;
2019-08-18 14:07:20 +02:00
if ( ac . reg && ac . reg != "????" && ac . reg != "z.NO-REG" )
2019-08-18 13:26:51 +02:00
plane . registration = ac . reg ;
if ( ac . type && ac . type != "????" )
plane . icaoType = ac . type ;
if ( plane . icaoType != plane . icaoTypeCache ) {
var typeData = _aircraft _type _cache [ plane . icaoType ] ;
if ( typeData ) {
plane . typeDescription = typeData . desc ;
plane . wtc = typeData . wtc ;
}
2019-08-20 16:39:30 +02:00
//console.log(plane.icao +" "+ plane.flight + " was " + plane.icaoTypeCache + " and is now " + plane.icaoType + " " + plane.typeDescription + "-" + plane.wtc);
2019-08-18 13:26:51 +02:00
//console.log(plane.flight);
plane . icaoTypeCache = plane . icaoType ;
}
}
} ) ;
2019-08-19 00:35:49 +02:00
}
2019-08-18 13:26:51 +02:00
}