diff --git a/src/common/map.ts b/src/common/map.ts index 40856be4..a6571bd6 100644 --- a/src/common/map.ts +++ b/src/common/map.ts @@ -14,7 +14,7 @@ const lccMapOptionsParam: MapOptions = { // Web Mercator map options const wmMapOptionsParam: MapOptions = { zoomFactor: 5, - minZoom: 2, + minZoom: 4, maxZooom: 19, maxBounds: new LatLngBounds({ lat: -89.999, lng: -180 }, { lat: 89.999, lng: 180 }), maxBoundsViscosity: 0.0, diff --git a/src/components/search/data-collection-option.json b/src/components/search/data-collection-option.json index c2b78818..fccc6280 100644 --- a/src/components/search/data-collection-option.json +++ b/src/components/search/data-collection-option.json @@ -6,5 +6,9 @@ { "label": "datacollection.SENTINEL1", "value": "sentinel-1" + }, + { + "label": "datacollection.RCM-ARD", + "value": "rcm-ard" } ] diff --git a/src/components/search/geosearch.tsx b/src/components/search/geosearch.tsx index 185aa7cc..82599f98 100644 --- a/src/components/search/geosearch.tsx +++ b/src/components/search/geosearch.tsx @@ -122,13 +122,57 @@ const GeoSearch = ( const [ofOpen, setOfOpen] = useState(false); const [allkw, setKWShowing] = useState([]); const [sortbyValue, setSortbyValue] = useState(queryParams.sort ? queryParams.sort : 'popularity-desc'); + const [initialCenter, setInitialCenter] = useState(null); + const [initialZoom, setInitialZoom] = useState(null); + + const supportedFormats = [ + "data;tiff;", + "image/tiff", + "thumbnail;png", + "image/png", + "thumbnail;jpeg", + "image/jpeg", + "application/geotiff" + ]; /* const orgfilters = useSelector((state) => state.mappingReducer.orgfilter); const typefilters = useSelector((state) => state.mappingReducer.typefilter); const themefilters = useSelector((state) => state.mappingReducer.themefilter); const foundational = useSelector((state) => state.mappingReducer.foundational); const dispatch = useDispatch(); */ + const removeLayers = () => { + map.eachLayer((layer: unknown) => { + // Check for layers with zIndex 9999 + if (layer.options && layer.options.zIndex === 9999) { + map.removeLayer(layer); + return; // Exit early as layer is already removed + } + + // Check for layers with geoJSON feature properties + const { feature } = layer; + if ( + feature && + feature.type === 'Feature' && + feature.properties && + feature.properties.tag === 'geoViewGeoJSON' + ) { + map.removeLayer(layer); + } + }); + }; + + const resetMapToInitialState = () => { + if (initialCenter && initialZoom !== null) { + // Reset the map view to the initial center and zoom + console.log(initialCenter); + console.log(initialZoom); + map.setView(initialCenter, initialZoom); + } + }; + const selectResult = (result: SearchResult | undefined) => { + map.setMinZoom(4); + resetMapToInitialState(); if(image!==null){ map.removeLayer(image); setImage(null); @@ -153,7 +197,7 @@ const GeoSearch = ( if (result) { const coordinates=JSON.parse(result.coordinates); - const data = { + const geojson_data = { type: 'Feature', properties: { id: result.id, tag: 'geoViewGeoJSON' }, geometry: { @@ -188,80 +232,144 @@ const GeoSearch = ( } analyticPost(selectedParams); // eslint-disable-next-line new-cap - new L.geoJSON(data).addTo(map); + const center=new LatLng((coordinates[0][2][1] + coordinates[0][0][1]) / 2, (coordinates[0][1][0] + coordinates[0][0][0]) / 2); const bounds = L.latLngBounds([[coordinates[0][2][1], coordinates[0][1][0]],[coordinates[0][0][1],coordinates[0][0][0]]]); - //console.log(center, bounds); - if(result.options){ - const parsedOptions=JSON.parse(result.options.replaceAll('""','"')); - let imageUrls=parsedOptions.filter(o=>o.url && o.url !==null && o.description && o.description.en && (o.description.en.toLowerCase().indexOf("data;tiff;")>=0 ||o.description.en.toLowerCase().indexOf("image/tiff")>=0 - || o.description.en.toLowerCase().indexOf("thumbnail;png")>=0 ||o.description.en.toLowerCase().indexOf("image/png")>=0 - || o.description.en.toLowerCase().indexOf("thumbnail;jpeg")>=0 ||o.description.en.toLowerCase().indexOf("image/jpeg")>=0)); - if(imageUrls.length>0 && thumbnailConfig['eodms_use_image']===true && result.systemName && result.systemName.toLowerCase().indexOf("eodms")>=0 && result.eoCollection==='sentinel-1'){ - //const imageBounds = L.latLngBounds([[coordinates[0][2][1], coordinates[0][1][0]],[coordinates[0][0][1],coordinates[0][0][0]]]); - let thumbnail_correction = thumbnailConfig['thumbnail_correction_proxy_dev']; + if (result.options) { + const parsedOptions = JSON.parse(result.options.replaceAll('""', '"')); + const imageUrls = getFilteredImageUrls(parsedOptions, supportedFormats); + + if ( + imageUrls.length > 0 && + thumbnailConfig['eodms_use_image'] === true && + result.systemName?.toLowerCase().includes("eodms") && + result.eoCollection === "sentinel-1" + ) { + // Handle EODMS Sentinel-1 thumnbnail image rendering + const thumbnailCorrection = thumbnailConfig['thumbnail_correction_proxy_dev']; const eoFilters = JSON.parse(result.eoFilters.replace(/\"\"/g, '"')); - let orbitDirection = eoFilters[0].orbitState; - let url=thumbnail_correction + imageUrls[0].url + "&side=" + orbitDirection; - //handling if image is type tiff - let imgUrlsTIFF=imageUrls.filter(o=>o.description.en.toLowerCase().indexOf("data;tiff;")>=0||o.description.en.toLowerCase().indexOf("image/tiff")>=0); - if(imgUrlsTIFF.length>0){ - url=imgUrlsTIFF[0].url; - } - const image=L.imageOverlay(url, bounds, {opacity: 1}).addTo(map); - setImage(image); - //map.fitBounds(bounds); - //map.setView(center, map.getZoom()); - map.fitBounds(bounds, {padding: [50,50]}); - - setTimeout(()=>map.setView(center, map.getZoom()>5?map.getZoom()-1:map.getZoom()), 500); - }else if(imageUrls.length>0 && (result.keywords.toLowerCase().indexOf("stac")>=0 - || (thumbnailConfig['eodms_use_image']===false && result.systemName && result.systemName.toLowerCase().indexOf("eodms")>=0 && result.eoCollection==='sentinel-1'))){ - let imgUrls=imageUrls.filter(o=>o.description.en.toLowerCase().indexOf("data;tiff;")>=0 || o.description.en.toLowerCase().indexOf("image/tiff")>=0); - let url=imageUrls[0].url; - if(imgUrls.length>0){ - url=imgUrls[0].url; + const orbitDirection = eoFilters[0].orbitState; + + // Get the first image URL and prioritize TIFF images + let url = thumbnailCorrection + imageUrls[0].url + "&side=" + orbitDirection; + const tiffImages = getFilteredImageUrls(imageUrls, ["data;tiff;", "image/tiff"]); + if (tiffImages.length > 0) { + url = tiffImages[0].url; } + + // Add image overlay to map + const imageLayer = L.imageOverlay(url, bounds, { opacity: 1 }).addTo(map); + setImage(imageLayer); + + // Adjust map view + setMapView(center, bounds); - axios.get(`${EnvGlobals.COG_TILEJSON_URL}`, {params: {url}}).then((res)=>{ - //console.log(res); - const centers=res.data.center; - const imageBounds = L.latLngBounds([[res.data.bounds[3], res.data.bounds[2]],[res.data.bounds[1], res.data.bounds[0]]]); - axios.get(`${EnvGlobals.COG_STATISTICS_URL}`, {params: {url, unscale: 'false', resampling:'nearest', max_size: '1024', categorical: 'false'}}).then((res2)=>{ - //console.log(res2); - const min=res2.data.b1.min; - const max=res2.data.b1.max; - var layer=new L.TileLayer(`${EnvGlobals.COG_TILESERVICE_URL}?url=${url}&resampling_method=nearest&bidx=1&rescale=${min}%2C${max}`, {bounds:imageBounds, zIndex:9999}); + // Draw the bounding box + setTimeout(() => { + new L.geoJSON(geojson_data).addTo(map); + }, 200); + } else if ( + imageUrls.length > 0 && + (result.keywords.toLowerCase().includes("stac") || + (!thumbnailConfig['eodms_use_image'] && + result.systemName?.toLowerCase().includes("eodms") && + result.eoCollection === "sentinel-1")) + ) { + // Handle COG image rendering via tiling service + const tiffImages = getFilteredImageUrls(imageUrls, ["data;tiff;", "image/tiff"]); + const url = tiffImages.length > 0 ? tiffImages[0].url : imageUrls[0].url; + let imageBounds; + let tileCenter; + + axios + .get(`${EnvGlobals.COG_TILEJSON_URL}`, { params: { url } }) + .then((tileResponse) => { + const { center, bounds: tileBounds } = tileResponse.data; + tileCenter = center; + + // Parse tile bounds + imageBounds = L.latLngBounds([ + [tileBounds[3], tileBounds[2]], + [tileBounds[1], tileBounds[0]], + ]); + + return axios.get(`${EnvGlobals.COG_STATISTICS_URL}`, { + params: { + url, + unscale: "false", + resampling: "nearest", + max_size: "1024", + categorical: "false", + }, + }); + }) + .then((statsResponse) => { + const { min, percentile_98 } = statsResponse.data.b1; + + const layer = new L.TileLayer( + `${EnvGlobals.COG_TILESERVICE_URL}?url=${url}&resampling_method=nearest&bidx=1&rescale=${min},${percentile_98}`, + { bounds: imageBounds, zIndex: 9999 } + ); + //Add tile to map + //console.log("Adding tile to map"); map.addLayer(layer); - //console.log('added', layer); - map.setView(new LatLng(centers[1], centers[0]), centers[2]); + map.setView(new LatLng(tileCenter[1], tileCenter[0]), tileCenter[2]); + setTimeout(() => { + new L.geoJSON(geojson_data).addTo(map); + }, 200); + }) + .catch((err) => { + //Handle errors in getting the Tile + console.error("TileJSON Error:", err); + setMapView(center, bounds); + setTimeout(() => { + new L.geoJSON(geojson_data).addTo(map); + }, 200); }); - }).catch(err=>{ - console.log('tilejson', err); - setMapView(center, bounds); - }); - - }else{ + } else { + // Handle fallback GEO.ca record or default case setMapView(center, bounds); - } - } else{ + setTimeout(() => { + new L.geoJSON(geojson_data).addTo(map); + }, 200); + } + } else { + // Default handling when no options are provided setMapView(center, bounds); - } + setTimeout(() => { + new L.geoJSON(geojson_data).addTo(map); + }, 200); + } } }; - - const setMapView=(center, bounds)=>{ - map.fitBounds(bounds); - setTimeout(()=>map.setView(center, map.getZoom()>5?map.getZoom()-1:map.getZoom()), 500); + + function getFilteredImageUrls(parsedOptions, formats) { + return parsedOptions.filter( + (o) => + o.url && + o.description && + o.description.en && + formats.some((format) => o.description.en.toLowerCase().includes(format)) + ); } + const setMapView = (center, bounds) => { + const bestZoom = map.getBoundsZoom(bounds, true); + if (bestZoom > 8) { + map.fitBounds(bounds); + } else { + // Set a minimum zoom level of 4 + setTimeout(() => map.setView(center, Math.min(4, map.getZoom())), 200); + } + }; + const handleSelect = (event: string) => { // const {selectResult} = this.props; const cardOpen = selected === event ? !open : true; setFootprintViewed(cardOpen); const result = - Array.isArray(results) && results.length > 0 && cardOpen ? results.find((r: SearchResult) => r.id === event) : undefined; + Array.isArray(results) && results.length > 0 && cardOpen ? results.find((r: SearchResult) => r.id === event) : undefined; setSelected(event); setOpen(cardOpen); selectResult(result); @@ -994,7 +1102,7 @@ const GeoSearch = ( }; const isMobile = useMediaQuery('(max-width: 760px)'); useEffect(() => { - // console.log(freeze); + console.log(freeze); if (!freeze.freeze) { map.on('moveend', (event) => eventHandler(event, initKeyword)); } else { @@ -1370,17 +1478,21 @@ const GeoSearch = ( )}
{cnt > 0 && (!loading || cpn) && ( - handleKOSearch(initKeyword, pnum) - : (pnum: number) => handleSearch(initKeyword, initBounds, pnum) - } + selectPage={(pnum: number) => { + removeLayers(); + + if (ksOnly) { + handleKOSearch(initKeyword, pnum); + } else { + handleSearch(initKeyword, initBounds, pnum); + } + }} /> )} {loading ? ( @@ -1576,11 +1688,15 @@ const GeoSearch = ( rcnt={cnt} current={pn} loading={loading} - selectPage={ - ksOnly - ? (pnum: number) => handleKOSearch(initKeyword, pnum) - : (pnum: number) => handleSearch(initKeyword, initBounds, pnum) - } + selectPage={(pnum: number) => { + removeLayers(); + + if (ksOnly) { + handleKOSearch(initKeyword, pnum); + } else { + handleSearch(initKeyword, initBounds, pnum); + } + }} /> )}
diff --git a/src/components/search/metadatapage.jsx b/src/components/search/metadatapage.jsx index 4922112c..b145b82f 100644 --- a/src/components/search/metadatapage.jsx +++ b/src/components/search/metadatapage.jsx @@ -170,43 +170,63 @@ const MetaDataPage = (props) => { setSimilarRecords(sims); setShowSimilarRecords(sims.slice(0, 5)); } - if(res.options){ - const imageUrls=res.options.filter(o=>o.url && o.url!==null && o.description && o.description.en && (o.description.en.toLowerCase().indexOf("data;tiff;")>=0||o.description.en.toLowerCase().indexOf("image/tiff")>=0 - ||o.description.en.toLowerCase().indexOf("thumbnail;png")>=0 - ||o.description.en.toLowerCase().indexOf("image/png")>=0 - ||o.description.en.toLowerCase().indexOf("thumbnail;jpeg")>=0 - ||o.description.en.toLowerCase().indexOf("image/jpeg")>=0)); + if(res.options){ + const imageUrls = res.options.filter(o => + o.url && o.url !== null && + o.description && o.description.en && + ( + o.description.en.toLowerCase().indexOf("data;tiff;") >= 0 || + o.description.en.toLowerCase().indexOf("image/tiff") >= 0 || + o.description.en.toLowerCase().indexOf("thumbnail;png") >= 0 || + o.description.en.toLowerCase().indexOf("image/png") >= 0 || + o.description.en.toLowerCase().indexOf("thumbnail;jpeg") >= 0 || + o.description.en.toLowerCase().indexOf("image/jpeg") >= 0 || + o.description.en.toLowerCase().indexOf("application/geotiff") >= 0 + ) + ); let url; - const isSentinel1=imageUrls.length>0 && res.sourceSystemName.toLowerCase().indexOf("eodms")>=0 && res.eoCollection==='sentinel-1' && thumbnailConfig['eodms_use_image']; + const isSentinel1=imageUrls.length>0 && res.sourceSystemName.toLowerCase().indexOf("ccmeo-eodms")>=0 && res.eoCollection==='sentinel-1' && thumbnailConfig['eodms_use_image']; + const isRCMARD=imageUrls.length>0 && res.sourceSystemName.toLowerCase().indexOf("ccmeo-eodms")>=0 && res.eoCollection==='rcm-ard'; + const isDatacube=imageUrls.length>0 && res.sourceSystemName.toLowerCase().indexOf("ccmeo-datacube")>=0; if (isSentinel1) setTileServiceUrl(null); - const hasImage=imageUrls.length>0 && res.keywords.toLowerCase().indexOf("stac")>=0; - if(imageUrls.length>0){ + const hasImage=imageUrls.length>0 && res.keywords.toLowerCase().indexOf("stac")>=0; + if (isSentinel1 && imageUrls.length > 0) { + // Set URL to load the thumbnail image let thumbnail_correction = thumbnailConfig['thumbnail_correction_proxy_dev']; let orbitDirection = res.eoFilters[0]?.orbitState; - //console.log(orbitDirection); - url=thumbnail_correction + imageUrls[0].url + "&side=" + orbitDirection; - //handling if image is type tiff - let imgUrlsTIFF=imageUrls.filter(o=>o.description.en.toLowerCase().indexOf("data;tiff;")>=0||o.description.en.toLowerCase().indexOf("image/tiff")>=0); - if(imgUrlsTIFF.length>0){ - url=imgUrlsTIFF[0].url; - } + url = thumbnail_correction + imageUrls[0].url + "&side=" + orbitDirection; } - - if(!isSentinel1 && hasImage){ + else if ((isRCMARD || isDatacube) && imageUrls.length > 0) { + // Set URL to load the COG geotiff + let imgUrlsTIFF = imageUrls.filter(o => ( + o.description.en.toLowerCase().indexOf("data;tiff;") >= 0 || + o.description.en.toLowerCase().indexOf("image/tiff") >= 0 || + o.description.en.toLowerCase().indexOf("application/geotiff") >= 0 + )); + if (imgUrlsTIFF.length > 0) { + url = imgUrlsTIFF[0].url; + } + } + console.log(imageUrls); + console.log(isRCMARD); + console.log(isDatacube); + console.log(hasImage); + if((isRCMARD || isDatacube) && hasImage){ + console.log("trying to load tile"); axios.get(`${EnvGlobals.COG_TILEJSON_URL}`, {params: {url}}).then((res)=>{ - //console.log(res); + console.log(res); const centers=res.data.center; setCogCenter(new LatLng(centers[1], centers[0])); setCogZoom(centers[2]); const imageBounds = L.latLngBounds([[res.data.bounds[3], res.data.bounds[2]],[res.data.bounds[1], res.data.bounds[0]]]); setCogBounds(imageBounds); axios.get(`${EnvGlobals.COG_STATISTICS_URL}`, {params: {url, unscale: 'false', resampling:'nearest', max_size: '1024', categorical: 'false'}}).then((res2)=>{ - //console.log(res2); + console.log(res2); const min=res2.data.b1.min; - const max=res2.data.b1.max; + const max=res2.data.b1.percentile_98; setTileServiceUrl(`${EnvGlobals.COG_TILESERVICE_URL}?url=${url}&resampling_method=nearest&bidx=1&rescale=${min}%2C${max}`); - setLoading1(false); + setLoading1(false); }); }).catch(err=>{ //console.log('tilejson', err); @@ -437,12 +457,20 @@ const MetaDataPage = (props) => { const desc = option.description[language].split(";"); return { name: option.name[language], type: desc[0], format: desc[1], language: t(`page.${desc[2].toLowerCase().replace(',', '')}`), url: option.url }; }); - const imageUrls=formattedOption.filter(o=>o.url && o.url!==null && o.description && o.description.en && (o.description.en.toLowerCase().indexOf("data;tiff;")>=0 - ||o.description.en.toLowerCase().indexOf("image/tiff")>=0 - ||o.description.en.toLowerCase().indexOf("thumbnail;png")>=0 - ||o.description.en.toLowerCase().indexOf("image/png")>=0 - ||o.description.en.toLowerCase().indexOf("thumbnail;jpeg")>=0 - ||o.description.en.toLowerCase().indexOf("image/jpeg")>=0)); + + const imageUrls = formattedOption.filter(o => + o.url && o.url !== null && + o.description && o.description.en && + ( + o.description.en.toLowerCase().indexOf("data;tiff;") >= 0 || + o.description.en.toLowerCase().indexOf("image/tiff") >= 0 || + o.description.en.toLowerCase().indexOf("thumbnail;png") >= 0 || + o.description.en.toLowerCase().indexOf("image/png") >= 0 || + o.description.en.toLowerCase().indexOf("thumbnail;jpeg") >= 0 || + o.description.en.toLowerCase().indexOf("image/jpeg") >= 0 || + o.description.en.toLowerCase().indexOf("application/geotiff") >= 0 + ) + ); let url; const isSentinel1=imageUrls.length>0 && result.sourceSystemName==='ccmeo-eodms' && result.eoCollection==='sentinel-1' && thumbnailConfig['eodms_use_image']; const hasImage=imageUrls.length>0 && result.keywords.toLowerCase().indexOf("stac")>=0; @@ -848,7 +876,7 @@ const MetaDataPage = (props) => { } diff --git a/src/components/search/polarization-option.json b/src/components/search/polarization-option-old.json similarity index 100% rename from src/components/search/polarization-option.json rename to src/components/search/polarization-option-old.json diff --git a/src/components/search/polarization-option-rcm-ard.json b/src/components/search/polarization-option-rcm-ard.json new file mode 100644 index 00000000..1a99e534 --- /dev/null +++ b/src/components/search/polarization-option-rcm-ard.json @@ -0,0 +1,14 @@ +[ + { + "label": "polarization.DEFAULT", + "value": "" + }, + { + "label": "polarization.CHCV", + "value": "CH + CV" + }, + { + "label": "polarization.HHHV", + "value": "HH + HV" + } +] diff --git a/src/components/search/polarization-option-sentinel-1.json b/src/components/search/polarization-option-sentinel-1.json new file mode 100644 index 00000000..29b80a36 --- /dev/null +++ b/src/components/search/polarization-option-sentinel-1.json @@ -0,0 +1,38 @@ +[ + { + "label": "polarization.DEFAULT", + "value": "" + }, + { + "label": "polarization.VV", + "value": "VV" + }, + { + "label": "polarization.VVVH", + "value": "VV + VH" + }, + { + "label": "polarization.HH", + "value": "HH" + }, + { + "label": "polarization.HHHV", + "value": "HH + HV" + }, + { + "label": "polarization.HHHVVHVV", + "value": "HH + HV + VH + VV" + }, + { + "label": "polarization.HHVV", + "value": "HH + VV" + }, + { + "label": "polarization.HV", + "value": "HV" + }, + { + "label": "polarization.VH", + "value": "VH" + } +] diff --git a/src/components/searchfilter/eo-filter.scss b/src/components/searchfilter/eo-filter.scss index 7f792ece..04a404d6 100644 --- a/src/components/searchfilter/eo-filter.scss +++ b/src/components/searchfilter/eo-filter.scss @@ -6,4 +6,7 @@ } .sentinel-1 { padding-left: 10px; -} \ No newline at end of file +} +.rcm-ard { + padding-left: 10px; +} diff --git a/src/components/searchfilter/eo-filter.tsx b/src/components/searchfilter/eo-filter.tsx index 513ef1e4..9c055e3a 100644 --- a/src/components/searchfilter/eo-filter.tsx +++ b/src/components/searchfilter/eo-filter.tsx @@ -2,7 +2,8 @@ import { useState } from 'react'; import { useTranslation } from 'react-i18next'; import dataCollectionOptions from '../search/data-collection-option.json'; import orbitOptions from '../search/orbit-direction-option.json'; -import polarizationOptions from '../search/polarization-option.json'; +import polarizationOptionsSentinel from '../search/polarization-option-sentinel-1.json'; +import polarizationOptionsRCMARD from '../search/polarization-option-rcm-ard.json'; import DropdownSelection from './dropdown-selection'; import './eo-filter.scss'; @@ -47,7 +48,7 @@ export default function EoSearchFilter(props: EoSearchProps): JSX.Element { { dataCollection === 'sentinel-1' && (
+ +
+ ) } + { dataCollection === 'rcm-ard' && (
+ Data can be acquired in single polarisation HH (SH) or VV (SV) or in dual polarisation HH&HV (DH) or VV&VH (DV), depending on the instrument mode.
SM, IW and EW can be acquired in single or dual polarisation. WV can only be acquired in single polarisation.", "orbit-tooltip":"Determines whether the data was recorded during a descending orbit (flight direction: north - south) or an ascending orbit (flight direction: south - north).", - "sentinel-1-tooltip":"Sentinel-1 provides all-weather, day and night radar imagery for land and ocean services.
EO Browser provides data acquired in Interferometric Wide Swath (IW) and Extra Wide Swath (EW) modes processed to Level-1 Ground Range Detected (GRD)." + "sentinel-1-tooltip":"Sentinel-1 provides all-weather, day and night radar imagery for land and ocean services.
EO Browser provides data acquired in Interferometric Wide Swath (IW) and Extra Wide Swath (EW) modes processed to Level-1 Ground Range Detected (GRD).", + "rcm-ard-tooltip":"Radarsat Constellation Mission (RCM) - Analysis Ready Data (ARD) includes a trio of Earth observation satellites, capable of scanning Earth day or night and in any weather conditions. The three-satellite configuration allows for daily revisits of Canada's vast territory and maritime approaches, as well as daily access to 90% of the world's surface and the Arctic up to four times a day." } } }, @@ -292,14 +293,15 @@ "NU": "Nunavut", "NT": "Northwest Territories", "YT": "Yukon", - "DEFAULT": "Please select one" + "DEFAULT": "Show all" }, "datacollection": { - "DEFAULT": "Please select one", - "SENTINEL1": "Sentinel-1" + "DEFAULT": "Show all", + "SENTINEL1": "Sentinel-1", + "RCM-ARD": "Radarsat Constellation Mission (RCM) - Analysis Ready Data (ARD)" }, "polarization": { - "DEFAULT": "Please select one", + "DEFAULT": "Show all", "VV": "VV", "VVVH": "VV+VH", "HH": "HH", @@ -307,10 +309,11 @@ "HHHVVHVV":"HH+HV+VH+VV", "HHVV":"HH+VV", "HV": "HV", - "VH": "VH" + "VH": "VH", + "CHCV": "CH+CV" }, "orbit": { - "DEFAULT": "Please select one", + "DEFAULT": "Show all", "ASC": "Ascending", "DESC": "Descending" }, diff --git a/src/locales/fr-CA/translation.json b/src/locales/fr-CA/translation.json index 3352024b..c29d4b95 100644 --- a/src/locales/fr-CA/translation.json +++ b/src/locales/fr-CA/translation.json @@ -117,7 +117,8 @@ "data-collection-tooltip":"", "polarization-tooltip":"Détermine la polarisation avec laquelle les données ont été acquises. La première lettre indique la polarisation lors de l'envoi du signal, la deuxième lettre lors de la réception du signal, par exemple, HV = polarisation horizontale lors de l'envoi du signal et polarisation verticale lors de la réception.
Les données peuvent être acquises en polarisation simple HH (SH) ou VV (SV) ou en polarisation double HH&HV (DH) ou VV&VH (DV), selon le mode de l'instrument.
SM, IW et EW peuvent être acquis en polarisation simple ou double. WV ne peut être acquis qu'en polarisation simple.", "orbit-tooltip":"Détermine si les données ont été enregistrées sur une orbite descendante (direction de déplacement : nord - sud) ou une orbite ascendante (direction de déplacement : sud - nord).", - "sentinel-1-tooltip":"Sentinel-1 fournit des images radar de jour et de nuit, par tous les temps, pour les services terrestres et océaniques. EO Browser fournit des données acquises en mode interférométrique Wide Swath (IW) et Extra Wide Swath (EW), traitées en niveau 1 de détection de la portée au sol (GRD). traitées en niveau 1 Ground Range Detected (GRD)." + "sentinel-1-tooltip":"Sentinel-1 fournit des images radar de jour et de nuit, par tous les temps, pour les services terrestres et océaniques. EO Browser fournit des données acquises en mode interférométrique Wide Swath (IW) et Extra Wide Swath (EW), traitées en niveau 1 de détection de la portée au sol (GRD). traitées en niveau 1 Ground Range Detected (GRD).", + "rcm-ard-tooltip":"Mission de la Constellation RADARSAT (MCR) - données prêtes à l'analyse (DPA) Les trois satellites d'observation de la Terre identiques balaient la Terre jour et nuit, quelles que soient les conditions météorologiques. La configuration à trois satellites permet des réobservations journalières du vaste territoire et des approches maritimes du Canada ainsi qu'un accès à 90 % de la surface terrestre tous les jours et à l'Arctique jusqu'à quatre fois par jour." } } }, @@ -292,14 +293,15 @@ "NU": "Nunavut", "NT": "Territoires du Nord-Ouest", "YT": "Yukon", - "DEFAULT": "Sélectionnez une option" + "DEFAULT": "Tout afficher" }, "datacollection": { - "DEFAULT": "Sélectionnez une option", - "SENTINEL1": "Sentinel-1" + "DEFAULT": "Tout afficher", + "SENTINEL1": "Sentinel-1", + "RCM-ARD": "Mission de la Constellation RADARSAT (MCR) - données prêtes à l'analyse (DPA)" }, "polarization": { - "DEFAULT": "Sélectionnez une option", + "DEFAULT": "Tout afficher", "VV": "VV", "VVVH": "VV+VH", "HH": "HH", @@ -307,10 +309,11 @@ "HHHVVHVV":"HH+HV+VH+VV", "HHVV":"HH+VV", "HV": "HV", - "VH": "VH" + "VH": "VH", + "CHCV": "CH+CV" }, "orbit": { - "DEFAULT": "Sélectionnez une option", + "DEFAULT": "Tout afficher", "ASC": "ascendante", "DESC": "descendante" }, diff --git a/src/reducers/localStorage.ts b/src/reducers/localStorage.ts index a4b29acb..21f182a4 100644 --- a/src/reducers/localStorage.ts +++ b/src/reducers/localStorage.ts @@ -2,78 +2,92 @@ import { StoreEnhancer } from 'redux'; import { INITMAINMAPINFO, INITMETADATASRCFILTER, INITSPATIALTEMPORALFILTER } from './reducer'; +const SESSION_TIMEOUT = 5 * 60 * 1000; // 5 minutes in milliseconds + function checkNestedProperty(obj, props: string): boolean { const splitted = props.split('.'); let temp = obj; for (const index in splitted) { - if (temp[splitted[index]] === 'undefined' || !temp[splitted[index]]) return false; + if (typeof temp[splitted[index]] === 'undefined' || !temp[splitted[index]]) return false; temp = temp[splitted[index]]; } return true; } - export const loadState = (): StoreEnhancer | undefined => { try { const urlParams = new URLSearchParams(window.location.search); - if (!urlParams.toString()) { - const serializedState = localStorage.getItem('state'); - if (serializedState === null) { - return undefined; - } - const state = JSON.parse(serializedState); - if (!checkNestedProperty(state, 'mappingReducer.spatempfilter')) { - state['mappingReducer'].spatempfilter = INITSPATIALTEMPORALFILTER; - } - if (!checkNestedProperty(state, 'mappingReducer.spatialfilter')) { - state['mappingReducer'].spatialfilter = []; - } - if (!checkNestedProperty(state, 'mappingReducer.metasrcfilter')) { - state['mappingReducer'].metasrcfilter = INITMETADATASRCFILTER; - } - if (!checkNestedProperty(state, 'mappingReducer.stacfilter')) { - state['mappingReducer'].stacfilter = []; - } - if (!checkNestedProperty(state, 'mappingReducer.center')) { - state['mappingReducer'].center = INITMAINMAPINFO.center; - } - if (!checkNestedProperty(state, 'mappingReducer.zoom')) { - state['mappingReducer'].zoom = INITMAINMAPINFO.zoom; - } - if (!checkNestedProperty(state, 'mappingReducer.freezeMapSearch')) { - state['mappingReducer'].freezeMapSearch = { freeze: true }; - } - return state; + const serializedState = localStorage.getItem('state'); + + // No state in localStorage, return undefined + if (serializedState === null) { + return undefined; + } + + // Get saved timestamp from localStorage + const savedTime = localStorage.getItem('stateTimestamp'); + + // If no timestamp is found or session is expired + if (savedTime === null) { + console.log("No session timestamp found, starting a new session"); + localStorage.clear(); // Clear localStorage + return undefined; } - else { - const serializedState = localStorage.getItem('state'); - if (serializedState === null) { - return undefined; - } - const state = JSON.parse(serializedState); - state['mappingReducer'].spatempfilter = { extents: [], startDate: "", endDate: "" }; + + // Check if the session has expired (5 minutes timeout) + const currentTime = new Date().getTime(); + if (currentTime - parseInt(savedTime) > SESSION_TIMEOUT) { + console.log("Session expired, clearing state."); + localStorage.clear(); // Invalidate state if session expired + localStorage.setItem('stateTimestamp', currentTime.toString()); // Reset timestamp + return undefined; + } + + // Proceed with loading the state if session is valid + const state = JSON.parse(serializedState); + + // Set default values if they are missing in the state + if (!checkNestedProperty(state, 'mappingReducer.spatempfilter')) { + state['mappingReducer'].spatempfilter = INITSPATIALTEMPORALFILTER; + } + if (!checkNestedProperty(state, 'mappingReducer.spatialfilter')) { state['mappingReducer'].spatialfilter = []; - state['mappingReducer'].metasrcfilter = { sources: [], dataCollection: '', polarization: '', orbitDirection: '' }; + } + if (!checkNestedProperty(state, 'mappingReducer.metasrcfilter')) { + state['mappingReducer'].metasrcfilter = INITMETADATASRCFILTER; + } + if (!checkNestedProperty(state, 'mappingReducer.stacfilter')) { state['mappingReducer'].stacfilter = []; - state['mappingReducer'].center = { lat: 54.5, lng: -115 }; - state['mappingReducer'].zoom = []; + } + if (!checkNestedProperty(state, 'mappingReducer.center')) { + state['mappingReducer'].center = INITMAINMAPINFO.center; + } + if (!checkNestedProperty(state, 'mappingReducer.zoom')) { + state['mappingReducer'].zoom = INITMAINMAPINFO.zoom; + } + if (!checkNestedProperty(state, 'mappingReducer.freezeMapSearch')) { state['mappingReducer'].freezeMapSearch = { freeze: true }; - return state; } + return state; } catch (err) { + // Return undefined if any error occurs during state loading return undefined; } }; export const saveState = (state: unknown): void => { try { - // console.log(state); const serializedState = JSON.stringify(state); - // console.log(serializedState) + const currentTime = new Date().getTime().toString(); // Get current timestamp + + // Clear existing state in localStorage before saving localStorage.clear(); + + // Save the state and the timestamp localStorage.setItem('state', serializedState); + localStorage.setItem('stateTimestamp', currentTime); // Save current timestamp to track session } catch (err) { - // ignore write errors - console.log('error set local:', err); + // Handle errors (e.g., if localStorage is unavailable or quota exceeded) + console.log('error saving to localStorage:', err); } -}; +}; \ No newline at end of file