1
1
import { getApp , getDefaultAppDomain , Logger , NotInitializedError , Scope } from "@navigraph/app"
2
2
import { NavigraphAuth } from "@navigraph/auth"
3
- import { Coords , DoneCallback , TileLayer , TileLayerOptions } from "leaflet"
3
+ import { Coords , DoneCallback , LatLngBounds , TileLayer , TileLayerOptions } from "leaflet"
4
4
5
5
enum NavigraphRasterSourceOption {
6
6
"IFR HIGH" = "ifr.hi" ,
@@ -9,21 +9,26 @@ enum NavigraphRasterSourceOption {
9
9
"WORLD" = "world" ,
10
10
}
11
11
12
- export type NavigraphRasterSource = keyof typeof NavigraphRasterSourceOption
13
- export type NavigraphRasterTheme = "DAY" | "NIGHT"
14
-
15
- export interface PresetConfig {
16
- source : NavigraphRasterSource
17
- theme : NavigraphRasterTheme
18
- forceRetina ?: boolean
12
+ enum FAASourceOption {
13
+ "VFR" = "VFR" ,
14
+ "IFR HIGH" = "IFRH" ,
15
+ "IFR LOW" = "IFRL" ,
19
16
}
20
17
21
- function getNavigraphTileURL (
22
- source : NavigraphRasterSource = "VFR" ,
23
- theme : NavigraphRasterTheme = "DAY" ,
24
- retina = false ,
25
- ) {
26
- return `https://enroute-bitmap.charts.api-v2.${ getDefaultAppDomain ( ) } /styles/${ NavigraphRasterSourceOption [ source ] } .${ theme . toLowerCase ( ) } /{z}/{x}/{y}${ retina ? "@2x" : "{r}" } .png` // prettier-ignore
18
+ export type NavigraphRasterSource = keyof typeof NavigraphRasterSourceOption
19
+ export type FAASource = keyof typeof FAASourceOption
20
+ export type NavigraphTheme = "DAY" | "NIGHT"
21
+
22
+ export type PresetConfig = { theme ?: NavigraphTheme ; forceRetina ?: boolean } & (
23
+ | { type : "Navigraph" ; source : NavigraphRasterSource }
24
+ | { type : "FAA" ; source : Extract < FAASource , "VFR" > ; withTAC ?: boolean }
25
+ | { type : "FAA" ; source : Exclude < FAASource , "VFR" > }
26
+ )
27
+
28
+ function getNavigraphTileURL ( options : PresetConfig ) {
29
+ const { source, theme = "DAY" } = options
30
+ const forceRetina = "forceRetina" in options ? options . forceRetina : false
31
+ return `https://enroute-bitmap.charts.api-v2.${ getDefaultAppDomain ( ) } /styles/${ NavigraphRasterSourceOption [ source ] } .${ theme . toLowerCase ( ) } /{z}/{x}/{y}${ forceRetina ? "@2x" : "{r}" } .png` // prettier-ignore
27
32
}
28
33
29
34
/**
@@ -43,12 +48,67 @@ export class NavigraphTileLayer extends TileLayer {
43
48
/** Indicates whether map tiles failed to load due to authentication being invalid or missing. */
44
49
private isMissingAuth = false
45
50
51
+ private maxFAAZoom = 12
52
+
53
+ private tacLayer = new TileLayer ( `https://enroute.charts.api-v2.${ getDefaultAppDomain ( ) } /FAA/TAC/{z}/{x}/{y}.png` , {
54
+ minZoom : 10 ,
55
+ maxNativeZoom : 12 ,
56
+ maxZoom : this . maxFAAZoom ,
57
+ tileSize : 512 ,
58
+ zoomOffset : - 1 ,
59
+ className : "faa-vfr-tiles" ,
60
+ } )
61
+
62
+ private vfrLayer = new TileLayer ( `https://enroute.charts.api-v2.${ getDefaultAppDomain ( ) } /FAA/VFR/{z}/{x}/{y}.png` , {
63
+ minZoom : 1 ,
64
+ maxNativeZoom : 11 ,
65
+ maxZoom : this . maxFAAZoom ,
66
+ className : "faa-vfr-tiles" ,
67
+ } )
68
+
69
+ // prettier-ignore
70
+ private ifrLowLayer = new TileLayer ( `https://enroute.charts.api-v2.${ getDefaultAppDomain ( ) } /FAA/IFRL/{z}/{x}/{y}.png` , {
71
+ minZoom : 1 ,
72
+ maxNativeZoom : 10 ,
73
+ maxZoom : this . maxFAAZoom ,
74
+ className : "faa-ifr-tiles"
75
+ } )
76
+
77
+ // prettier-ignore
78
+ private ifrHighLayer = new TileLayer ( `https://enroute.charts.api-v2.${ getDefaultAppDomain ( ) } /FAA/IFRH/{z}/{x}/{y}.png` , {
79
+ minZoom : 1 ,
80
+ maxNativeZoom : 9 ,
81
+ maxZoom : this . maxFAAZoom ,
82
+ className : "faa-ifr-tiles"
83
+ } )
84
+
85
+ private styleElement = ( ( ) => {
86
+ const style = document . createElement ( "style" )
87
+ style . innerHTML = `
88
+ .night .faa-vfr-tiles img {
89
+ filter: brightness(0.6);
90
+ }
91
+
92
+ .night .faa-ifr-tiles img {
93
+ filter: hue-rotate(180deg) invert(1);
94
+ }
95
+ `
96
+
97
+ return style
98
+ } ) ( )
99
+
46
100
constructor (
47
101
public auth : NavigraphAuth ,
48
- public preset : PresetConfig = { source : "VFR" , theme : "DAY" } ,
102
+ public preset : PresetConfig = { type : "Navigraph" , source : "VFR" , theme : "DAY" } ,
49
103
tileOptions ?: TileLayerOptions ,
50
104
) {
51
- super ( getNavigraphTileURL ( preset . source , preset . theme , preset . forceRetina ) , tileOptions )
105
+ super ( getNavigraphTileURL ( preset ) , tileOptions )
106
+
107
+ this . on ( "remove" , ( ) => document . head ?. removeChild ( this . styleElement ) )
108
+ this . on ( "add" , ( ) => {
109
+ document . head . appendChild ( this . styleElement )
110
+ this . setPreset ( preset )
111
+ } )
52
112
53
113
const app = getApp ( )
54
114
@@ -78,10 +138,30 @@ export class NavigraphTileLayer extends TileLayer {
78
138
* navigraphLayer.setPreset({ source: "IFR HIGH", theme: "NIGHT" });
79
139
* ```
80
140
*/
81
- public setPreset ( preset : Partial < PresetConfig > ) {
82
- this . preset = { ...this . preset , ...preset }
83
- const newUrl = getNavigraphTileURL ( this . preset . source , this . preset . theme , this . preset . forceRetina )
141
+ public setPreset ( preset : PresetConfig ) {
142
+ const newUrl = getNavigraphTileURL ( preset )
84
143
this . setUrl ( newUrl )
144
+
145
+ this . toggleFAALayer ( this . vfrLayer , preset . type === "FAA" && preset . source === "VFR" )
146
+ this . toggleFAALayer ( this . tacLayer , preset . type === "FAA" && preset . source === "VFR" && ( preset . withTAC ?? false ) )
147
+ this . toggleFAALayer ( this . ifrLowLayer , preset . type === "FAA" && preset . source === "IFR LOW" )
148
+ this . toggleFAALayer ( this . ifrHighLayer , preset . type === "FAA" && preset . source === "IFR HIGH" )
149
+
150
+ document . body . classList . toggle ( "night" , preset . theme === "NIGHT" )
151
+
152
+ Logger . debug ( "Changed map preset" , preset )
153
+
154
+ this . preset = preset
155
+ }
156
+
157
+ private toggleFAALayer ( layer : TileLayer , visible : boolean ) {
158
+ if ( visible && ! this . _map . hasLayer ( layer ) ) {
159
+ Logger . debug ( "Adding FAA layer" , layer )
160
+ layer . addTo ( this . _map )
161
+ } else if ( ! visible && this . _map . hasLayer ( layer ) ) {
162
+ Logger . debug ( "Removing FAA layer" , layer )
163
+ layer . remove ( )
164
+ }
85
165
}
86
166
87
167
protected createTile ( coords : Coords , done : DoneCallback ) : HTMLElement {
0 commit comments