From e3772b5a1355998d3736ee27f38bac10d56dc414 Mon Sep 17 00:00:00 2001 From: Slesa Adhikari Date: Wed, 13 Mar 2024 17:57:52 -0500 Subject: [PATCH 01/23] Add support for arcgis imageserver datasets visualization --- .../common/map/style-generators/hooks.ts | 47 ++++++ .../common/mapbox/layers/arc-timeseries.tsx | 158 ++++++++++++++++++ .../components/common/mapbox/layers/utils.ts | 6 + parcel-resolver-veda/index.d.ts | 2 +- 4 files changed, 212 insertions(+), 1 deletion(-) create mode 100644 app/scripts/components/common/mapbox/layers/arc-timeseries.tsx diff --git a/app/scripts/components/common/map/style-generators/hooks.ts b/app/scripts/components/common/map/style-generators/hooks.ts index 5fbbe1830..22ba150a9 100644 --- a/app/scripts/components/common/map/style-generators/hooks.ts +++ b/app/scripts/components/common/map/style-generators/hooks.ts @@ -13,6 +13,17 @@ interface ZarrResponseData { } } } +interface Link { + href: string, + rel: string, + type: string, + title: string, + "wms:layers": Array, + "wms:styles": Array +} +interface ArcResponseData { + links: Array +} interface CMRResponseData { features: { assets: { @@ -110,4 +121,40 @@ export function useCMR({ id, stacCol, stacApiEndpointToUse, date, assetUrlReplac return assetUrl; +} + +export function useArc({ id, stacCol, stacApiEndpointToUse, date, onStatusChange }){ + const [wmsUrl, setWmsUrl] = useState(''); + + useEffect(() => { + const controller = new AbortController(); + + async function load() { + try { + onStatusChange?.({ status: S_LOADING, id }); + const data:ArcResponseData = await requestQuickCache({ + url: `${stacApiEndpointToUse}/collections/${stacCol}`, + method: 'GET', + controller + }); + + setWmsUrl(data.links[0].href); + onStatusChange?.({ status: S_SUCCEEDED, id }); + } catch (error) { + if (!controller.signal.aborted) { + setWmsUrl(''); + onStatusChange?.({ status: S_FAILED, id }); + } + return; + } + } + + load(); + + return () => { + controller.abort(); + }; + }, [id, stacCol, stacApiEndpointToUse, date, onStatusChange]); + + return wmsUrl; } \ No newline at end of file diff --git a/app/scripts/components/common/mapbox/layers/arc-timeseries.tsx b/app/scripts/components/common/mapbox/layers/arc-timeseries.tsx new file mode 100644 index 000000000..7ee5a6ce5 --- /dev/null +++ b/app/scripts/components/common/mapbox/layers/arc-timeseries.tsx @@ -0,0 +1,158 @@ +import React, { useEffect, useMemo } from 'react'; +import qs from 'qs'; +import { RasterSource, RasterLayer } from 'mapbox-gl'; + +import { useMapStyle } from './styles'; +import { useArc } from '$components/common/map/style-generators/hooks'; + +import { ActionStatus } from '$utils/status'; + +export interface MapLayerArcTimeseriesProps { + id: string; + stacCol: string; + date?: Date; + sourceParams?: Record; + stacApiEndpoint?: string; + tileApiEndpoint?: string; + zoomExtent?: number[]; + onStatusChange?: (result: { status: ActionStatus; id: string }) => void; + isHidden?: boolean; + idSuffix?: string; +} + +interface ArcPaintLayerProps { + id: string; + date?: Date; + sourceParams?: Record; + tileApiEndpoint?: string; + zoomExtent?: number[]; + isHidden?: boolean; + idSuffix?: string; + wmsUrl: string; +} + +export function ArcPaintLayer(props: ArcPaintLayerProps) { + const { + id, + tileApiEndpoint, + date, + sourceParams, + zoomExtent, + isHidden, + wmsUrl, + idSuffix = '' + } = props; + + const { updateStyle } = useMapStyle(); + + const [minZoom] = zoomExtent ?? [0, 20]; + + const generatorId = 'arc-timeseries' + idSuffix; + + // Generate Mapbox GL layers and sources for raster timeseries + // + const haveSourceParamsChanged = useMemo( + () => JSON.stringify(sourceParams), + [sourceParams] + ); + + useEffect( + () => { + if (!wmsUrl) return; + //https://arcgis.asdc.larc.nasa.gov/server/services/POWER/power_901_annual_meterology_utc/ImageServer/WMSServer + // ?bbox={bbox-epsg-3857}&format=image/png&service=WMS&version=1.1.1&request=GetMap&srs=EPSG:3857&transparent=true&width=256&height=256&LAYERS=PS&DIM_StdTime=1981-12-31T00:00:00Z" + + // TODO: investigate For some reason the request being made is 6 hours ahead? Something to do with UTC <-> local conversion? + date?.setHours(date.getHours() - 6) + + const tileParams = qs.stringify({ + format: 'image/png', + service: "WMS", + version: "1.1.1", + request: "GetMap", + srs: "EPSG:3857", + transparent: "true", // TODO: get from sourceparams maybe + width: "256", + height: "256", + DIM_StdTime: `${date?.toISOString().slice(0, -5)}Z`, // TODO: better date conversion + ...sourceParams + }); + + const arcSource: RasterSource = { + type: 'raster', + tiles: [`${wmsUrl}?${tileParams}&bbox={bbox-epsg-3857}`] + }; + + const arcLayer: RasterLayer = { + id: id, + type: 'raster', + source: id, + layout: { + visibility: isHidden ? 'none' : 'visible' + }, + paint: { + 'raster-opacity': Number(!isHidden), + 'raster-opacity-transition': { + duration: 320 + } + }, + minzoom: minZoom, + metadata: { + layerOrderPosition: 'raster' + } + }; + + const sources = { + [id]: arcSource + }; + const layers = [arcLayer]; + + updateStyle({ + generatorId, + sources, + layers + }); + }, + // sourceParams not included, but using a stringified version of it to detect changes (haveSourceParamsChanged) + [ + updateStyle, + id, + date, + wmsUrl, + minZoom, + haveSourceParamsChanged, + isHidden, + generatorId, + tileApiEndpoint + ] + ); + + // + // Cleanup layers on unmount. + // + useEffect(() => { + return () => { + updateStyle({ + generatorId, + sources: {}, + layers: [] + }); + }; + }, [updateStyle, generatorId]); + + return null; +} + +export function MapLayerArcTimeseries(props:MapLayerArcTimeseriesProps) { + const { + id, + stacCol, + stacApiEndpoint, + date, + onStatusChange, + } = props; + + const stacApiEndpointToUse = stacApiEndpoint?? process.env.API_STAC_ENDPOINT; + const wmsUrl = useArc({id, stacCol, stacApiEndpointToUse, date, onStatusChange}); + return ; +} diff --git a/app/scripts/components/common/mapbox/layers/utils.ts b/app/scripts/components/common/mapbox/layers/utils.ts index b8a310dc8..cf5ded817 100644 --- a/app/scripts/components/common/mapbox/layers/utils.ts +++ b/app/scripts/components/common/mapbox/layers/utils.ts @@ -37,6 +37,10 @@ import { MapLayerCMRTimeseries, MapLayerCMRTimeseriesProps } from './cmr-timeseries'; +import { + MapLayerArcTimeseries, + MapLayerArcTimeseriesProps +} from './arc-timeseries'; import { userTzDate2utcString, utcString2userTzDate } from '$utils/date'; import { AsyncDatasetLayer } from '$context/layer-data'; @@ -51,12 +55,14 @@ export const getLayerComponent = ( | MapLayerVectorTimeseriesProps | MapLayerZarrTimeseriesProps | MapLayerCMRTimeseriesProps + | MapLayerArcTimeseriesProps > | null => { if (isTimeseries) { if (layerType === 'raster') return MapLayerRasterTimeseries; if (layerType === 'vector') return MapLayerVectorTimeseries; if (layerType === 'zarr') return MapLayerZarrTimeseries; if (layerType === 'cmr') return MapLayerCMRTimeseries; + if (layerType === 'arc') return MapLayerArcTimeseries; } return null; diff --git a/parcel-resolver-veda/index.d.ts b/parcel-resolver-veda/index.d.ts index 893801aac..de2bd268e 100644 --- a/parcel-resolver-veda/index.d.ts +++ b/parcel-resolver-veda/index.d.ts @@ -7,7 +7,7 @@ declare module 'veda' { // /////////////////////////////////////////////////////////////////////////// // Datasets // // /////////////////////////////////////////////////////////////////////////// - type DatasetLayerType = 'raster' | 'vector' | 'zarr'| 'cmr'; + type DatasetLayerType = 'raster' | 'vector' | 'zarr'| 'cmr' | 'arc'; // // Dataset Layers From 4359ef4d73149f68a82784b8d043ef5536b82a95 Mon Sep 17 00:00:00 2001 From: Slesa Adhikari Date: Wed, 13 Mar 2024 17:59:17 -0500 Subject: [PATCH 02/23] Add analysis support for arcgis imageserver dataset --- .../analysis/results/timeseries-data.ts | 249 +++++++++++------- 1 file changed, 148 insertions(+), 101 deletions(-) diff --git a/app/scripts/components/analysis/results/timeseries-data.ts b/app/scripts/components/analysis/results/timeseries-data.ts index 2a5ea4396..c46373624 100644 --- a/app/scripts/components/analysis/results/timeseries-data.ts +++ b/app/scripts/components/analysis/results/timeseries-data.ts @@ -8,27 +8,30 @@ import { getFilterPayload, combineFeatureCollection } from '../utils'; import EventEmitter from './mini-events'; import { ConcurrencyManager, ConcurrencyManagerInstance } from './concurrency'; import { TimeDensity } from '$context/layer-data'; +import { userTzDate2utcString } from '$utils/date'; + export const TIMESERIES_DATA_BASE_ID = 'analysis'; +// ArcGIS ImageServer doesn't give back all these values export interface TimeseriesDataUnit { date: string; - min: number; - max: number; + min?: number; + max?: number; mean: number; - count: number; - sum: number; - std: number; - median: number; - majority: number; - minority: number; - unique: number; - histogram: [number[], number[]]; - valid_percent: number; - masked_pixels: number; - valid_pixels: number; - percentile_2: number; - percentile_98: number; + count?: number; + sum?: number; + std?: number; + median?: number; + majority?: number; + minority?: number; + unique?: number; + histogram?: [number[], number[]]; + valid_percent?: number; + masked_pixels?: number; + valid_pixels?: number; + percentile_2?: number; + percentile_98?: number; } export interface TimeseriesDataResult { @@ -247,97 +250,141 @@ async function requestTimeseries({ // attached yet. setTimeout(() => onData(layersBase), 0); + // TODO: Maybe there's a better way than an if else conditional? try { - const layerInfoFromSTAC = await queryClient.fetchQuery( - [TIMESERIES_DATA_BASE_ID, 'dataset', id, aoi, start, end], - ({ signal }) => - getDatasetAssets( - { - stacCol: layer.stacCol, - stacApiEndpoint: layer.stacApiEndpoint, - assets: layer.sourceParams?.assets || 'cog_default', - aoi, - dateStart: start, - dateEnd: end - }, - { signal }, - concurrencyManager - ), - { - staleTime: Infinity - } - ); - const { assets, ...otherCollectionProps } = layerInfoFromSTAC; - - if (assets.length > MAX_QUERY_NUM) - throw Error( - `Too many requests. We currently only allow requests up to ${MAX_QUERY_NUM} and this analysis requires ${assets.length} requests.` - ); - - onData({ - ...layersBase, - status: 'loading', - meta: { - total: assets.length, - loaded: 0 + if (layer.type === "arc") { + const params = { + collection_id: layer.stacCol, + variable: layer.sourceParams?.layers, + datetime_range: `${`${userTzDate2utcString(start).slice(0, -5)}Z`},${`${userTzDate2utcString(end).slice(0, -5)}Z`}`, + aoi: aoi } - }); - - const tileEndpointToUse = - layer.tileApiEndpoint ?? process.env.API_RASTER_ENDPOINT; - - const analysisParams = layersBase.layer.analysis?.sourceParams ?? {}; + const statistics = await queryClient.fetchQuery( + [TIMESERIES_DATA_BASE_ID, 'dataset', id], + async ({ signal }) => { + return concurrencyManager.queue(async () => { + const { data } = await axios.post( + `${layer.tileApiEndpoint}/statistics`, + params, + { signal } + ); + return data; + }); + }, + { + staleTime: Infinity + } + ); - const layerStatistics = await Promise.all( - assets.map(async ({ date, url }) => { - const statistics = await queryClient.fetchQuery( - [TIMESERIES_DATA_BASE_ID, 'asset', url], - async ({ signal }) => { - return concurrencyManager.queue(async () => { - const { data } = await axios.post( - `${tileEndpointToUse}/cog/statistics?url=${url}`, - // Making a request with a FC causes a 500 (as of 2023/01/20) - combineFeatureCollection(aoi), - { params: { ...analysisParams, url }, signal } - ); - return { - date, - // Remove 1 when https://github.com/NASA-IMPACT/veda-ui/issues/572 is fixed. - ...(data.properties.statistics.b1 || - data.properties.statistics['1']) - }; - }); - }, - { - staleTime: Infinity - } + console.log(statistics) + + onData({ + ...layersBase, + status: 'succeeded', + meta: { + total: statistics.length, + loaded: statistics.length + }, + data: { + // ...otherCollectionProps, + // TODO: Get these from the API instead + isPeriodic: false, + timeDensity: "year", + domain: ['1983-01-01T00:00:00Z', '2022-12-31T23:59:59Z'], + timeseries: statistics.slice(0, 4) // TODO: FIX: For some reason the UI freezes for more than 4 timestamps + } + }); + } else { + const layerInfoFromSTAC = await queryClient.fetchQuery( + [TIMESERIES_DATA_BASE_ID, 'dataset', id, aoi, start, end], + ({ signal }) => + getDatasetAssets( + { + stacCol: layer.stacCol, + stacApiEndpoint: layer.stacApiEndpoint, + assets: layer.sourceParams?.assets || 'cog_default', + aoi, + dateStart: start, + dateEnd: end + }, + { signal }, + concurrencyManager + ), + { + staleTime: Infinity + } + ); + const { assets, ...otherCollectionProps } = layerInfoFromSTAC; + + if (assets.length > MAX_QUERY_NUM) + throw Error( + `Too many requests. We currently only allow requests up to ${MAX_QUERY_NUM} and this analysis requires ${assets.length} requests.` ); - - onData({ - ...layersBase, - meta: { - total: assets.length, - loaded: (layersBase.meta.loaded ?? 0) + 1 - } - }); - - return statistics; - }) - ); - - onData({ - ...layersBase, - status: 'succeeded', - meta: { - total: assets.length, - loaded: assets.length - }, - data: { - ...otherCollectionProps, - timeseries: layerStatistics - } - }); + + onData({ + ...layersBase, + status: 'loading', + meta: { + total: assets.length, + loaded: 0 + } + }); + + const tileEndpointToUse = + layer.tileApiEndpoint ?? process.env.API_RASTER_ENDPOINT; + + const analysisParams = layersBase.layer.analysis?.sourceParams ?? {}; + + const layerStatistics = await Promise.all( + assets.map(async ({ date, url }) => { + const statistics = await queryClient.fetchQuery( + [TIMESERIES_DATA_BASE_ID, 'asset', url], + async ({ signal }) => { + return concurrencyManager.queue(async () => { + const { data } = await axios.post( + `${tileEndpointToUse}/cog/statistics?url=${url}`, + // Making a request with a FC causes a 500 (as of 2023/01/20) + combineFeatureCollection(aoi), + { params: { ...analysisParams, url }, signal } + ); + return { + date, + // Remove 1 when https://github.com/NASA-IMPACT/veda-ui/issues/572 is fixed. + ...(data.properties.statistics.b1 || + data.properties.statistics['1']) + }; + }); + }, + { + staleTime: Infinity + } + ); + + onData({ + ...layersBase, + meta: { + total: assets.length, + loaded: (layersBase.meta.loaded ?? 0) + 1 + } + }); + + return statistics; + }) + ); + onData({ + ...layersBase, + status: 'succeeded', + meta: { + total: assets.length, + loaded: assets.length + }, + data: { + ...otherCollectionProps, + timeseries: layerStatistics + } + }); + } } catch (error) { // Discard abort related errors. if (error.revert) return; From eca2490b46fc1ec67510dce89020d31b4c6c4217 Mon Sep 17 00:00:00 2001 From: Slesa Adhikari Date: Wed, 13 Mar 2024 17:59:33 -0500 Subject: [PATCH 03/23] Add example argis imageserver dataset --- mock/datasets/power_meteorology.data.mdx | 106 +++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 mock/datasets/power_meteorology.data.mdx diff --git a/mock/datasets/power_meteorology.data.mdx b/mock/datasets/power_meteorology.data.mdx new file mode 100644 index 000000000..93c53c048 --- /dev/null +++ b/mock/datasets/power_meteorology.data.mdx @@ -0,0 +1,106 @@ +--- +id: power_901_annual_meterology_utc +name: 'POWER meteorology' +featured: true +description: "Meteorology" +media: + src: ::file ./no2--dataset-cover.jpg + alt: Power plant shooting steam at the sky. + author: + name: Mick Truyts + url: https://unsplash.com/photos/x6WQeNYJC1w +taxonomy: + - name: Topics + values: + - Air Quality +layers: + - id: cdd10 + stacApiEndpoint: http://localhost:8000 + tileApiEndpoint: http://localhost:8000 + stacCol: POWER/power_901_annual_meterology_utc + name: Cooling Degree Days Above 10 C + type: arc + description: + "Lorem Ipsum" + zoomExtent: + - 0 + - 20 + sourceParams: + layers: CDD10 + legend: + unit: + label: degree-day + type: gradient + min: 0 + max: 8972.0625 + stops: + - "#4575b4" + - "#91bfdb" + - "#e0f3f8" + - "#ffffbf" + - "#fee090" + - "#fc8d59" + - "#d73027" + # analysis: + # exclude: true + - id: cdd18_3 + stacApiEndpoint: http://localhost:8000 + tileApiEndpoint: http://localhost:8000 + stacCol: POWER/power_901_annual_meterology_utc + name: Cooling Degree Days Above 18.3 C + type: arc + description: + "Lorem Ipsum" + zoomExtent: + - 0 + - 20 + sourceParams: + layers: CDD18_3 + # TODO: get this from `/legend` endpoint? ex - https://arcgis.asdc.larc.nasa.gov/server/rest/services/POWER/power_901_annual_meterology_utc/ImageServer/legend + legend: + unit: + label: degree-day + type: gradient + min: 0 + max: 8972.0625 + stops: + - "#4575b4" + - "#91bfdb" + - "#e0f3f8" + - "#ffffbf" + - "#fee090" + - "#fc8d59" + - "#d73027" + # analysis: + # exclude: true + - id: power_901_annual_meterology_utc_DISPH + stacApiEndpoint: http://localhost:8000 + tileApiEndpoint: http://localhost:8000 + stacCol: POWER/power_901_annual_meterology_utc + name: Zero Plane Displacement Height + type: arc + description: + "Lorem Ipsum" + zoomExtent: + - 0 + - 20 + sourceParams: + layers: DISPH + legend: + unit: + label: m + type: gradient + min: 0 + max: 8972.0625 + stops: + - "#4575b4" + - "#91bfdb" + - "#e0f3f8" + - "#ffffbf" + - "#fee090" + - "#fc8d59" + - "#d73027" + # analysis: + # exclude: true +--- + From 9774a90f3515cb6694d9ef90a8371bf12027a303 Mon Sep 17 00:00:00 2001 From: Slesa Adhikari Date: Thu, 14 Mar 2024 11:49:45 -0500 Subject: [PATCH 04/23] Update stac/tile urls --- mock/datasets/power_meteorology.data.mdx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mock/datasets/power_meteorology.data.mdx b/mock/datasets/power_meteorology.data.mdx index 93c53c048..376fbf1e9 100644 --- a/mock/datasets/power_meteorology.data.mdx +++ b/mock/datasets/power_meteorology.data.mdx @@ -15,8 +15,8 @@ taxonomy: - Air Quality layers: - id: cdd10 - stacApiEndpoint: http://localhost:8000 - tileApiEndpoint: http://localhost:8000 + stacApiEndpoint: https://hh76k5rqdh.execute-api.us-west-2.amazonaws.com/dev + tileApiEndpoint: https://hh76k5rqdh.execute-api.us-west-2.amazonaws.com/dev stacCol: POWER/power_901_annual_meterology_utc name: Cooling Degree Days Above 10 C type: arc @@ -44,8 +44,8 @@ layers: # analysis: # exclude: true - id: cdd18_3 - stacApiEndpoint: http://localhost:8000 - tileApiEndpoint: http://localhost:8000 + stacApiEndpoint: https://hh76k5rqdh.execute-api.us-west-2.amazonaws.com/dev + tileApiEndpoint: https://hh76k5rqdh.execute-api.us-west-2.amazonaws.com/dev stacCol: POWER/power_901_annual_meterology_utc name: Cooling Degree Days Above 18.3 C type: arc @@ -74,8 +74,8 @@ layers: # analysis: # exclude: true - id: power_901_annual_meterology_utc_DISPH - stacApiEndpoint: http://localhost:8000 - tileApiEndpoint: http://localhost:8000 + stacApiEndpoint: https://hh76k5rqdh.execute-api.us-west-2.amazonaws.com/dev + tileApiEndpoint: https://hh76k5rqdh.execute-api.us-west-2.amazonaws.com/dev stacCol: POWER/power_901_annual_meterology_utc name: Zero Plane Displacement Height type: arc From 5977725920c1fb3e9c2d59c12a35aae1f71baed4 Mon Sep 17 00:00:00 2001 From: Slesa Adhikari Date: Thu, 14 Mar 2024 12:13:00 -0500 Subject: [PATCH 05/23] Add change to retrigger deploy preview --- mock/datasets/power_meteorology.data.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mock/datasets/power_meteorology.data.mdx b/mock/datasets/power_meteorology.data.mdx index 376fbf1e9..8175c04fa 100644 --- a/mock/datasets/power_meteorology.data.mdx +++ b/mock/datasets/power_meteorology.data.mdx @@ -21,7 +21,7 @@ layers: name: Cooling Degree Days Above 10 C type: arc description: - "Lorem Ipsum" + "Test" zoomExtent: - 0 - 20 From ad678d95028c771216580eca9dfee37ab0cc7cdb Mon Sep 17 00:00:00 2001 From: Slesa Adhikari Date: Thu, 14 Mar 2024 13:02:48 -0500 Subject: [PATCH 06/23] Add compare to arc layers --- mock/datasets/power_meteorology.data.mdx | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/mock/datasets/power_meteorology.data.mdx b/mock/datasets/power_meteorology.data.mdx index 8175c04fa..fe25ef5f9 100644 --- a/mock/datasets/power_meteorology.data.mdx +++ b/mock/datasets/power_meteorology.data.mdx @@ -27,6 +27,13 @@ layers: - 20 sourceParams: layers: CDD10 + compare: + datasetId: power_901_annual_meterology_utc + layerId: power_901_annual_meterology_utc_DISPH + mapLabel: | + ::js ({ dateFns, datetime, compareDatetime }) => { + return `${dateFns.format(datetime, 'LLL yyyy')} VS ${dateFns.format(compareDatetime, 'LLL yyyy')}`; + } legend: unit: label: degree-day @@ -57,6 +64,13 @@ layers: sourceParams: layers: CDD18_3 # TODO: get this from `/legend` endpoint? ex - https://arcgis.asdc.larc.nasa.gov/server/rest/services/POWER/power_901_annual_meterology_utc/ImageServer/legend + compare: + datasetId: power_901_annual_meterology_utc + layerId: cdd10 + mapLabel: | + ::js ({ dateFns, datetime, compareDatetime }) => { + return `${dateFns.format(datetime, 'LLL yyyy')} VS ${dateFns.format(compareDatetime, 'LLL yyyy')}`; + } legend: unit: label: degree-day @@ -86,6 +100,13 @@ layers: - 20 sourceParams: layers: DISPH + compare: + datasetId: power_901_annual_meterology_utc + layerId: power_901_annual_meterology_utc_DISPH + mapLabel: | + ::js ({ dateFns, datetime, compareDatetime }) => { + return `${dateFns.format(datetime, 'LLL yyyy')} VS ${dateFns.format(compareDatetime, 'LLL yyyy')}`; + } legend: unit: label: m From a4b71c4d5bb5d63c38974ea9595d90deeb44268d Mon Sep 17 00:00:00 2001 From: Slesa Adhikari Date: Wed, 27 Mar 2024 10:03:25 -0500 Subject: [PATCH 07/23] Get full statistics --- app/scripts/components/analysis/results/timeseries-data.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/scripts/components/analysis/results/timeseries-data.ts b/app/scripts/components/analysis/results/timeseries-data.ts index c46373624..5d928075d 100644 --- a/app/scripts/components/analysis/results/timeseries-data.ts +++ b/app/scripts/components/analysis/results/timeseries-data.ts @@ -277,8 +277,6 @@ async function requestTimeseries({ } ); - console.log(statistics) - onData({ ...layersBase, status: 'succeeded', @@ -292,7 +290,7 @@ async function requestTimeseries({ isPeriodic: false, timeDensity: "year", domain: ['1983-01-01T00:00:00Z', '2022-12-31T23:59:59Z'], - timeseries: statistics.slice(0, 4) // TODO: FIX: For some reason the UI freezes for more than 4 timestamps + timeseries: statistics // TODO: FIX: For some reason the UI freezes for more than 4 timestamps } }); } else { From 9802243bbf143d8df3a9863dc5aedeffe69af3d4 Mon Sep 17 00:00:00 2001 From: Slesa Adhikari Date: Wed, 27 Mar 2024 11:17:17 -0500 Subject: [PATCH 08/23] Fix datetime issue --- .../components/common/mapbox/layers/arc-timeseries.tsx | 7 +++---- app/scripts/utils/date.ts | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/app/scripts/components/common/mapbox/layers/arc-timeseries.tsx b/app/scripts/components/common/mapbox/layers/arc-timeseries.tsx index 7ee5a6ce5..4a795fa64 100644 --- a/app/scripts/components/common/mapbox/layers/arc-timeseries.tsx +++ b/app/scripts/components/common/mapbox/layers/arc-timeseries.tsx @@ -5,6 +5,7 @@ import { RasterSource, RasterLayer } from 'mapbox-gl'; import { useMapStyle } from './styles'; import { useArc } from '$components/common/map/style-generators/hooks'; +import { userTzDate2utcString } from '$utils/date'; import { ActionStatus } from '$utils/status'; export interface MapLayerArcTimeseriesProps { @@ -61,10 +62,8 @@ export function ArcPaintLayer(props: ArcPaintLayerProps) { if (!wmsUrl) return; //https://arcgis.asdc.larc.nasa.gov/server/services/POWER/power_901_annual_meterology_utc/ImageServer/WMSServer // ?bbox={bbox-epsg-3857}&format=image/png&service=WMS&version=1.1.1&request=GetMap&srs=EPSG:3857&transparent=true&width=256&height=256&LAYERS=PS&DIM_StdTime=1981-12-31T00:00:00Z" - + // TODO: investigate For some reason the request being made is 6 hours ahead? Something to do with UTC <-> local conversion? - date?.setHours(date.getHours() - 6) - const tileParams = qs.stringify({ format: 'image/png', service: "WMS", @@ -74,7 +73,7 @@ export function ArcPaintLayer(props: ArcPaintLayerProps) { transparent: "true", // TODO: get from sourceparams maybe width: "256", height: "256", - DIM_StdTime: `${date?.toISOString().slice(0, -5)}Z`, // TODO: better date conversion + DIM_StdTime: userTzDate2utcString(date), // TODO: better date conversion ...sourceParams }); diff --git a/app/scripts/utils/date.ts b/app/scripts/utils/date.ts index 1ff91fac0..2ae159f44 100644 --- a/app/scripts/utils/date.ts +++ b/app/scripts/utils/date.ts @@ -19,7 +19,7 @@ import { * * Basically it parses the date ignoring the timezone and treats it as if the * date is already in the user's Tz. - * Times I had timezone related bugs and this fn saved me: 7 + * Times I had timezone related bugs and this fn saved me: 8 * * Reverse function of userTzDate2utcString() * From 77ca62898eb2ad0003d53e235675a3c3c6dd6f94 Mon Sep 17 00:00:00 2001 From: Hanbyul Jo Date: Mon, 3 Jun 2024 11:06:29 -0500 Subject: [PATCH 09/23] Use ESI_4WK collection --- .../common/map/style-generators/hooks.ts | 11 +++++----- .../common/mapbox/layers/arc-timeseries.tsx | 21 +++++++++---------- mock/datasets/power_meteorology.data.mdx | 12 +++++------ 3 files changed, 21 insertions(+), 23 deletions(-) diff --git a/app/scripts/components/common/map/style-generators/hooks.ts b/app/scripts/components/common/map/style-generators/hooks.ts index 22ba150a9..e07f0b547 100644 --- a/app/scripts/components/common/map/style-generators/hooks.ts +++ b/app/scripts/components/common/map/style-generators/hooks.ts @@ -18,11 +18,11 @@ interface Link { rel: string, type: string, title: string, - "wms:layers": Array, - "wms:styles": Array + "wms:layers": string[], + "wms:styles": string[] } interface ArcResponseData { - links: Array + links: Link[] } interface CMRResponseData { features: { @@ -137,8 +137,9 @@ export function useArc({ id, stacCol, stacApiEndpointToUse, date, onStatusChange method: 'GET', controller }); - - setWmsUrl(data.links[0].href); + const wms = data.links.find(l => l.rel==='wms'); + if (wms) setWmsUrl(wms.href); + else throw new Error('no wms link'); onStatusChange?.({ status: S_SUCCEEDED, id }); } catch (error) { if (!controller.signal.aborted) { diff --git a/app/scripts/components/common/mapbox/layers/arc-timeseries.tsx b/app/scripts/components/common/mapbox/layers/arc-timeseries.tsx index 4a795fa64..1efe86259 100644 --- a/app/scripts/components/common/mapbox/layers/arc-timeseries.tsx +++ b/app/scripts/components/common/mapbox/layers/arc-timeseries.tsx @@ -5,7 +5,6 @@ import { RasterSource, RasterLayer } from 'mapbox-gl'; import { useMapStyle } from './styles'; import { useArc } from '$components/common/map/style-generators/hooks'; -import { userTzDate2utcString } from '$utils/date'; import { ActionStatus } from '$utils/status'; export interface MapLayerArcTimeseriesProps { @@ -60,26 +59,25 @@ export function ArcPaintLayer(props: ArcPaintLayerProps) { useEffect( () => { if (!wmsUrl) return; - //https://arcgis.asdc.larc.nasa.gov/server/services/POWER/power_901_annual_meterology_utc/ImageServer/WMSServer - // ?bbox={bbox-epsg-3857}&format=image/png&service=WMS&version=1.1.1&request=GetMap&srs=EPSG:3857&transparent=true&width=256&height=256&LAYERS=PS&DIM_StdTime=1981-12-31T00:00:00Z" - - // TODO: investigate For some reason the request being made is 6 hours ahead? Something to do with UTC <-> local conversion? + const tileParams = qs.stringify({ format: 'image/png', service: "WMS", - version: "1.1.1", + version: "1.3.0", request: "GetMap", - srs: "EPSG:3857", - transparent: "true", // TODO: get from sourceparams maybe + crs: "EPSG:3857", + transparent: "true", width: "256", height: "256", - DIM_StdTime: userTzDate2utcString(date), // TODO: better date conversion + layers: 1, + styles: '', ...sourceParams }); - + const arcSource: RasterSource = { type: 'raster', - tiles: [`${wmsUrl}?${tileParams}&bbox={bbox-epsg-3857}`] + tiles: [`${wmsUrl}?${tileParams}&bbox={bbox-epsg-3857}`], + tileSize: 256, }; const arcLayer: RasterLayer = { @@ -153,5 +151,6 @@ export function MapLayerArcTimeseries(props:MapLayerArcTimeseriesProps) { const stacApiEndpointToUse = stacApiEndpoint?? process.env.API_STAC_ENDPOINT; const wmsUrl = useArc({id, stacCol, stacApiEndpointToUse, date, onStatusChange}); + return ; } diff --git a/mock/datasets/power_meteorology.data.mdx b/mock/datasets/power_meteorology.data.mdx index fe25ef5f9..7bc7bf2ba 100644 --- a/mock/datasets/power_meteorology.data.mdx +++ b/mock/datasets/power_meteorology.data.mdx @@ -15,18 +15,16 @@ taxonomy: - Air Quality layers: - id: cdd10 - stacApiEndpoint: https://hh76k5rqdh.execute-api.us-west-2.amazonaws.com/dev - tileApiEndpoint: https://hh76k5rqdh.execute-api.us-west-2.amazonaws.com/dev - stacCol: POWER/power_901_annual_meterology_utc - name: Cooling Degree Days Above 10 C - type: arc + stacApiEndpoint: https://dev.openveda.cloud/api/stac + tileApiEndpoint: https://dev.openveda.cloud/api/stac + stacCol: ESI_4WK + name: Experimental + type: arc description: "Test" zoomExtent: - 0 - 20 - sourceParams: - layers: CDD10 compare: datasetId: power_901_annual_meterology_utc layerId: power_901_annual_meterology_utc_DISPH From c8dc5bad2ea276f1c2d9741977e0f6465023a8cb Mon Sep 17 00:00:00 2001 From: Hanbyul Jo Date: Tue, 4 Jun 2024 18:13:55 -0400 Subject: [PATCH 10/23] Replace wms sample data --- .../common/mapbox/layers/arc-timeseries.tsx | 15 +-- mock/datasets/esi_4wk.data.mdx | 55 ++++++++ mock/datasets/power_meteorology.data.mdx | 125 ------------------ 3 files changed, 62 insertions(+), 133 deletions(-) create mode 100644 mock/datasets/esi_4wk.data.mdx delete mode 100644 mock/datasets/power_meteorology.data.mdx diff --git a/app/scripts/components/common/mapbox/layers/arc-timeseries.tsx b/app/scripts/components/common/mapbox/layers/arc-timeseries.tsx index 1efe86259..9ae81da2a 100644 --- a/app/scripts/components/common/mapbox/layers/arc-timeseries.tsx +++ b/app/scripts/components/common/mapbox/layers/arc-timeseries.tsx @@ -62,14 +62,13 @@ export function ArcPaintLayer(props: ArcPaintLayerProps) { const tileParams = qs.stringify({ format: 'image/png', - service: "WMS", - version: "1.3.0", - request: "GetMap", - crs: "EPSG:3857", - transparent: "true", - width: "256", - height: "256", - layers: 1, + service: 'WMS', + version: '1.3.0', + request: 'GetMap', + crs: 'EPSG:3857', + transparent: 'true', + width: '256', + height: '256', styles: '', ...sourceParams }); diff --git a/mock/datasets/esi_4wk.data.mdx b/mock/datasets/esi_4wk.data.mdx new file mode 100644 index 000000000..2a6fec39f --- /dev/null +++ b/mock/datasets/esi_4wk.data.mdx @@ -0,0 +1,55 @@ +--- +id: esi_4wk +name: Global ESI_4WK +featured: true +description: The new global dataset, called the Evaporative Stress Index (ESI), available online and produced weekly at 5-kilometer resolution for the entire globe, reveals regions of drought where vegetation is stressed due to lack of water, enabling agriculture ministries to provide farmers with actionable advice about irrigation. +media: + src: ::file ./no2--dataset-cover.jpg + alt: Power plant shooting steam at the sky. + author: + name: Mick Truyts + url: https://unsplash.com/photos/x6WQeNYJC1w +infoDescription: | + ::markdown + The ESI can capture early signals of “flash drought,” a condition brought on by extended periods of hot, dry, and windy conditions leading to rapid soil moisture depletion. Reduced rates of water loss can be observed through the use of land surface temperature before it can be observed through decreases in vegetation health or “greenness.” The ESI describes soil moisture across the landscape without using observed rainfall data. This is critical in developing regions and other parts of the world lacking sufficient ground-based observations of rainfall. The ESI is based on satellite observations of land surface temperature, which are used to estimate water loss due to evapotranspiration (ET), the loss of water via evaporation from soil and plant surfaces and via transpiration through plant leaves. Generally, healthy green vegetation with access to an adequate supply of water warms at a much slower rate than does dry and/or stressed vegetation. Based on variations in land surface temperature, the ESI indicates how the current rate of ET compares to normal conditions. Negative ESI values show below normal ET rates, indicating vegetation that stressed due to inadequate soil moisture. (Plants’ first response when stressed from lack of water is to reduce their transpiration to conserve water within the plant.) +layers: + - id: esi_4wk_layer + stacApiEndpoint: https://dev.openveda.cloud/api/stac + tileApiEndpoint: https://dev.openveda.cloud/api/stac + stacCol: ESI_4WK + name: Evaporative Stress Index (ESI) + type: arc + description: The new global dataset, called the Evaporative Stress Index (ESI), available online and produced weekly at 5-kilometer resolution for the entire globe, reveals regions of drought where vegetation is stressed due to lack of water, enabling agriculture ministries to provide farmers with actionable advice about irrigation. + sourceParams: + layers: 1 + zoomExtent: + - 0 + - 20 + compare: + datasetId: power_901_annual_meterology_utc + layerId: power_901_annual_meterology_utc_DISPH + mapLabel: | + ::js ({ dateFns, datetime, compareDatetime }) => { + return `${dateFns.format(datetime, 'LLL yyyy')} VS ${dateFns.format(compareDatetime, 'LLL yyyy')}`; + } + legend: + type: gradient + min: -3.0 + max: 3.0 + stops: + - rgb(231,61,52) + - rgb(255,141,90) + - rgb(255,212,137) + - rgb(255,255,196) + - rgb(200,234,140) + - rgb(123,203,112) + - rgb(0,101,91) + - rgb(0,104, 59) +--- + + +The new global dataset, called the Evaporative Stress Index (ESI), available online and produced weekly at 5-kilometer resolution for the entire globe, reveals regions of drought where vegetation is stressed due to lack of water, enabling agriculture ministries to provide farmers with actionable advice about irrigation. The ESI can capture early signals of “flash drought,” a condition brought on by extended periods of hot, dry, and windy conditions leading to rapid soil moisture depletion. Reduced rates of water loss can be observed through the use of land surface temperature before it can be observed through decreases in vegetation health or “greenness.” The ESI describes soil moisture across the landscape without using observed rainfall data. This is critical in developing regions and other parts of the world lacking sufficient ground-based observations of rainfall. The ESI is based on satellite observations of land surface temperature, which are used to estimate water loss due to evapotranspiration (ET), the loss of water via evaporation from soil and plant surfaces and via transpiration through plant leaves. Generally, healthy green vegetation with access to an adequate supply of water warms at a much slower rate than does dry and/or stressed vegetation. Based on variations in land surface temperature, the ESI indicates how the current rate of ET compares to normal conditions. Negative ESI values show below normal ET rates, indicating vegetation that stressed due to inadequate soil moisture. (Plants’ first response when stressed from lack of water is to reduce their transpiration to conserve water within the plant.) + + + + \ No newline at end of file diff --git a/mock/datasets/power_meteorology.data.mdx b/mock/datasets/power_meteorology.data.mdx deleted file mode 100644 index 7bc7bf2ba..000000000 --- a/mock/datasets/power_meteorology.data.mdx +++ /dev/null @@ -1,125 +0,0 @@ ---- -id: power_901_annual_meterology_utc -name: 'POWER meteorology' -featured: true -description: "Meteorology" -media: - src: ::file ./no2--dataset-cover.jpg - alt: Power plant shooting steam at the sky. - author: - name: Mick Truyts - url: https://unsplash.com/photos/x6WQeNYJC1w -taxonomy: - - name: Topics - values: - - Air Quality -layers: - - id: cdd10 - stacApiEndpoint: https://dev.openveda.cloud/api/stac - tileApiEndpoint: https://dev.openveda.cloud/api/stac - stacCol: ESI_4WK - name: Experimental - type: arc - description: - "Test" - zoomExtent: - - 0 - - 20 - compare: - datasetId: power_901_annual_meterology_utc - layerId: power_901_annual_meterology_utc_DISPH - mapLabel: | - ::js ({ dateFns, datetime, compareDatetime }) => { - return `${dateFns.format(datetime, 'LLL yyyy')} VS ${dateFns.format(compareDatetime, 'LLL yyyy')}`; - } - legend: - unit: - label: degree-day - type: gradient - min: 0 - max: 8972.0625 - stops: - - "#4575b4" - - "#91bfdb" - - "#e0f3f8" - - "#ffffbf" - - "#fee090" - - "#fc8d59" - - "#d73027" - # analysis: - # exclude: true - - id: cdd18_3 - stacApiEndpoint: https://hh76k5rqdh.execute-api.us-west-2.amazonaws.com/dev - tileApiEndpoint: https://hh76k5rqdh.execute-api.us-west-2.amazonaws.com/dev - stacCol: POWER/power_901_annual_meterology_utc - name: Cooling Degree Days Above 18.3 C - type: arc - description: - "Lorem Ipsum" - zoomExtent: - - 0 - - 20 - sourceParams: - layers: CDD18_3 - # TODO: get this from `/legend` endpoint? ex - https://arcgis.asdc.larc.nasa.gov/server/rest/services/POWER/power_901_annual_meterology_utc/ImageServer/legend - compare: - datasetId: power_901_annual_meterology_utc - layerId: cdd10 - mapLabel: | - ::js ({ dateFns, datetime, compareDatetime }) => { - return `${dateFns.format(datetime, 'LLL yyyy')} VS ${dateFns.format(compareDatetime, 'LLL yyyy')}`; - } - legend: - unit: - label: degree-day - type: gradient - min: 0 - max: 8972.0625 - stops: - - "#4575b4" - - "#91bfdb" - - "#e0f3f8" - - "#ffffbf" - - "#fee090" - - "#fc8d59" - - "#d73027" - # analysis: - # exclude: true - - id: power_901_annual_meterology_utc_DISPH - stacApiEndpoint: https://hh76k5rqdh.execute-api.us-west-2.amazonaws.com/dev - tileApiEndpoint: https://hh76k5rqdh.execute-api.us-west-2.amazonaws.com/dev - stacCol: POWER/power_901_annual_meterology_utc - name: Zero Plane Displacement Height - type: arc - description: - "Lorem Ipsum" - zoomExtent: - - 0 - - 20 - sourceParams: - layers: DISPH - compare: - datasetId: power_901_annual_meterology_utc - layerId: power_901_annual_meterology_utc_DISPH - mapLabel: | - ::js ({ dateFns, datetime, compareDatetime }) => { - return `${dateFns.format(datetime, 'LLL yyyy')} VS ${dateFns.format(compareDatetime, 'LLL yyyy')}`; - } - legend: - unit: - label: m - type: gradient - min: 0 - max: 8972.0625 - stops: - - "#4575b4" - - "#91bfdb" - - "#e0f3f8" - - "#ffffbf" - - "#fee090" - - "#fc8d59" - - "#d73027" - # analysis: - # exclude: true ---- - From 8f88fc3033eecc959936f9699e2a6cd3124e8566 Mon Sep 17 00:00:00 2001 From: Hanbyul Jo Date: Wed, 5 Jun 2024 14:33:58 -0400 Subject: [PATCH 11/23] Add Arc layer for new E&A page --- .../common/map/style-generators/arc.tsx | 157 ++++++++++++++++++ .../common/map/style-generators/hooks.ts | 4 +- .../map/style-generators/zarr-timeseries.tsx | 15 +- .../layers/{arc-timeseries.tsx => arc.tsx} | 17 +- .../components/common/mapbox/layers/utils.ts | 10 +- .../exploration/components/map/layer.tsx | 26 ++- mock/datasets/esi_4wk.data.mdx | 10 +- mock/datasets/sandbox.data.mdx | 2 + 8 files changed, 201 insertions(+), 40 deletions(-) create mode 100644 app/scripts/components/common/map/style-generators/arc.tsx rename app/scripts/components/common/mapbox/layers/{arc-timeseries.tsx => arc.tsx} (88%) diff --git a/app/scripts/components/common/map/style-generators/arc.tsx b/app/scripts/components/common/map/style-generators/arc.tsx new file mode 100644 index 000000000..790694da7 --- /dev/null +++ b/app/scripts/components/common/map/style-generators/arc.tsx @@ -0,0 +1,157 @@ +import React, { useEffect, useMemo } from 'react'; +import qs from 'qs'; +import { RasterSource, RasterLayer } from 'mapbox-gl'; + +import useGeneratorParams from '../hooks/use-generator-params'; +import useMapStyle from '../hooks/use-map-style'; +import { BaseGeneratorParams } from '../types'; + +import { useArc } from '$components/common/map/style-generators/hooks'; +import { ActionStatus } from '$utils/status'; + +// @NOTE: ArcGIS Layer doens't have a timestamp +export interface MapLayerArcProps extends BaseGeneratorParams { + id: string; + stacCol: string; + sourceParams?: Record; + stacApiEndpoint?: string; + zoomExtent?: number[]; + onStatusChange?: (result: { status: ActionStatus; id: string }) => void; +} + +interface ArcPaintLayerProps extends BaseGeneratorParams{ + id: string; + sourceParams?: Record; + zoomExtent?: number[]; + wmsUrl: string; +} + +export function ArcPaintLayer(props: ArcPaintLayerProps) { + const { + id, + sourceParams, + zoomExtent, + wmsUrl, + generatorOrder, + hidden, + opacity + } = props; + + const { updateStyle } = useMapStyle(); + + const [minZoom] = zoomExtent ?? [0, 20]; + + const generatorId = 'arc-' + id; + + const generatorParams = useGeneratorParams( {generatorOrder, hidden, opacity }); + + // Generate Mapbox GL layers and sources for raster layer + // + const haveSourceParamsChanged = useMemo( + () => JSON.stringify(sourceParams), + [sourceParams] + ); + + useEffect( + () => { + if (!wmsUrl) return; + + const tileParams = qs.stringify({ + format: 'image/png', + service: 'WMS', + version: '1.3.0', + request: 'GetMap', + crs: 'EPSG:3857', + transparent: 'true', + width: '256', + height: '256', + styles: '', + ...sourceParams + }); + + const arcSource: RasterSource = { + type: 'raster', + tiles: [`${wmsUrl}?${tileParams}&bbox={bbox-epsg-3857}`], + tileSize: 256, + }; + + const rasterOpacity = typeof opacity === 'number' ? opacity / 100 : 1; + + const arcLayer: 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: '', + wmtsTileUrl: `${wmsUrl}?${tileParams}` + } + }; + + const sources = { + [id]: arcSource + }; + const layers = [arcLayer]; + + updateStyle({ + generatorId, + sources, + layers, + params: generatorParams + }); + }, + // sourceParams not included, but using a stringified version of it to detect changes (haveSourceParamsChanged) + [ + updateStyle, + id, + wmsUrl, + minZoom, + haveSourceParamsChanged, + hidden, + opacity, + generatorId, + generatorParams, + sourceParams + ] + ); + + // + // Cleanup layers on unmount. + // + useEffect(() => { + return () => { + updateStyle({ + generatorId, + sources: {}, + layers: [] + }); + }; + }, [updateStyle, generatorId]); + + return null; +} + +export function Arc(props:MapLayerArcProps) { + const { + id, + stacCol, + stacApiEndpoint, + onStatusChange, + } = props; + + const stacApiEndpointToUse = stacApiEndpoint?? process.env.API_STAC_ENDPOINT; + const wmsUrl = useArc({id, stacCol, stacApiEndpointToUse, onStatusChange}); + + return ; +} diff --git a/app/scripts/components/common/map/style-generators/hooks.ts b/app/scripts/components/common/map/style-generators/hooks.ts index e07f0b547..d204dc7c0 100644 --- a/app/scripts/components/common/map/style-generators/hooks.ts +++ b/app/scripts/components/common/map/style-generators/hooks.ts @@ -123,7 +123,7 @@ export function useCMR({ id, stacCol, stacApiEndpointToUse, date, assetUrlReplac } -export function useArc({ id, stacCol, stacApiEndpointToUse, date, onStatusChange }){ +export function useArc({ id, stacCol, stacApiEndpointToUse, onStatusChange }){ const [wmsUrl, setWmsUrl] = useState(''); useEffect(() => { @@ -155,7 +155,7 @@ export function useArc({ id, stacCol, stacApiEndpointToUse, date, onStatusChange return () => { controller.abort(); }; - }, [id, stacCol, stacApiEndpointToUse, date, onStatusChange]); + }, [id, stacCol, stacApiEndpointToUse, onStatusChange]); return wmsUrl; } \ No newline at end of file diff --git a/app/scripts/components/common/map/style-generators/zarr-timeseries.tsx b/app/scripts/components/common/map/style-generators/zarr-timeseries.tsx index 38243442d..026103f4b 100644 --- a/app/scripts/components/common/map/style-generators/zarr-timeseries.tsx +++ b/app/scripts/components/common/map/style-generators/zarr-timeseries.tsx @@ -105,17 +105,16 @@ export function ZarrPaintLayer(props: ZarrPaintLayerProps) { [ updateStyle, id, - date, assetUrl, - minZoom, + date, tileApiEndpoint, + minZoom, haveSourceParamsChanged, - generatorParams - // generatorParams includes hidden and opacity - // hidden, - // opacity, - // generatorId, // - dependent on id - // sourceParams, // tracked by haveSourceParamsChanged + hidden, + opacity, + generatorId, + generatorParams, + sourceParams ] ); diff --git a/app/scripts/components/common/mapbox/layers/arc-timeseries.tsx b/app/scripts/components/common/mapbox/layers/arc.tsx similarity index 88% rename from app/scripts/components/common/mapbox/layers/arc-timeseries.tsx rename to app/scripts/components/common/mapbox/layers/arc.tsx index 9ae81da2a..990884ad9 100644 --- a/app/scripts/components/common/mapbox/layers/arc-timeseries.tsx +++ b/app/scripts/components/common/mapbox/layers/arc.tsx @@ -7,13 +7,12 @@ import { useArc } from '$components/common/map/style-generators/hooks'; import { ActionStatus } from '$utils/status'; -export interface MapLayerArcTimeseriesProps { +// @NOTE: ArcGIS Layer doens't have a timestamp +export interface MapLayerArcProps { id: string; stacCol: string; - date?: Date; sourceParams?: Record; stacApiEndpoint?: string; - tileApiEndpoint?: string; zoomExtent?: number[]; onStatusChange?: (result: { status: ActionStatus; id: string }) => void; isHidden?: boolean; @@ -24,7 +23,6 @@ interface ArcPaintLayerProps { id: string; date?: Date; sourceParams?: Record; - tileApiEndpoint?: string; zoomExtent?: number[]; isHidden?: boolean; idSuffix?: string; @@ -34,7 +32,6 @@ interface ArcPaintLayerProps { export function ArcPaintLayer(props: ArcPaintLayerProps) { const { id, - tileApiEndpoint, date, sourceParams, zoomExtent, @@ -47,7 +44,7 @@ export function ArcPaintLayer(props: ArcPaintLayerProps) { const [minZoom] = zoomExtent ?? [0, 20]; - const generatorId = 'arc-timeseries' + idSuffix; + const generatorId = 'arc-' + idSuffix; // Generate Mapbox GL layers and sources for raster timeseries // @@ -118,8 +115,7 @@ export function ArcPaintLayer(props: ArcPaintLayerProps) { minZoom, haveSourceParamsChanged, isHidden, - generatorId, - tileApiEndpoint + generatorId ] ); @@ -139,17 +135,16 @@ export function ArcPaintLayer(props: ArcPaintLayerProps) { return null; } -export function MapLayerArcTimeseries(props:MapLayerArcTimeseriesProps) { +export function MapLayerArc(props:MapLayerArcProps) { const { id, stacCol, stacApiEndpoint, - date, onStatusChange, } = props; const stacApiEndpointToUse = stacApiEndpoint?? process.env.API_STAC_ENDPOINT; - const wmsUrl = useArc({id, stacCol, stacApiEndpointToUse, date, onStatusChange}); + const wmsUrl = useArc({id, stacCol, stacApiEndpointToUse, onStatusChange}); return ; } diff --git a/app/scripts/components/common/mapbox/layers/utils.ts b/app/scripts/components/common/mapbox/layers/utils.ts index cf5ded817..e9000795d 100644 --- a/app/scripts/components/common/mapbox/layers/utils.ts +++ b/app/scripts/components/common/mapbox/layers/utils.ts @@ -38,9 +38,9 @@ import { MapLayerCMRTimeseriesProps } from './cmr-timeseries'; import { - MapLayerArcTimeseries, - MapLayerArcTimeseriesProps -} from './arc-timeseries'; + MapLayerArc, + MapLayerArcProps +} from './arc'; import { userTzDate2utcString, utcString2userTzDate } from '$utils/date'; import { AsyncDatasetLayer } from '$context/layer-data'; @@ -55,14 +55,14 @@ export const getLayerComponent = ( | MapLayerVectorTimeseriesProps | MapLayerZarrTimeseriesProps | MapLayerCMRTimeseriesProps - | MapLayerArcTimeseriesProps + | MapLayerArcProps > | null => { if (isTimeseries) { if (layerType === 'raster') return MapLayerRasterTimeseries; if (layerType === 'vector') return MapLayerVectorTimeseries; if (layerType === 'zarr') return MapLayerZarrTimeseries; if (layerType === 'cmr') return MapLayerCMRTimeseries; - if (layerType === 'arc') return MapLayerArcTimeseries; + if (layerType === 'arc') return MapLayerArc; } return null; diff --git a/app/scripts/components/exploration/components/map/layer.tsx b/app/scripts/components/exploration/components/map/layer.tsx index d2727abda..8b411df68 100644 --- a/app/scripts/components/exploration/components/map/layer.tsx +++ b/app/scripts/components/exploration/components/map/layer.tsx @@ -14,6 +14,7 @@ import { RasterTimeseries } from '$components/common/map/style-generators/raster import { VectorTimeseries } from '$components/common/map/style-generators/vector-timeseries'; import { ZarrTimeseries } from '$components/common/map/style-generators/zarr-timeseries'; import { CMRTimeseries } from '$components/common/map/style-generators/cmr-timeseries'; +import { Arc } from '$components/common/map/style-generators/arc'; interface LayerProps { id: string; @@ -45,8 +46,8 @@ export function Layer(props: LayerProps) { // The date needs to match the dataset's time density. const relevantDate = useMemo( - () => getTimeDensityStartDate(selectedDay, dataset.data?.timeDensity), - [selectedDay, dataset.data?.timeDensity] + () => getTimeDensityStartDate(selectedDay, dataset.data.timeDensity), + [selectedDay, dataset.data.timeDensity] ); // Resolve config functions. @@ -106,14 +107,12 @@ export function Layer(props: LayerProps) { opacity={opacity} /> ); - case 'raster': + case 'arc': return ( - ); + case 'raster': + return ( +