-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Titiler-cmr layer #1001
Closed
+536
−476
Closed
Titiler-cmr layer #1001
Changes from all commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
973ce19
Ongoing dataset support
abarciauskas-bgse a4f4087
layer working (with bad changes)
abarciauskas-bgse 4b659fd
Initial refactor of existing zarr/cmr types
abarciauskas-bgse 0242f19
Refactor source params into use* hooks
abarciauskas-bgse 495c88b
Changes for titiler-cmr hook before testing
abarciauskas-bgse 8653e48
Add titiler-cmr-timeseries file
abarciauskas-bgse 0813bc7
Minor tweaks to get layer working
abarciauskas-bgse c34b16a
Change layer type to cmr-stac and use jet colormap
abarciauskas-bgse 402bf2c
Rename files
abarciauskas-bgse f12bd6e
Add MUR; remove GPM IMERG via CMR STAC
abarciauskas-bgse d705bf6
Simplify fetchStacDatasetById conditional
abarciauskas-bgse 1b3bbd0
Fix lint error
abarciauskas-bgse eb0cb4d
Revert changes to style-generators
abarciauskas-bgse 1ae67d9
Fix ts-check errors
abarciauskas-bgse a95e25b
Refactoring to new map component
abarciauskas-bgse b96b6b2
Add new files
abarciauskas-bgse 4791707
Merge main
abarciauskas-bgse 528b5a2
Don't use same name for local variable
abarciauskas-bgse 722793e
Run ts check
abarciauskas-bgse f793fe5
Add hidden value
abarciauskas-bgse File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
32 changes: 8 additions & 24 deletions
32
app/scripts/components/common/map/style-generators/cmr-timeseries.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,38 +1,22 @@ | ||
import React from 'react'; | ||
|
||
import { BaseGeneratorParams } from '../types'; | ||
import { ZarrPaintLayer } from './zarr-timeseries'; | ||
import { useCMR } from './hooks'; | ||
import { ActionStatus } from '$utils/status'; | ||
import { useCMRSTAC } from './hooks'; | ||
import { RasterTimeseriesProps } from './raster-timeseries'; | ||
import { RasterPaintLayer } from '$components/common/map/style-generators/raster-paint-layer'; | ||
|
||
interface AssetUrlReplacement { | ||
from: string; | ||
to: string; | ||
} | ||
|
||
export interface CMRTimeseriesProps extends BaseGeneratorParams { | ||
id: string; | ||
stacCol: string; | ||
date?: Date; | ||
sourceParams?: Record<string, any>; | ||
stacApiEndpoint?: string; | ||
tileApiEndpoint?: string; | ||
assetUrlReplacements?: AssetUrlReplacement; | ||
zoomExtent?: number[]; | ||
onStatusChange?: (result: { status: ActionStatus; id: string }) => void; | ||
} | ||
|
||
export function CMRTimeseries(props:CMRTimeseriesProps) { | ||
export function CMRTimeseries(props: RasterTimeseriesProps) { | ||
const { | ||
id, | ||
stacCol, | ||
stacApiEndpoint, | ||
date, | ||
assetUrlReplacements, | ||
onStatusChange, | ||
sourceParams, | ||
hidden | ||
} = props; | ||
|
||
const stacApiEndpointToUse = stacApiEndpoint?? process.env.API_STAC_ENDPOINT; | ||
const assetUrl = useCMR({ id, stacCol, stacApiEndpointToUse, date, assetUrlReplacements, stacApiEndpoint, onStatusChange }); | ||
return <ZarrPaintLayer {...props} assetUrl={assetUrl} />; | ||
const tileParams = useCMRSTAC({ id, stacCol, stacApiEndpointToUse, date, assetUrlReplacements, stacApiEndpoint, onStatusChange, sourceParams }); | ||
return <RasterPaintLayer {...props} tileParams={tileParams} />; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,7 +11,7 @@ interface ZarrResponseData { | |
zarr: { | ||
href: string | ||
} | ||
} | ||
}, | ||
} | ||
interface CMRResponseData { | ||
features: { | ||
|
@@ -23,8 +23,13 @@ interface CMRResponseData { | |
}[] | ||
} | ||
|
||
export function useZarr({ id, stacCol, stacApiEndpointToUse, date, onStatusChange }){ | ||
const [assetUrl, setAssetUrl] = useState(''); | ||
interface STACforCMRResponseData { | ||
collection_concept_id: string; | ||
renders: Record<string, any>; | ||
} | ||
|
||
export function useZarr({ id, stacCol, stacApiEndpointToUse, date, onStatusChange, sourceParams }){ | ||
const [tileParams, setTileParams] = useState({}); | ||
|
||
useEffect(() => { | ||
const controller = new AbortController(); | ||
|
@@ -38,11 +43,18 @@ export function useZarr({ id, stacCol, stacApiEndpointToUse, date, onStatusChang | |
controller | ||
}); | ||
|
||
setAssetUrl(data.assets.zarr.href); | ||
if (data.assets.zarr.href) { | ||
setTileParams({ | ||
url: data.assets.zarr.href, | ||
time_slice: date, | ||
...sourceParams | ||
}); | ||
} | ||
|
||
onStatusChange?.({ status: S_SUCCEEDED, id }); | ||
} catch (error) { | ||
if (!controller.signal.aborted) { | ||
setAssetUrl(''); | ||
setTileParams({}); | ||
onStatusChange?.({ status: S_FAILED, id }); | ||
} | ||
return; | ||
|
@@ -54,15 +66,15 @@ export function useZarr({ id, stacCol, stacApiEndpointToUse, date, onStatusChang | |
return () => { | ||
controller.abort(); | ||
}; | ||
}, [id, stacCol, stacApiEndpointToUse, date, onStatusChange]); | ||
}, [id, stacCol, stacApiEndpointToUse, date, onStatusChange, sourceParams]); | ||
|
||
return assetUrl; | ||
return tileParams; | ||
} | ||
|
||
|
||
|
||
export function useCMR({ id, stacCol, stacApiEndpointToUse, date, assetUrlReplacements, stacApiEndpoint, onStatusChange }){ | ||
const [assetUrl, setAssetUrl] = useState(''); | ||
export function useCMRSTAC({ id, stacCol, stacApiEndpointToUse, date, assetUrlReplacements, stacApiEndpoint, onStatusChange, sourceParams }){ | ||
const [tileParams, setTileParams] = useState({}); | ||
|
||
const replaceInAssetUrl = (url: string, replacement: AssetUrlReplacement) => { | ||
const {from, to } = replacement; | ||
|
@@ -90,11 +102,15 @@ export function useCMR({ id, stacCol, stacApiEndpointToUse, date, assetUrlReplac | |
}); | ||
|
||
const assetUrl = replaceInAssetUrl(data.features[0].assets.data.href, assetUrlReplacements); | ||
setAssetUrl(assetUrl); | ||
setTileParams({ | ||
url: assetUrl, | ||
time_slice: date, | ||
...sourceParams | ||
}); | ||
onStatusChange?.({ status: S_SUCCEEDED, id }); | ||
} catch (error) { | ||
if (!controller.signal.aborted) { | ||
setAssetUrl(''); | ||
setTileParams({}); | ||
onStatusChange?.({ status: S_FAILED, id }); | ||
} | ||
return; | ||
|
@@ -106,8 +122,61 @@ export function useCMR({ id, stacCol, stacApiEndpointToUse, date, assetUrlReplac | |
return () => { | ||
controller.abort(); | ||
}; | ||
}, [id, stacCol, stacApiEndpointToUse, date, assetUrlReplacements, stacApiEndpoint, onStatusChange]); | ||
}, [id, stacCol, stacApiEndpointToUse, date, assetUrlReplacements, stacApiEndpoint, onStatusChange, sourceParams]); | ||
|
||
return tileParams; | ||
|
||
} | ||
|
||
|
||
export function useTitilerCMR({ id, stacCol, stacApiEndpointToUse, date, stacApiEndpoint, onStatusChange, sourceParams }){ | ||
const [tileParams, setTileParams] = useState({}); | ||
|
||
useEffect(() => { | ||
const controller = new AbortController(); | ||
|
||
async function load() { | ||
try { | ||
onStatusChange?.({ status: S_LOADING, id }); | ||
|
||
const data: STACforCMRResponseData = await requestQuickCache({ | ||
url: `${stacApiEndpointToUse}/collections/${stacCol}`, | ||
method: 'GET', | ||
controller | ||
}); | ||
|
||
const baseParams = { | ||
concept_id: data.collection_concept_id, | ||
datetime: date, | ||
...sourceParams | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔧 : This matches the naming of local state variable, can we change the name so it isn't confusing. |
||
}; | ||
|
||
const variable = sourceParams?.variable; | ||
|
||
if (variable) { | ||
baseParams.variable = variable; | ||
const renderParams = data.renders[variable] || {}; | ||
setTileParams({ ...renderParams, ...baseParams }); | ||
} else { | ||
setTileParams(baseParams); | ||
} | ||
|
||
return assetUrl; | ||
onStatusChange?.({ status: S_SUCCEEDED, id }); | ||
} catch (error) { | ||
if (!controller.signal.aborted) { | ||
setTileParams({}); | ||
onStatusChange?.({ status: S_FAILED, id }); | ||
} | ||
return; | ||
} | ||
} | ||
|
||
load(); | ||
|
||
return () => { | ||
controller.abort(); | ||
}; | ||
}, [id, stacCol, stacApiEndpointToUse, date, stacApiEndpoint, onStatusChange, sourceParams]); | ||
|
||
return tileParams; | ||
} |
119 changes: 119 additions & 0 deletions
119
app/scripts/components/common/map/style-generators/raster-paint-layer.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
import { useEffect, useMemo } from 'react'; | ||
import qs from 'qs'; | ||
import { RasterSource, RasterLayer } from 'mapbox-gl'; | ||
|
||
import useMapStyle from '../hooks/use-map-style'; | ||
|
||
interface RasterPaintLayerProps { | ||
id: string; | ||
tileParams?: Record<string, any>; | ||
tileApiEndpoint?: string; | ||
zoomExtent?: number[]; | ||
hidden?: boolean; | ||
idSuffix?: string; | ||
opacity?: number; | ||
} | ||
|
||
export function RasterPaintLayer(props: RasterPaintLayerProps) { | ||
const { | ||
id, | ||
tileApiEndpoint, | ||
tileParams, | ||
zoomExtent, | ||
hidden, | ||
opacity, | ||
idSuffix = '' | ||
} = props; | ||
|
||
const { updateStyle } = useMapStyle(); | ||
|
||
const [minZoom] = zoomExtent ?? [0, 20]; | ||
|
||
const generatorId = 'zarr-timeseries' + idSuffix; | ||
|
||
// Generate Mapbox GL layers and sources for raster timeseries | ||
// | ||
const haveSourceParamsChanged = useMemo( | ||
() => JSON.stringify(tileParams), | ||
[tileParams] | ||
); | ||
|
||
useEffect( | ||
() => { | ||
|
||
// Customize qs to use comma separated values for arrays | ||
// e.g. rescale: [[0, 100]] -> rescale=0,100 | ||
// TODO: test this with multiple rescale values, for multiple bands | ||
const options = { | ||
arrayFormat: 'comma', | ||
}; | ||
|
||
const tileParamsAsString = qs.stringify(tileParams, options); | ||
const tileServerUrl = `${tileApiEndpoint}?${tileParamsAsString}`; | ||
const layerSource: RasterSource = { | ||
type: 'raster', | ||
url: tileServerUrl | ||
}; | ||
const rasterOpacity = typeof opacity === 'number' ? opacity / 100 : 1; | ||
const layer: RasterLayer = { | ||
id: id, | ||
type: 'raster', | ||
source: id, | ||
layout: { | ||
visibility: hidden ? 'none' : 'visible' | ||
}, | ||
paint: { | ||
//'raster-opacity': hidden ? 0 : rasterOpacity, | ||
'raster-opacity-transition': { | ||
duration: 320 | ||
} | ||
}, | ||
minzoom: minZoom, | ||
metadata: { | ||
id, | ||
layerOrderPosition: 'raster', | ||
xyzTileUrl: tileServerUrl, | ||
} | ||
}; | ||
|
||
const sources = { | ||
[id]: layerSource | ||
}; | ||
const layers = [layer]; | ||
|
||
updateStyle({ | ||
generatorId, | ||
sources, | ||
layers | ||
}); | ||
}, | ||
// sourceParams not included, but using a stringified version of it to detect changes (haveSourceParamsChanged) | ||
[ | ||
updateStyle, | ||
id, | ||
tileParams, | ||
minZoom, | ||
haveSourceParamsChanged, | ||
hidden, | ||
generatorId, | ||
tileApiEndpoint, | ||
opacity | ||
|
||
] | ||
); | ||
|
||
// | ||
// Cleanup layers on unmount. | ||
// | ||
useEffect(() => { | ||
return () => { | ||
updateStyle({ | ||
generatorId, | ||
sources: {}, | ||
layers: [] | ||
}); | ||
}; | ||
}, [updateStyle, generatorId]); | ||
|
||
return null; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
20 changes: 20 additions & 0 deletions
20
app/scripts/components/common/map/style-generators/titiler-cmr-timeseries.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import React from 'react'; | ||
import { RasterPaintLayer } from './raster-paint-layer'; | ||
import { RasterTimeseriesProps } from './raster-timeseries'; | ||
import { useTitilerCMR } from '$components/common/map/style-generators/hooks'; | ||
|
||
export function TitilerCMRTimeseries(props: RasterTimeseriesProps) { | ||
const { | ||
id, | ||
stacCol, | ||
stacApiEndpoint, | ||
date, | ||
onStatusChange, | ||
sourceParams, | ||
hidden, | ||
} = props; | ||
|
||
const stacApiEndpointToUse = stacApiEndpoint?? process.env.API_STAC_ENDPOINT; | ||
const tileParams = useTitilerCMR({ id, stacCol, stacApiEndpointToUse, date, stacApiEndpoint, onStatusChange, sourceParams }); | ||
return <RasterPaintLayer {...props} tileParams={tileParams} />; | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder 🤔 if the backend team has json schemas we could generate into typescript interfaces to import, interested.. I'll follow up with them on this