Select Git revision
App.jsx 8.55 KiB
import React, { useEffect, useState } from "react";
import UsgsHeader from "../presentational/UsgsHeader.jsx";
import UsgsFooter from "../presentational/UsgsFooter.jsx";
import GeoStacApp from "./GeoStacApp.jsx";
import SplashScreen from "../presentational/SplashScreen.jsx";
/**
* App is the parent component for all of the other components in the project.
* It loads the data needed to initialize GeoStac.
* It includes the main GeoStacApp and OCAP compliant headers and footers.
*
* @component
*/
export default function App() {
const [mainComponent, setMainComponent] = useState(() => {
return(
<SplashScreen />
);
})
useEffect(() => {
// Astro Web Maps, has the tile data
const astroWebMaps =
"https://astrowebmaps.wr.usgs.gov/webmapatlas/Layers/maps.json";
// STAC API, has footprint data
const stacApiCollections =
"https://stac.astrogeology.usgs.gov/api/collections";
// Async tracking
let fetchStatus = {};
let fetchPromise = {};
let jsonPromise = {};
// Fetched Maps
let mapsJson = {};
// Combined Data
let aggregateMapList = {};
// Init
fetchStatus[astroWebMaps] = "Not Started";
fetchPromise[astroWebMaps] = "Not Started";
jsonPromise[astroWebMaps] = "Not Started";
mapsJson[astroWebMaps] = [];
fetchStatus[stacApiCollections] = "Not Started";
fetchPromise[stacApiCollections] = "Not Started";
jsonPromise[stacApiCollections] = "Not Started";
mapsJson[stacApiCollections] = [];
// Fetch JSON and read into object
async function ensureFetched(targetUrl) {
if(fetchStatus[targetUrl] === "Not Started")
{
fetchStatus[targetUrl] = "Started";
fetchPromise[targetUrl] = fetch(
targetUrl
).then((res)=>{
jsonPromise[targetUrl] = res.json().then((jsonData)=>{
mapsJson[targetUrl] = jsonData;
}).catch((err)=>{
console.log(err);
});
}).catch((err) => {
console.log(err);
});
}
await fetchPromise[targetUrl];
await jsonPromise[targetUrl];
}
// Combine data from Astro Web Maps and STAC API into one new object
function organizeData(astroWebMaps, stacApiCollections) {
// Initialize Objects
let mapList = { "systems" : [] };
let stacList = [];
// Check for Planets that have STAC footprints from the STAC API
for (let i = 0; i < stacApiCollections.collections.length; i++) {
let stacTarget = stacApiCollections.collections[i].summaries["ssys:targets"][0].toLowerCase();
if(!stacList.find(targetBody => targetBody == stacTarget)){
stacList.push(stacTarget.toLowerCase());
}
}
// Scan through every target in the Astro Web Maps JSON
for (const target of astroWebMaps.targets){
// Check for, add system if system is not in array
if (!mapList.systems.some(system => system.name === target.system)) {
mapList.systems.push({
"name" : target.system,
"naif" : 0,
"bodies" : []
})
}
// Index of System
let sysIndex = mapList.systems.map(sys => sys.name).indexOf(target.system);
// ID the system
if (target.naif % 100 === 99){
mapList.systems[sysIndex].naif = target.naif;
}
// Check for/add body if not already incl
if (!mapList.systems[sysIndex].bodies.some(body => body.name === target.name)) {
// A flag that indicates whether or not the body has footprints
let hasFootprints = stacList.includes(target.name.toLowerCase())
// Add STAC collections
let myCollections = []
if (hasFootprints) {
for (const collection of stacApiCollections.collections){
if (target.name == collection.summaries["ssys:targets"][0].toUpperCase()) {
myCollections.push(collection);
}
}
}
// Add a body data entry
mapList.systems[sysIndex].bodies.push({
"name" : target.name,
"naif" : target.naif,
"hasFootprints" : hasFootprints,
"aaxisradius": target.aaxisradius,
"baxisradius": target.baxisradius,
"caxisradius":target.caxisradius,
"layers" : {
"base" : [],
"overlays" : [],
"nomenclature" : []
},
"collections" : myCollections
})
}
// Index of Body
let bodIndex = mapList.systems[sysIndex].bodies.map(bod => bod.name).indexOf(target.name);
// Sort through AstroWebMaps to get the right ones for GeoSTAC
function getWmsMaps(webMaps) {
let myLayers = {
"base" : [],
"overlays" : [],
"nomenclature" : [],
/* "wfs" : [] */
};
// Add maps
for (const wmap of webMaps) {
if(wmap.type === "WMS" && wmap.layer != "GENERIC") {
if(wmap.transparent == "false") {
// Non-transparent layers are base maps
myLayers.base.push(wmap);
} else if (wmap.layer == "NOMENCLATURE") {
// Feature Name Layers
myLayers.nomenclature.push(wmap);
} else {
// OthTransparent layers are overlays
myLayers.overlays.push(wmap);
}
}
// else if (wmap.type === "WFS") {
// // Currently in AstroMap but doesn't seem to be used.
// myLayers.wfs.push(wmap);
// }
}
return myLayers;
}
// Add base and overlay maps (but not empty arrays!)
let myLayers = getWmsMaps(target.webmap);
if (myLayers.base.length > 0){
mapList.systems[sysIndex].bodies[bodIndex].layers.base.push(...myLayers.base);
}
if (myLayers.nomenclature.length > 0){
mapList.systems[sysIndex].bodies[bodIndex].layers.nomenclature.push(...myLayers.nomenclature);
}
if (myLayers.overlays.length > 0){
mapList.systems[sysIndex].bodies[bodIndex].layers.overlays.push(...myLayers.overlays);
}
}
// Sort systems by NAIF ID
mapList.systems.sort((a, b)=>{return a.naif - b.naif})
// Go through each System
for (let sysIndex = 0; sysIndex < mapList.systems.length; sysIndex++){
// Remove bodies with no base maps
for (let bodIndex = mapList.systems[sysIndex].bodies.length - 1; bodIndex >= 0; bodIndex--){
if(mapList.systems[sysIndex].bodies[bodIndex].layers.base.length < 1){
mapList.systems[sysIndex].bodies.splice(bodIndex, 1);
}
}
// Sort targets by naif id
mapList.systems[sysIndex].bodies.sort((a, b)=>{
let valA = a.naif;
let valB = b.naif;
if (a.naif % 100 == 99) valA = 0; // Planet IDs end with 99,
if (b.naif % 100 == 99) valB = 0; // but put them first.
return valA - valB;
})
}
return mapList;
}
// Fetch and organize data from
async function getStacAndAstroWebMapsData() {
// Start fetching from AWM and STAC API concurrently
ensureFetched(astroWebMaps);
ensureFetched(stacApiCollections);
// Wait for both to complete before moving on
await ensureFetched(astroWebMaps);
await ensureFetched(stacApiCollections);
return organizeData(mapsJson[astroWebMaps], mapsJson[stacApiCollections]);
}
(async () => {
aggregateMapList = await getStacAndAstroWebMapsData();
setMainComponent(<GeoStacApp mapList={aggregateMapList}/>);
})();
}, [])
return (
<>
<UsgsHeader />
{mainComponent}
<UsgsFooter />
</>
);
}