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