Skip to content

Commit

Permalink
Simplify use Stac Collection (#670)
Browse files Browse the repository at this point in the history
@hanbyul-here This is a simplification suggestion for #666

It:
- Reduces array passes by merging the different `.map` and `.filter`
into a single `.reduce`
- Reduces component renders by avoiding state variables (status and
data)
- Uses the useQuery built in state to track the request status.
hanbyul-here authored Sep 22, 2023
2 parents 5eaa819 + 4e395e4 commit fc5bbbc
Showing 1 changed file with 65 additions and 68 deletions.
133 changes: 65 additions & 68 deletions app/scripts/components/analysis/define/use-stac-collection-search.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,14 @@
import { DatasetLayer } from 'veda';
import { useMemo } from 'react';
import { FeatureCollection, Polygon } from 'geojson';
import { useEffect, useState } from 'react';
import axios from 'axios';
import { useQuery } from '@tanstack/react-query';
import booleanIntersects from '@turf/boolean-intersects';
import bboxPolygon from '@turf/bbox-polygon';
import { areIntervalsOverlapping } from 'date-fns';

import { allAvailableDatasetsLayers } from '.';

import { utcString2userTzDate } from '$utils/date';
import {
ActionStatus,
S_FAILED,
S_IDLE,
S_LOADING,
S_SUCCEEDED
} from '$utils/status';

interface UseStacSearchProps {
start?: Date;
@@ -32,73 +25,77 @@ export function useStacCollectionSearch({
}: UseStacSearchProps) {
const readyToLoadDatasets = !!(start && end && aoi);

const [selectableDatasetLayers, setSelectableDatasetLayers] = useState<
DatasetLayer[]
>([]);

const [stacSearchStatus, setStacSearchStatus] =
useState<ActionStatus>(S_IDLE);

const { data: collectionData } = useQuery({
const result = useQuery({
queryKey: ['stacCollection'],
queryFn: async ({ signal }) => {
setStacSearchStatus(S_LOADING);
try {
const collectionResponse = await axios.get(collectionUrl, {
signal
});
setStacSearchStatus(S_SUCCEEDED);
return collectionResponse.data.collections;
} catch (e) {
if (!signal?.aborted) {
setStacSearchStatus(S_FAILED);
}
}
const collectionResponse = await axios.get(collectionUrl, {
signal
});
return collectionResponse.data.collections;
},
enabled: readyToLoadDatasets
});

useEffect(() => {
if (!collectionData || !readyToLoadDatasets) return;
const selectableDatasetLayers = useMemo(() => {
try {
setStacSearchStatus(S_LOADING);
const matchingCollectionIds = collectionData
.filter(
(col) => col.extent.spatial.bbox && col.extent.temporal.interval
)
.map((col) => {
return {
id: col.id,
bbox: col.extent.spatial.bbox[0],
start: utcString2userTzDate(col.extent.temporal.interval[0][0]),
end: utcString2userTzDate(col.extent.temporal.interval[0][1])
};
})
.filter((col) => {
return (
aoi.features.some((feature) =>
booleanIntersects(feature, bboxPolygon(col.bbox))
) &&
areIntervalsOverlapping(
{ start: new Date(start), end: new Date(end) },
{
start: new Date(col.start),
end: new Date(col.end)
}
)
);
})
.map((c) => c.id);
setSelectableDatasetLayers(
allAvailableDatasetsLayers.filter((l) =>
matchingCollectionIds.includes(l.stacCol)
)
);
return getInTemporalAndSpatialExtent(result.data, aoi, {
start,
end
});
} catch (e) {
setStacSearchStatus(S_FAILED);
return [];
}
}, [result.data, aoi, start, end]);

return {
selectableDatasetLayers: selectableDatasetLayers,
stacSearchStatus: result.status,
readyToLoadDatasets
};
}

function getInTemporalAndSpatialExtent(collectionData, aoi, timeRange) {
const matchingCollectionIds = collectionData.reduce((acc, col) => {
const id = col.id;

// Is is a dataset defined in the app?
// If not, skip other calculations.
const isAppDataset = allAvailableDatasetsLayers.some(
(l) => l.stacCol === id
);

if (
!isAppDataset ||
!col.extent.spatial.bbox ||
!col.extent.temporal.interval
) {
return acc;
}

const bbox = col.extent.spatial.bbox[0];
const start = utcString2userTzDate(col.extent.temporal.interval[0][0]);
const end = utcString2userTzDate(col.extent.temporal.interval[0][1]);

const isInAOI = aoi.features.some((feature) =>
booleanIntersects(feature, bboxPolygon(bbox))
);

const isInTOI = areIntervalsOverlapping(
{ start: new Date(timeRange.start), end: new Date(timeRange.end) },
{
start: new Date(start),
end: new Date(end)
}
);

if (isInAOI && isInTOI) {
return [...acc, id];
} else {
return acc;
}
setStacSearchStatus(S_SUCCEEDED);
}, [collectionData, start, end, aoi, readyToLoadDatasets]);
}, []);

return { selectableDatasetLayers, stacSearchStatus, readyToLoadDatasets };
return allAvailableDatasetsLayers.filter((l) =>
matchingCollectionIds.includes(l.stacCol)
);
}

0 comments on commit fc5bbbc

Please sign in to comment.