1- import  {  Card ,  HStack ,  Icon ,  Link ,  Stack ,  Text  }  from  "@chakra-ui/react" ; 
2- import  type  {  ReactNode  }  from  "react" ; 
1+ import  { 
2+   Card , 
3+   Checkbox , 
4+   HStack , 
5+   Icon , 
6+   Link , 
7+   Stack , 
8+   Text , 
9+ }  from  "@chakra-ui/react" ; 
10+ import  {  useEffect ,  useState ,  type  ReactNode  }  from  "react" ; 
311import  {  LuFolderPlus ,  LuFolderSearch  }  from  "react-icons/lu" ; 
412import  {  MarkdownHooks  }  from  "react-markdown" ; 
513import  type  {  StacCatalog ,  StacCollection  }  from  "stac-ts" ; 
@@ -8,6 +16,8 @@ import { useChildren } from "../hooks/stac-value";
816import  type  {  SetHref  }  from  "../types/app" ; 
917import  {  CollectionSearch  }  from  "./search/collection" ; 
1018import  Section  from  "./section" ; 
19+ import  {  useMap  }  from  "react-map-gl/maplibre" ; 
20+ import  type  {  BBox  }  from  "geojson" ; 
1121
1222export  function  Children ( { 
1323  value, 
@@ -18,51 +28,93 @@ export function Children({
1828} )  { 
1929  const  {  collections }  =  useStacMap ( ) ; 
2030  const  children  =  useChildren ( value ,  ! ! collections ) ; 
31+   const  {  map }  =  useMap ( ) ; 
2132  const  selfHref  =  value ?. links ?. find ( ( link )  =>  link . rel  ===  "self" ) ?. href ; 
33+   const  [ mapBbox ,  setMapBbox ]  =  useState < BBox > ( ) ; 
34+   const  [ filterByViewport ,  setFilterByViewport ]  =  useState ( true ) ; 
35+   const  [ filteredCollections ,  setFilteredCollections ]  =  useState ( collections ) ; 
36+ 
37+   useEffect ( ( )  =>  { 
38+     if  ( map )  { 
39+       map . on ( "moveend" ,  ( )  =>  { 
40+         if  ( map )  { 
41+           setMapBbox ( map . getBounds ( ) . toArray ( ) . flat ( )  as  BBox ) ; 
42+         } 
43+       } ) ; 
44+     } 
45+   } ,  [ map ] ) ; 
46+ 
47+   useEffect ( ( )  =>  { 
48+     if  ( filterByViewport  &&  mapBbox )  { 
49+       setFilteredCollections ( 
50+         collections ?. filter ( ( collection )  => 
51+           isCollectionInBbox ( collection ,  mapBbox ) , 
52+         ) , 
53+       ) ; 
54+     }  else  { 
55+       setFilteredCollections ( collections ) ; 
56+     } 
57+   } ,  [ collections ,  filterByViewport ,  mapBbox ] ) ; 
2258
2359  return  ( 
2460    < > 
25-       { collections  &&  collections ?. length  >  0  &&  ( 
26-         < > 
27-           < Section 
28-             title = { 
29-               < HStack > 
30-                 < Icon > 
31-                   < LuFolderSearch > </ LuFolderSearch > 
32-                 </ Icon > { " " } 
33-                 Collection search
34-               </ HStack > 
35-             } 
36-           > 
37-             < CollectionSearch 
38-               href = { selfHref } 
39-               setHref = { setHref } 
40-               collections = { collections } 
41-             > </ CollectionSearch > 
42-           </ Section > 
61+       { collections  && 
62+         filteredCollections  && 
63+         filteredCollections ?. length  >  0  &&  ( 
64+           < > 
65+             < Section 
66+               title = { 
67+                 < HStack > 
68+                   < Icon > 
69+                     < LuFolderSearch > </ LuFolderSearch > 
70+                   </ Icon > { " " } 
71+                   Collection search
72+                 </ HStack > 
73+               } 
74+             > 
75+               < CollectionSearch 
76+                 href = { selfHref } 
77+                 setHref = { setHref } 
78+                 collections = { filteredCollections } 
79+               > </ CollectionSearch > 
80+             </ Section > 
4381
44-           < Section 
45-             title = { 
46-               < HStack > 
47-                 < Icon > 
48-                   < LuFolderPlus > </ LuFolderPlus > 
49-                 </ Icon > { " " } 
50-                 Collections ({ collections . length } )
51-               </ HStack > 
52-             } 
53-           > 
54-             < Stack > 
55-               { collections . map ( ( collection )  =>  ( 
56-                 < ChildCard 
57-                   child = { collection } 
58-                   setHref = { setHref } 
59-                   key = { "collection-"  +  collection . id } 
60-                 > </ ChildCard > 
61-               ) ) } 
62-             </ Stack > 
63-           </ Section > 
64-         </ > 
65-       ) } 
82+             < Section 
83+               title = { 
84+                 < HStack > 
85+                   < Icon > 
86+                     < LuFolderPlus > </ LuFolderPlus > 
87+                   </ Icon > { " " } 
88+                   Collections (
89+                   { ( filterByViewport  && 
90+                     filteredCollections . length  +  "/"  +  collections . length )  || 
91+                     collections . length } 
92+                   )
93+                 </ HStack > 
94+               } 
95+             > 
96+               < Stack > 
97+                 < Checkbox . Root 
98+                   mb = { 2 } 
99+                   size = { "sm" } 
100+                   checked = { filterByViewport } 
101+                   onCheckedChange = { ( e )  =>  setFilterByViewport ( ! ! e . checked ) } 
102+                 > 
103+                   < Checkbox . HiddenInput > </ Checkbox . HiddenInput > 
104+                   < Checkbox . Control > </ Checkbox . Control > 
105+                   < Checkbox . Label > Filter by viewport</ Checkbox . Label > 
106+                 </ Checkbox . Root > 
107+                 { filteredCollections . map ( ( collection )  =>  ( 
108+                   < ChildCard 
109+                     child = { collection } 
110+                     setHref = { setHref } 
111+                     key = { "collection-"  +  collection . id } 
112+                   > </ ChildCard > 
113+                 ) ) } 
114+               </ Stack > 
115+             </ Section > 
116+           </ > 
117+         ) } 
66118
67119      { children  &&  children . length  >  0  &&  ( 
68120        < Section  title = "Children" > 
@@ -114,3 +166,29 @@ export function ChildCard({
114166    </ Card . Root > 
115167  ) ; 
116168} 
169+ 
170+ function  isCollectionInBbox ( collection : StacCollection ,  bbox : BBox )  { 
171+   if  ( bbox [ 2 ]  -  bbox [ 0 ]  >=  360 )  { 
172+     // A global bbox always contains every collection 
173+     return  true ; 
174+   } 
175+   const  collectionBbox  =  collection ?. extent ?. spatial ?. bbox ?. [ 0 ] ; 
176+   if  ( collectionBbox )  { 
177+     return  ( 
178+       ! ( 
179+         collectionBbox [ 0 ]  <  bbox [ 0 ]  && 
180+         collectionBbox [ 1 ]  <  bbox [ 1 ]  && 
181+         collectionBbox [ 2 ]  >  bbox [ 2 ]  && 
182+         collectionBbox [ 3 ]  >  bbox [ 3 ] 
183+       )  && 
184+       ! ( 
185+         collectionBbox [ 0 ]  >  bbox [ 2 ]  || 
186+         collectionBbox [ 1 ]  >  bbox [ 3 ]  || 
187+         collectionBbox [ 2 ]  <  bbox [ 0 ]  || 
188+         collectionBbox [ 3 ]  <  bbox [ 1 ] 
189+       ) 
190+     ) ; 
191+   }  else  { 
192+     return  false ; 
193+   } 
194+ } 
0 commit comments