2017-12-28 07:20:34 +08:00
/ * *
*
* @ type { { render _airspace _map , render _live _map , render _route _map } }
* /
2017-12-27 05:26:12 +08:00
const phpvms = ( function ( ) {
2017-12-20 05:19:06 +08:00
2017-12-28 10:52:37 +08:00
const PLAN _ROUTE _COLOR = '#36b123' ;
const ACTUAL _ROUTE _COLOR = '#172aea' ;
2017-12-20 07:30:30 +08:00
const draw _base _map = ( opts ) => {
2017-12-20 05:19:06 +08:00
2017-12-21 01:28:21 +08:00
opts = _ . defaults ( opts , {
render _elem : 'map' ,
zoom : 12 ,
layers : [ ] ,
set _marker : false ,
} ) ;
2017-12-28 06:47:22 +08:00
let feature _groups = [ ] ;
2017-12-20 07:30:30 +08:00
/ * v a r o p e n a i p _ a i r s p a c e _ l a b e l s = n e w L . T i l e L a y e r . W M S (
"http://{s}.tile.maps.openaip.net/geowebcache/service/wms" , {
maxZoom : 14 ,
minZoom : 12 ,
layers : 'openaip_approved_airspaces_labels' ,
tileSize : 1024 ,
detectRetina : true ,
subdomains : '12' ,
format : 'image/png' ,
transparent : true
} ) ;
2017-12-20 05:19:06 +08:00
2017-12-20 07:30:30 +08:00
openaip _airspace _labels . addTo ( map ) ; * /
2017-12-20 05:19:06 +08:00
2017-12-20 07:30:30 +08:00
const opencyclemap _phys _osm = new L . TileLayer (
'http://{s}.tile.thunderforest.com/landscape/{z}/{x}/{y}.png?apikey=f09a38fa87514de4890fc96e7fe8ecb1' , {
maxZoom : 14 ,
minZoom : 4 ,
format : 'image/png' ,
transparent : true
} ) ;
2017-12-20 05:19:06 +08:00
2017-12-28 06:47:22 +08:00
feature _groups . push ( opencyclemap _phys _osm ) ;
/*const openaip_cached_basemap = new L.TileLayer("http:/ / { s } . tile . maps . openaip . net / geowebcache / service / tms / 1.0 . 0 / openaip _basemap @ EPSG % 3 A900913 @ png / { z } / { x } / { y } . png " , {
2017-12-20 05:19:06 +08:00
maxZoom : 14 ,
2017-12-20 07:30:30 +08:00
minZoom : 4 ,
tms : true ,
2017-12-20 05:19:06 +08:00
detectRetina : true ,
subdomains : '12' ,
format : 'image/png' ,
transparent : true
} ) ;
2017-12-28 06:47:22 +08:00
feature _groups . push ( openaip _cached _basemap ) ;
* /
const openaip _basemap _phys _osm = L . featureGroup ( feature _groups ) ;
2017-12-20 05:19:06 +08:00
2017-12-20 07:30:30 +08:00
let map = L . map ( 'map' , {
layers : [ openaip _basemap _phys _osm ] ,
zoom : opts . zoom ,
scrollWheelZoom : false ,
2017-12-20 05:19:06 +08:00
} ) ;
2017-12-20 07:30:30 +08:00
const attrib = L . control . attribution ( { position : 'bottomleft' } ) ;
attrib . addAttribution ( "<a href=\"https://www.thunderforest.com\" target=\"_blank\" style=\"\">Thunderforest</a>" ) ;
attrib . addAttribution ( "<a href=\"https://www.openaip.net\" target=\"_blank\" style=\"\">openAIP</a>" ) ;
attrib . addAttribution ( "<a href=\"https://www.openstreetmap.org/copyright\" target=\"_blank\" style=\"\">OpenStreetMap</a> contributors" ) ;
attrib . addAttribution ( "<a href=\"https://www.openweathermap.org\" target=\"_blank\" style=\"\">OpenWeatherMap</a>" ) ;
attrib . addTo ( map ) ;
return map ;
2017-12-21 01:28:21 +08:00
} ;
2017-12-20 07:30:30 +08:00
2017-12-25 07:38:38 +08:00
/ * *
* Show some popup text when a feature is clicked on
* @ param feature
* @ param layer
* /
const onFeaturePointClick = ( feature , layer ) => {
let popup _html = "" ;
if ( feature . properties && feature . properties . popup ) {
popup _html += feature . properties . popup ;
}
layer . bindPopup ( popup _html ) ;
} ;
2017-12-28 06:47:22 +08:00
/ * *
* Show each point as a marker
* @ param feature
* @ param latlng
* @ returns { * }
* /
const pointToLayer = ( feature , latlng ) => {
2017-12-27 05:26:12 +08:00
return L . circleMarker ( latlng , {
radius : 12 ,
fillColor : "#ff7800" ,
color : "#000" ,
weight : 1 ,
opacity : 1 ,
fillOpacity : 0.8
} ) ;
} ;
2017-12-28 00:17:11 +08:00
/ * *
*
* @ param opts
* @ private
* /
const _render _route _map = ( opts ) => {
2017-12-20 07:30:30 +08:00
2017-12-28 00:17:11 +08:00
opts = _ . defaults ( opts , {
route _points : null ,
planned _route _line : null ,
actual _route _points : null ,
actual _route _line : null ,
render _elem : 'map' ,
} ) ;
let map = draw _base _map ( opts ) ;
let geodesicLayer = L . geodesic ( [ ] , {
weight : 7 ,
opacity : 0.9 ,
2017-12-28 10:52:37 +08:00
color : PLAN _ROUTE _COLOR ,
2017-12-28 00:17:11 +08:00
steps : 50 ,
wrap : false ,
} ) . addTo ( map ) ;
geodesicLayer . geoJson ( opts . planned _route _line ) ;
map . fitBounds ( geodesicLayer . getBounds ( ) ) ;
// Draw the route points after
if ( opts . route _points !== null ) {
let route _points = L . geoJSON ( opts . route _points , {
onEachFeature : onFeaturePointClick ,
pointToLayer : pointToLayer ,
style : {
2017-12-28 10:52:37 +08:00
"color" : PLAN _ROUTE _COLOR ,
2017-12-28 00:17:11 +08:00
"weight" : 5 ,
"opacity" : 0.65 ,
} ,
2017-12-20 07:30:30 +08:00
} ) ;
2017-12-21 01:28:21 +08:00
2017-12-28 00:17:11 +08:00
route _points . addTo ( map ) ;
}
2017-12-20 07:30:30 +08:00
/ * *
2017-12-28 00:17:11 +08:00
* draw the actual route
2017-12-20 07:30:30 +08:00
* /
2017-12-28 00:17:11 +08:00
if ( opts . actual _route _line !== null ) {
let geodesicLayer = L . geodesic ( [ ] , {
weight : 7 ,
opacity : 0.9 ,
2017-12-28 10:52:37 +08:00
color : ACTUAL _ROUTE _COLOR ,
2017-12-28 00:17:11 +08:00
steps : 50 ,
wrap : false ,
} ) . addTo ( map ) ;
geodesicLayer . geoJson ( opts . actual _route _line ) ;
map . fitBounds ( geodesicLayer . getBounds ( ) ) ;
}
if ( opts . actual _route _points !== null ) {
let route _points = L . geoJSON ( opts . actual _route _points , {
onEachFeature : onFeaturePointClick ,
pointToLayer : pointToLayer ,
style : {
2017-12-28 10:52:37 +08:00
"color" : ACTUAL _ROUTE _COLOR ,
2017-12-28 00:17:11 +08:00
"weight" : 5 ,
"opacity" : 0.65 ,
} ,
2017-12-20 07:30:30 +08:00
} ) ;
2017-12-28 00:17:11 +08:00
route _points . addTo ( map ) ;
}
} ;
2017-12-20 07:30:30 +08:00
2017-12-28 00:17:11 +08:00
/ * *
* Render a map with the airspace , etc around a given set of coords
* e . g , the airport map
* @ param opts
* /
const _render _airspace _map = ( opts ) => {
opts = _ . defaults ( opts , {
render _elem : 'map' ,
overlay _elem : '' ,
lat : 0 ,
lon : 0 ,
zoom : 12 ,
layers : [ ] ,
set _marker : false ,
} ) ;
let map = draw _base _map ( opts ) ;
const coords = [ opts . lat , opts . lon ] ;
console . log ( 'Applying coords' , coords ) ;
2017-12-20 07:30:30 +08:00
2017-12-28 00:17:11 +08:00
map . setView ( coords , opts . zoom ) ;
if ( opts . set _marker === true ) {
L . marker ( coords ) . addTo ( map ) ;
2017-12-20 07:30:30 +08:00
}
2017-12-28 00:17:11 +08:00
return map ;
} ;
/ * *
* Render the live map
* @ param opts
* @ private
* /
const _render _live _map = ( opts ) => {
2017-12-28 06:47:22 +08:00
2017-12-28 00:17:11 +08:00
opts = _ . defaults ( opts , {
2017-12-28 06:47:22 +08:00
update _uri : '/api/acars' ,
2017-12-29 04:35:28 +08:00
pirep _uri : '/api/pireps/{id}/acars' ,
2017-12-28 06:47:22 +08:00
positions : null ,
2017-12-28 00:17:11 +08:00
render _elem : 'map' ,
2017-12-28 06:47:22 +08:00
aircraft _icon : '/assets/img/acars/aircraft.png' ,
2017-12-28 00:17:11 +08:00
} ) ;
2017-12-28 06:47:22 +08:00
let flightPositions = null ;
const map = draw _base _map ( opts ) ;
const aircraftIcon = L . icon ( {
iconUrl : opts . aircraft _icon ,
iconSize : [ 48 , 48 ] ,
iconAnchor : [ 0 , 0 ] ,
popupAnchor : [ - 3 , - 76 ] ,
} ) ;
const updateMap = ( ) => {
console . log ( 'reloading flights from acars...' ) ;
/ * *
* AJAX UPDATE
* /
let flights = $ . ajax ( {
url : opts . update _uri ,
dataType : "json" ,
error : console . log
} ) ;
$ . when ( flights ) . done ( function ( flightGeoJson ) {
if ( flightPositions !== null ) {
flightPositions . clearLayers ( ) ;
}
flightPositions = L . geoJSON ( flightGeoJson , {
onEachFeature : onFeaturePointClick ,
pointToLayer : function ( feature , latlon ) {
return L . marker ( latlon , {
icon : aircraftIcon ,
rotationAngle : feature . properties . heading
} ) ;
}
} ) ;
flightPositions . addTo ( map ) ;
map . fitBounds ( flightPositions . getBounds ( ) ) ;
} ) ;
} ;
updateMap ( ) ;
setTimeout ( updateMap , 10000 ) ;
2017-12-28 00:17:11 +08:00
} ;
return {
render _airspace _map : _render _airspace _map ,
render _live _map : _render _live _map ,
2017-12-28 06:47:22 +08:00
render _route _map : _render _route _map ,
2017-12-20 07:30:30 +08:00
}
} ) ( ) ;