From 24bea3c10c82216b69cbc318e56067f6ee65a49b Mon Sep 17 00:00:00 2001 From: Lucy Hutcheson Date: Mon, 20 Mar 2023 10:38:35 -0700 Subject: [PATCH] Add rescale, colormap, expression tiler parameters (#62) * Add rescale, colormap, expression tiler parameters * Fix for issue #8 * Fix for issue #35 --- .env.example | 6 +- CHANGELOG.md | 13 +++ README.md | 37 +++---- src/components/Search/Search.js | 50 +++++---- src/components/Search/envVarSetup.js | 152 ++++++++++++++++++--------- 5 files changed, 165 insertions(+), 93 deletions(-) diff --git a/.env.example b/.env.example index e23e942f..cdd05a3a 100644 --- a/.env.example +++ b/.env.example @@ -6,6 +6,8 @@ REACT_APP_ANALYZE_BTN_URL=https://analyze.example.com REACT_APP_SHOW_PUBLISH_BTN=false REACT_APP_STAC_API_URL=https://api-endpoint.example.com REACT_APP_DEFAULT_COLLECTION=collection-name -REACT_APP_TILER_URL=https://titiler.example.com -REACT_APP_TILER_PARAMS={"sentinel-2-l2a": { "assets": [ "visual" ], "mosaic_asset": "visual" }, "landsat-c2-l2": { "assets": [ "red", "green", "blue" ], "color_formula": "Gamma+RGB+1.7+Saturation+1.7+Sigmoidal+RGB+15+0.35", "mosaic_asset":"red", "mosaic_color_formula": "Gamma+R+1.7+Sigmoidal+R+15+0.35" }, "naip": { "assets": [ "image" ], "mosaic_asset": "image", "bidx":"1,2,3" } } +REACT_APP_SCENE_TILER_URL=https://titiler.example.com +REACT_APP_SCENE_TILER_PARAMS={ "sentinel-2-l2a": { "assets": [ "visual" ] }, "landsat-c2-l2": { "assets": [ "red", "green", "blue" ], "color_formula": "Gamma+RGB+1.7+Saturation+1.7+Sigmoidal+RGB+15+0.35" }, "naip": { "assets": [ "image" ], "bidx": "1,2,3" }, "cop-dem-glo-30": { "assets": [ "data" ], "colormap_name": "terrain", "rescale":["-1000,4000"] }, "cop-dem-glo-90": { "assets": [ "data" ], "colormap_name": "terrain", "rescale":["-1000,4000"] }, "sentinel-1-grd": { "assets": [ "vv"], "rescale": ["0,250"], "colormap_name": "plasma"} } +REACT_APP_MOSAIC_TILER_URL=https://titiler-mosaic.example.com +REACT_APP_MOSAIC_TILER_PARAMS={ "sentinel-2-l2a": { "assets": [ "visual" ] }, "landsat-c2-l2": { "assets": [ "red" ], "color_formula": "Gamma+RGB+1.7+Saturation+1.7+Sigmoidal+R+15+0.35" }, "naip": { "assets": [ "image" ], "bidx": "1,2,3" }, "cop-dem-glo-30": { "assets": [ "data" ], "colormap_name": "terrain", "rescale":["-1000,4000"]}, "cop-dem-glo-90": { "assets": [ "data" ], "colormap_name": "terrain", "rescale":["-1000,4000"]}, "sentinel-1-grd": { "assets": [ "vv" ], "rescale": ["0,250"], "colormap_name": "plasma"} } REACT_APP_MIN_ZOOM_LEVEL=7 \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index caa869c2..4587d72d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,19 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## v.0.5.0 - TBD + +### Changed + +- Move mosaic-specific tiler parameters (`mosaic_asset` and `mosaic_color_formula`) into REACT_APP_MOSAIC_TILER_PARAMS (new), and rename them to `assets` and `color_formula` to align with scene view tiler parameters. +- Rename REACT_APP_TILER_URL to REACT_APP_SCENE_TILER_URL +- Rename REACT_APP_TILER_PARAMS to REACT_APP_SCENE_TILER_PARAMS + +### Added + +- Env variable REACT_APP_MOSAIC_TILER_PARAMS +- `rescale`, `colormap_name`, and `expression` tiler parameters + ## v0.4.0 - 2023-03-14 ### Changed diff --git a/README.md b/README.md index 42ae5c17..b42791e1 100644 --- a/README.md +++ b/README.md @@ -22,24 +22,25 @@ FilmDrop UI is a browser-based interface for displaying results from a STAC API. For local development, you should create an `.env` file with the appropriate configuration outlined in the table below. The file `.env.example` is included in this repository as a representative file. -| Variable | Description | Required | -| ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | -| PUBLIC_URL | URL for the FilmDrop UI. Useful when using a CDN to host application. | Optional | -| REACT_APP_APP_NAME | Name for this app | Optional | -| REACT_APP_LOGO_URL | URL for your custom logo | Optional | -| REACT_APP_LOGO_ALT | Alt image description for your custom logo | Optional | -| REACT_APP_DASHBOARD_BTN_URL | URL for the Dashboard button at the top right of the UI. If not set, the button will not be visible. | Optional | -| REACT_APP_ANALYZE_BTN_URL | URL for the Analyze button at the bottom left of the UI. If not set, the button will not be visible. | Optional | -| REACT_APP_SHOW_PUBLISH_BTN | Flag for displaying the Publish button at the bottom left of the UI. Setting to `true` will display the button, any other value will not display the button. Default is to not display the button. | Optional | -| REACT_APP_STAC_API_URL | URL for STAC API | Required | -| REACT_APP_API_MAX_ITEMS | Maximum number of items requested from API. If not set, the default max items will be 200. | Optional | -| REACT_APP_DEFAULT_COLLECTION | Default collection option for collection dropdown | Optional | -| REACT_APP_TILER_URL | URL for map tiling | Required | -| REACT_APP_TILER_PARAMS | Per-collection configuration of TiTiler `assets`, `color_formula`, `bidx`, `mosaic_asset`, and `mosaic_color_formula` parameters. Example in [.env.example](.env.example) | Optional | -| REACT_APP_MIN_ZOOM_LEVEL | Minimum zoom level for search results. If not set, the default zoom level will be 7. | Optional | -| REACT_APP_CF_TEMPLATE_URL | CloudFormation Template URL used to create a new stack. If not set, the Launch Your Own button will not be visible. | Optional | -| REACT_APP_MOSAIC_TILER_URL | URL for mosaic tiling. If not set, the View Mode selector will not be visible. The app requires the use of the [NASA IMPACT TiTiler fork](https://github.com/NASA-IMPACT/titiler) as it contains the mosaicjson endpoints needed. | Optional | -| REACT_APP_MOSAIC_MAX_ITEMS | Maximum number of items in mosaic. If not set, the default max items will be 100. | Optional | +| Variable | Description | Required | +| ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | +| PUBLIC_URL | URL for the FilmDrop UI. Useful when using a CDN to host application. | Optional | +| REACT_APP_APP_NAME | Name for this app | Optional | +| REACT_APP_LOGO_URL | URL for your custom logo | Optional | +| REACT_APP_LOGO_ALT | Alt image description for your custom logo | Optional | +| REACT_APP_DASHBOARD_BTN_URL | URL for the Dashboard button at the top right of the UI. If not set, the button will not be visible. | Optional | +| REACT_APP_ANALYZE_BTN_URL | URL for the Analyze button at the bottom left of the UI. If not set, the button will not be visible. | Optional | +| REACT_APP_SHOW_PUBLISH_BTN | Flag for displaying the Publish button at the bottom left of the UI. Setting to `true` will display the button, any other value will not display the button. Default is to not display the button. | Optional | +| REACT_APP_STAC_API_URL | URL for STAC API | Required | +| REACT_APP_API_MAX_ITEMS | Maximum number of items requested from API. If not set, the default max items will be 200. | Optional | +| REACT_APP_DEFAULT_COLLECTION | Default collection option for collection dropdown | Optional | +| REACT_APP_SCENE_TILER_URL | URL for map tiling | Required | +| REACT_APP_SCENE_TILER_PARAMS | Per-collection configuration of TiTiler `assets`, `color_formula`, `bidx`, `rescale`, `expression`, and `colormap_name` parameters. Example in [.env.example](.env.example) | Optional | +| REACT_APP_MIN_ZOOM_LEVEL | Minimum zoom level for search results. If not set, the default zoom level will be 7. | Optional | +| REACT_APP_CF_TEMPLATE_URL | CloudFormation Template URL used to create a new stack. If not set, the Launch Your Own button will not be visible. | Optional | +| REACT_APP_MOSAIC_TILER_URL | URL for mosaic tiling. If not set, the View Mode selector will not be visible. The app requires the use of the [NASA IMPACT TiTiler fork](https://github.com/NASA-IMPACT/titiler) as it contains the mosaicjson endpoints needed. | Optional | +| REACT_APP_MOSAIC_TILER_PARAMS | Per-collection configuration of TiTiler mosaic `assets`, `color_formula`, `bidx`, `rescale`, `expression`, and `colormap_name` parameters. Example in [.env.example](.env.example) | Optional | +| REACT_APP_MOSAIC_MAX_ITEMS | Maximum number of items in mosaic. If not set, the default max items will be 100. | Optional | ### Links diff --git a/src/components/Search/Search.js b/src/components/Search/Search.js index 578ddd3c..49b7d533 100644 --- a/src/components/Search/Search.js +++ b/src/components/Search/Search.js @@ -1,11 +1,11 @@ import { React, useEffect, useState, useRef } from 'react' import './Search.css' import { - envTilerURL, - constructTilerParams, + envSceneTilerURL, + constructSceneTilerParams, + envMosaicTilerURL, constructMosaicTilerParams, - constructMosaicAssetVal, - envMosaicTilerURL + constructMosaicAssetVal } from './envVarSetup' import { convertDate, @@ -52,7 +52,7 @@ const Search = () => { const _sarPolarizations = useSelector( (state) => state.mainSlice.sarPolarizations ) - const tilerURL = envTilerURL + const sceneTilerURL = envSceneTilerURL const mosaicTilerURL = envMosaicTilerURL // set up map state @@ -412,7 +412,7 @@ const Search = () => { clickedFootprintImageLayerRef.current.clearLayers() const featureURL = feature.links[0].href - const tilerParams = constructTilerParams(selectedCollectionRef.current) + const tilerParams = constructSceneTilerParams(selectedCollectionRef.current) fetch(featureURL, { method: 'GET' @@ -422,23 +422,27 @@ const Search = () => { }) .then(function (json) { const tileBounds = setupBounds(json.bbox) - - L.tileLayer( - `${tilerURL}/stac/tiles/{z}/{x}/{y}.png?url=${featureURL}&${tilerParams}`, - { - tileSize: 256, - bounds: tileBounds, - pane: 'imagery' - } - ) - .addTo(clickedFootprintImageLayerRef.current) - .on('load', function () { - // hide loading spinner - dispatch(setSearchLoading(false)) - }) - .on('tileerror', function () { - console.log('Tile Error') - }) + if (sceneTilerURL) { + L.tileLayer( + `${sceneTilerURL}/stac/tiles/{z}/{x}/{y}.png?url=${featureURL}&${tilerParams}`, + { + tileSize: 256, + bounds: tileBounds, + pane: 'imagery' + } + ) + .addTo(clickedFootprintImageLayerRef.current) + .on('load', function () { + // hide loading spinner + dispatch(setSearchLoading(false)) + }) + .on('tileerror', function () { + console.log('Tile Error') + }) + } else { + dispatch(setSearchLoading(false)) + console.log('REACT_APP_SCENE_TILER_URL is not set in env variables.') + } }) } diff --git a/src/components/Search/envVarSetup.js b/src/components/Search/envVarSetup.js index 2f90fe64..01211426 100644 --- a/src/components/Search/envVarSetup.js +++ b/src/components/Search/envVarSetup.js @@ -1,62 +1,24 @@ // retrieve tiler URLs from env variable -export const envTilerURL = process.env.REACT_APP_TILER_URL || '' +export const envSceneTilerURL = process.env.REACT_APP_SCENE_TILER_URL || '' export const envMosaicTilerURL = process.env.REACT_APP_MOSAIC_TILER_URL || '' -// function to construct the Titiler tile query parameters from -// REACT_APP_TILER_PARAMS env var -export const constructTilerParams = (collection) => { - const params = [] - - const tilerParams = getTilerParams() - - const [asset, assetsParam] = constructAssetsParam(collection, tilerParams) - - params.push(assetsParam) - - const colorFormula = tilerParams[collection]?.color_formula - if (colorFormula) { - params.push(`color_formula=${colorFormula}`) - } - - const bidx = tilerParams[collection]?.bidx - const assetBidx = asset && bidx ? `${asset}|${bidx}` : null - if (assetBidx) { - params.push(`asset_bidx=${assetBidx}`) - } - - return params.join('&') -} - -export const constructMosaicTilerParams = (collection) => { - // retrieve tiler parameters from env variable - const tilerParams = getTilerParams() - - const params = [] - - const colorFormula = tilerParams[collection]?.mosaic_color_formula - if (colorFormula) { - params.push(`color_formula=${colorFormula}`) - } - - const bidx = tilerParams[collection]?.bidx - if (bidx) { - params.push(`bidx=${bidx}`) - } +// reusable variables +const envSceneTilerParams = 'REACT_APP_SCENE_TILER_PARAMS' +const envMosaicTilerParams = 'REACT_APP_MOSAIC_TILER_PARAMS' - return params.join('&') -} - -const getTilerParams = () => { +// retrieve tiler params from env variables for scene and mosaic +const getTilerParams = (configVariable) => { try { - return JSON.parse(process.env.REACT_APP_TILER_PARAMS) + return JSON.parse(process.env[configVariable]) } catch (e) { console.log(`Error parsing tiler params: ${e.message}`) } return {} } -const constructAssetsParam = (collection, tilerParams) => { - const assets = tilerParams[collection]?.assets || [] +// construct assets params from env variables for scene mode +const constructSceneAssetsParam = (collection, tilerParams) => { + const assets = tilerParams[collection]?.assets || '' if (!assets) { console.log(`Assets not defined for ${collection}`) return [null, ''] @@ -67,12 +29,102 @@ const constructAssetsParam = (collection, tilerParams) => { return [assets[0], `assets=${assets.join('&assets=')}`] } +// construct assets params from env variables for mosaic mode export const constructMosaicAssetVal = (collection) => { - const asset = getTilerParams()[collection]?.mosaic_asset || '' + const asset = getTilerParams(envMosaicTilerParams)[collection]?.assets || '' if (!asset) { console.log(`Assets not defined for ${collection}`) return null } else { - return asset + return asset.pop() } } + +// method to construct tiler parameter values for scene and mosaic +const parameters = { + colorFormula: (tilerParams, collection) => { + const value = tilerParams[collection]?.color_formula + return value && `color_formula=${value}` + }, + expression: (tilerParams, collection) => { + const value = tilerParams[collection]?.expression + return value && `expression=${value}` + }, + rescale: (tilerParams, collection) => { + const value = tilerParams[collection]?.rescale + return value && `rescale=${value}` + }, + colormapName: (tilerParams, collection) => { + const value = tilerParams[collection]?.colormap_name + return value && `colormap_name=${value}` + }, + bidx: (tilerParams, collection, asset) => { + const value = tilerParams[collection]?.bidx + // for scene tiler + if (asset) { + const assetBidx = asset && value ? `${asset}|${value}` : null + return assetBidx && `asset_bidx=${assetBidx}` + } else { + return value && `bidx=${value}` + } + } +} + +// function to construct the Titiler tile query parameters from +// REACT_APP_SCENE_TILER_PARAMS env var +export const constructSceneTilerParams = (collection) => { + // retrieve mosaic tiler parameters from env variable + const tilerParams = getTilerParams(envSceneTilerParams) + + const params = [] + + const [asset, assetsParam] = constructSceneAssetsParam( + collection, + tilerParams + ) + + params.push(assetsParam) + + const assetBidx = parameters.bidx(tilerParams, collection, asset) + if (assetBidx) params.push(assetBidx) + + const colorFormula = parameters.colorFormula(tilerParams, collection) + if (colorFormula) params.push(colorFormula) + + const expression = parameters.expression(tilerParams, collection) + if (expression) params.push(expression) + + const rescale = parameters.rescale(tilerParams, collection) + if (rescale) params.push(rescale) + + const colormapName = parameters.colormapName(tilerParams, collection) + if (colormapName) params.push(colormapName) + + return params.join('&') +} + +// function to construct the Titiler tile query parameters from +// REACT_APP_MOSAIC_TILER_PARAMS env var +export const constructMosaicTilerParams = (collection) => { + // retrieve mosaic tiler parameters from env variable + const tilerParams = getTilerParams(envMosaicTilerParams) + + const params = [] + + const bidx = parameters.bidx(tilerParams, collection) + if (bidx) params.push(bidx) + + const colorFormula = parameters.colorFormula(tilerParams, collection) + if (colorFormula) params.push(colorFormula) + + const expression = parameters.expression(tilerParams, collection) + if (expression) params.push(expression) + + const rescale = parameters.rescale(tilerParams, collection) + if (rescale) params.push(rescale) + + const colormapName = parameters.colormapName(tilerParams, collection) + if (colormapName) params.push(colormapName) + + return params.join('&') +}