1
1
import { useRecoilValue } from "recoil" ;
2
2
import { amdbLayersState } from "../../state/amdb" ;
3
3
import { AmdbLayerName , getAmdbAPI } from "@navigraph/amdb" ;
4
- import { userState } from "../../state/user" ;
5
- import { Scope } from "@navigraph/app" ;
6
- import { forwardRef , memo , useCallback , useRef } from "react" ;
7
- import { useQuery } from "@tanstack/react-query" ;
8
- import { GeoJSON } from "react-leaflet" ;
9
- import { circleMarker , GeoJSON as LeafletGeoJson } from 'leaflet' ;
4
+ import { memo , useEffect , useRef } from "react" ;
5
+ import { useQueries } from "@tanstack/react-query" ;
6
+ import { useMap } from "react-leaflet" ;
7
+ import { circleMarker , geoJson , GeoJSON } from 'leaflet' ;
10
8
import { renderToString } from "react-dom/server" ;
11
9
import JsonView from "../JsonView" ;
12
10
import amdbStyle , { layerOrder } from "./amdb_styles" ;
13
11
14
- const AmdbLayer = memo ( forwardRef < LeafletGeoJson , { idarpt : string , layer : AmdbLayerName , onClick ?: ( e : LeafletGeoJson ) => void } > ( ( { idarpt, layer, onClick } , ref ) => {
15
- const { data } = useQuery ( {
16
- queryKey : [ 'amdb-data' , idarpt , layer ] ,
17
- queryFn : async ( ) => {
18
- return amdb . getAmdbLayer ( { icao : idarpt , layer } )
19
- }
20
- } )
21
-
12
+ const AmdbManager = memo ( ( ) => {
22
13
const amdb = getAmdbAPI ( ) ;
23
14
24
- if ( ! data ) return null ;
25
-
26
- return (
27
- < GeoJSON
28
- ref = { ref }
29
- data = { data ?? { } }
30
- style = { amdbStyle ( layer ) }
31
- pointToLayer = { ( feature , latlng ) => {
32
- const marker = circleMarker ( latlng , amdbStyle ( layer ) ( feature ) ) ;
33
-
34
- marker . feature = feature ;
35
-
36
- return marker ;
37
- } }
38
- onEachFeature = { ( feature , _layer ) => {
39
- _layer . on ( 'click' , ( e ) => {
40
- onClick ?.( e . target ) ;
41
- } ) ;
42
-
43
- if ( feature . properties ) {
44
- _layer . bindPopup ( renderToString (
45
- < div className = "flex flex-col items-center gap-2" >
46
- < span className = "text-ng-background-200" > { layer } </ span >
47
- < JsonView content = { feature . properties } />
48
- </ div >
49
- ) )
50
- }
51
- } }
52
- />
53
-
54
- )
55
- } ) ) ;
56
-
57
- export default function AmdbManager ( ) {
15
+ const map = useMap ( ) ;
16
+
58
17
const amdbLayers = useRecoilValue ( amdbLayersState ) ;
59
18
60
- const user = useRecoilValue ( userState ) ;
19
+ const data = useQueries ( {
20
+ queries : amdbLayers . flatMap ( ( [ idarpt , layers ] ) => layers . map ( ( layer ) => ( {
21
+ queryKey : [ 'amdb-data' , idarpt , layer ] ,
22
+ queryFn : async ( ) => ( { idarpt, layer, data : await amdb . getAmdbLayer ( { icao : idarpt , layer } ) } ) ,
23
+ } ) ) )
24
+ } )
25
+
26
+ const layers = useRef < { idarpt : string , layerName : AmdbLayerName , layer : GeoJSON } [ ] > ( [ ] ) ;
61
27
62
- const refs = useRef < Record < string , Partial < Record < AmdbLayerName , LeafletGeoJson > > > > ( { } ) ;
28
+ useEffect ( ( ) => {
29
+ const toRemove = layers . current . filter ( ( { idarpt, layerName } ) => ! data . some ( ( { data } ) => data ?. idarpt === idarpt && data ?. layer === layerName ) ) ;
63
30
64
- const updateOrder = useCallback ( ( ) => {
65
- Object . values ( refs . current ) . forEach ( ( layer ) => {
66
- [ ... Object . entries ( layer ) ] . sort ( ( a , b ) => layerOrder [ b [ 0 ] as AmdbLayerName ] - layerOrder [ a [ 0 ] as AmdbLayerName ] ) . forEach ( ( layer ) => layer [ 1 ] ?. bringToFront ( ) )
31
+ toRemove . forEach ( ( { layer } ) => {
32
+ map . removeLayer ( layer ) ;
33
+ layers . current . splice ( layers . current . findIndex ( ( x ) => x . layer === layer ) , 1 ) ;
67
34
} ) ;
68
- } , [ refs . current ] ) ;
69
-
70
- if ( ! user ?. scope . includes ( Scope . AMDB ) ) return ;
71
-
72
- return amdbLayers . flatMap ( ( [ idarpt , layers ] ) =>
73
- [ ...layers , 'aerodromereferencepoint' as const satisfies AmdbLayerName ] . map ( ( layer ) => (
74
- < AmdbLayer
75
- ref = { ( _layer ) => {
76
- if ( ! refs . current [ idarpt ] ) {
77
- refs . current [ idarpt ] = { } ;
78
- }
79
- refs . current [ idarpt ] [ layer ] = _layer ?? undefined
80
-
81
- updateOrder ( ) ;
82
- } }
83
- key = { `${ idarpt } /${ layer } ` }
84
- onClick = { ( _layer ) => {
85
- const feature = _layer . feature ;
86
-
87
- if ( feature ?. type === 'Feature' ) {
88
- const style = amdbStyle ( layer ) ( feature ) ;
89
-
90
- style . stroke = true ;
91
- style . color = 'blue' ;
92
-
93
- Object . values ( refs . current ) . forEach ( ( layer ) => {
94
- Object . values ( layer ) . forEach ( ( x ) => {
95
- x ?. resetStyle ( ) ;
35
+
36
+ const newLayers = data . flatMap ( ( { data } ) => {
37
+ if ( data ?. data && ! layers . current . some ( ( { idarpt, layerName } ) => idarpt === data . idarpt && layerName === data . layer ) ) {
38
+ return [ {
39
+ idarpt : data . idarpt ,
40
+ layerName : data . layer ,
41
+ layer : geoJson ( data . data , {
42
+ style : amdbStyle ( data . layer ) ,
43
+
44
+ pointToLayer : ( feature , latlng ) => {
45
+ const marker = circleMarker ( latlng , amdbStyle ( data . layer ) ( feature ) ) ;
46
+
47
+ marker . feature = feature ;
48
+
49
+ return marker ;
50
+ } ,
51
+
52
+ onEachFeature : ( feature , _layer ) => {
53
+ _layer . on ( 'click' , ( e ) => {
54
+ const target = e . target as GeoJSON ;
55
+
56
+ const feature = target . feature ;
57
+
58
+ if ( feature ?. type === 'Feature' ) {
59
+ const style = amdbStyle ( data . layer ) ( feature ) ;
60
+
61
+ style . stroke = true ;
62
+ style . color = 'blue' ;
63
+
64
+ layers . current . forEach ( ( { layer } ) => {
65
+ layer . resetStyle ( ) ;
66
+ } )
67
+
68
+ target . setStyle ( style ) ;
69
+ }
96
70
} ) ;
97
- } )
98
-
99
- _layer . setStyle ( style ) ;
100
- }
101
- } }
102
- idarpt = { idarpt }
103
- layer = { layer }
104
- />
105
- ) )
106
- )
107
- }
71
+
72
+ if ( feature . properties ) {
73
+ _layer . bindPopup ( renderToString (
74
+ < div className = "flex flex-col items-center gap-2" >
75
+ < span className = "text-ng-background-200" > { data . layer } </ span >
76
+ < JsonView content = { feature . properties } />
77
+ </ div >
78
+ ) )
79
+ }
80
+ }
81
+ } )
82
+ } ] ;
83
+ }
84
+
85
+ return [ ] ;
86
+ } ) ;
87
+
88
+ newLayers . forEach ( ( { idarpt, layerName, layer } ) => {
89
+ map . addLayer ( layer ) ;
90
+ layers . current . push ( { idarpt, layerName, layer } ) ;
91
+ } ) ;
92
+
93
+ layers . current . sort ( ( a , b ) => layerOrder [ b . layerName ] - layerOrder [ a . layerName ] ) . forEach ( ( { layer } ) => layer . bringToFront ( ) )
94
+ } , [ data ] ) ;
95
+
96
+ return null ;
97
+ } ) ;
98
+
99
+ export default AmdbManager ;
0 commit comments