generated from RENCI/react-starter
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #12 from RENCI/obs-work
Updates to add observation layers to the map.
- Loading branch information
Showing
3 changed files
with
181 additions
and
71 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,78 +1,177 @@ | ||
import React, { Fragment, useEffect } from 'react'; | ||
import { WMSTileLayer } from 'react-leaflet'; | ||
import React, { Fragment, useEffect, useState } from 'react'; | ||
import { WMSTileLayer, GeoJSON, useMap } from 'react-leaflet'; | ||
import { CircleMarker } from 'leaflet'; | ||
import { useLayers } from '@context'; | ||
import { markClicked } from '@utils/map-utils'; | ||
|
||
export const DefaultLayers = () => { | ||
const { | ||
defaultModelLayers, | ||
setDefaultModelLayers, | ||
} = useLayers(); | ||
|
||
// Create the authorization header | ||
const requestOptions = { | ||
method: 'GET', | ||
headers: { | ||
Authorization: `Bearer ${process.env.REACT_APP_UI_DATA_TOKEN}` | ||
} | ||
}; | ||
const [obsData, setObsData] = useState(""); | ||
const map = useMap(); | ||
|
||
// create the URLs to the data endpoints | ||
const data_url = `${process.env.REACT_APP_UI_DATA_URL}get_ui_data_secure?limit=1&use_v3_sp=true`; | ||
const gs_url = `${process.env.REACT_APP_GS_DATA_URL}ADCIRC_2024/wms`; | ||
const { | ||
defaultModelLayers, | ||
setDefaultModelLayers, | ||
} = useLayers(); | ||
|
||
useEffect(() => { | ||
// React advises to declare the async function directly inside useEffect | ||
// TODO: Need to store this url in some website config file and | ||
// it should change to reflect the namspace we are running in | ||
async function getDefaultLayers() { | ||
const layer_list = []; | ||
const response = await fetch(data_url, requestOptions); | ||
const data = await response.json(); | ||
|
||
if (data) { | ||
// get layer id in workbench and find catalog entries for each | ||
//for (let layer_id in data.workbench) { | ||
data.workbench.forEach(function (layer_id) { | ||
const layer = getCatalogEntry(data.catalog, layer_id); | ||
if (layer) | ||
layer_list.push(layer); | ||
}); | ||
setDefaultModelLayers(layer_list); | ||
} | ||
} | ||
// Create the authorization header | ||
const requestOptions = { | ||
method: 'GET', | ||
headers: { | ||
Authorization: `Bearer ${process.env.REACT_APP_UI_DATA_TOKEN}` | ||
} | ||
}; | ||
|
||
// retrieve the catalog member with the provided id | ||
const getCatalogEntry = (catalog, id) => { | ||
let entry = ""; | ||
|
||
for (const idx in catalog) { | ||
catalog[idx].members.forEach (function (e) { | ||
if (e.id === id) { | ||
entry = e; | ||
const obsPointToLayer = ((feature, latlng) => { | ||
let obs_color = "#FFFFFF"; | ||
|
||
switch (feature.properties.gauge_owner) { | ||
case 'NOAA/NDBC': | ||
obs_color = "#FFFF00"; | ||
break; | ||
case 'NCEM': | ||
obs_color = "#3D4849"; | ||
break; | ||
case 'NOAA/NOS': | ||
obs_color = "#BEAEFA"; | ||
break; | ||
} | ||
|
||
return new CircleMarker(latlng, { | ||
radius: 6, | ||
weight: 0.7, | ||
color: '#000000', | ||
fillColor: obs_color, | ||
fillOpacity: 1 | ||
}); | ||
} | ||
return entry; | ||
}); | ||
|
||
const onEachObsFeature = (feature, layer) => { | ||
if (feature.properties && feature.properties.location_name) { | ||
const popupContent = feature.properties.location_name; | ||
|
||
layer.on("mouseover", function (e) { | ||
this.bindPopup(popupContent).openPopup(e.latlng); | ||
}); | ||
|
||
layer.on("mousemove", function (e) { | ||
this.getPopup().setLatLng(e.latlng); | ||
}); | ||
|
||
layer.on("mouseout", function () { | ||
this.closePopup(); | ||
}); | ||
layer.on("click", function (e) { | ||
// Do stuff here for retrieving time series data, in csv fomat, | ||
// from the feature.properties.csv_url and create a fancy plot | ||
console.log("Observation Station '" + feature.properties.location_name + "' clicked"); | ||
markClicked(map, e); | ||
}); | ||
} | ||
}; | ||
getDefaultLayers(); | ||
}, []); | ||
|
||
return ( | ||
<> | ||
{defaultModelLayers.map((layer, index) => { | ||
return( | ||
<WMSTileLayer | ||
key = {index} | ||
url ={gs_url} | ||
layers={layer.layers} | ||
params={{ | ||
format:"image/png", | ||
transparent: true, | ||
}} | ||
> | ||
</WMSTileLayer> | ||
// create the URLs to the data endpoints | ||
const data_url = `${process.env.REACT_APP_UI_DATA_URL}get_ui_data_secure?limit=1&use_new_wb=true&use_v3_sp=true`; | ||
const gs_wms_url = `${process.env.REACT_APP_GS_DATA_URL}wms`; | ||
const gs_wfs_url = `${process.env.REACT_APP_GS_DATA_URL}`; | ||
|
||
useEffect(() => { | ||
// React advises to declare the async function directly inside useEffect | ||
// TODO: Need to store this url in some website config file and | ||
// it should change to reflect the namspace we are running in | ||
async function getDefaultLayers() { | ||
const layer_list = []; | ||
const response = await fetch(data_url, requestOptions); | ||
const data = await response.json(); | ||
let obs_url = null; | ||
|
||
if (data) { | ||
// get layer id in workbench and find catalog entries for each | ||
data.workbench.forEach(function (layer_id) { | ||
const layer = getCatalogEntry(data.catalog, layer_id); | ||
if (layer) | ||
layer_list.push(layer); | ||
|
||
// TODO: do we really need to do this here??! | ||
// if this is an obs layer, need to retrieve | ||
// the json data for it from GeoServer | ||
const pieces = layer.id.split('-'); | ||
const type = pieces[pieces.length-1]; | ||
if( type === "obs") { | ||
obs_url = gs_wfs_url + | ||
"/ows?service=WFS&version=1.0.0&request=GetFeature&outputFormat=application/json" + | ||
"&typeName=" + | ||
layer.layers; | ||
} | ||
}); | ||
setDefaultModelLayers(layer_list); | ||
} | ||
|
||
if (obs_url) { | ||
const obs_response = await fetch(obs_url); | ||
const obs_data = await obs_response.json(); | ||
//console.log("obs_data 1: " + JSON.stringify(obs_data, null, 2)) | ||
|
||
setObsData(obs_data); | ||
} | ||
|
||
} | ||
|
||
// retrieve the catalog member with the provided id | ||
const getCatalogEntry = (catalog, id) => { | ||
let entry = ""; | ||
|
||
for (const idx in catalog) { | ||
catalog[idx].members.forEach (function (e) { | ||
if (e.id === id) { | ||
entry = e; | ||
} | ||
}); | ||
} | ||
return entry; | ||
}; | ||
getDefaultLayers().then(); | ||
}, []); | ||
|
||
//console.log("defaultModelLayers: " + JSON.stringify(defaultModelLayers, null, 2)) | ||
|
||
return ( | ||
<> | ||
{defaultModelLayers.map((layer, index) => { | ||
const pieces = layer.id.split('-'); | ||
const type = pieces[pieces.length-1]; | ||
//console.log("type: " + JSON.stringify(type, null, 2)) | ||
if( type === "obs" && obsData !== "") { | ||
//console.log("obsData: " + JSON.stringify(obsData, null, 2)); | ||
return ( | ||
<GeoJSON | ||
key = {index} | ||
data = {obsData} | ||
pointToLayer = {obsPointToLayer} | ||
onEachFeature = {onEachObsFeature} | ||
/> | ||
); | ||
} | ||
else { | ||
return ( | ||
<WMSTileLayer | ||
key = {index} | ||
/* eventHandlers={{ | ||
click: () => { | ||
console.log('marker clicked') | ||
}, | ||
}} */ | ||
url={gs_wms_url} | ||
layers={layer.layers} | ||
params={{ | ||
format:"image/png", | ||
transparent: true, | ||
}} | ||
|
||
/> | ||
); | ||
} | ||
})}; | ||
</> | ||
); | ||
})}; | ||
</> | ||
); | ||
}; |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,25 @@ | ||
import useLayers from '../context/map-context'; | ||
import { StacApiProvider } from "stac-react"; | ||
//import { useLayers } from '@context'; | ||
import locationIcon from '@images/location_searching_FILL0_wght400_GRAD0_opsz24.png'; | ||
|
||
const { | ||
/* const { | ||
defaultModelLayers, | ||
setDefaultModelLayers, | ||
filteredModelLayers, | ||
setFilteredModelLayers | ||
} = useLayers(); | ||
} = useLayers(); */ | ||
|
||
|
||
// Utilities to access the stac catalog items to load on map | ||
const stacCatalog = ({stacUrl}) => { | ||
// function to add a location marker where ever and obs mod layer | ||
// feature is clicked icon downloaded as png from here: | ||
// https://fonts.google.com/icons?selected=Material+Symbols+Outlined:location_searching:FILL@0;wght@400;GRAD@0;opsz@24&icon.query=location | ||
export const markClicked = (map, event) => { | ||
|
||
const targetIcon = L.icon({ | ||
iconUrl: locationIcon, | ||
iconSize: [38, 38], | ||
iconAnchor: [19, 19], | ||
popupAnchor: [0, 0], | ||
}); | ||
|
||
L.marker([event.latlng.lat, event.latlng.lng], {icon: targetIcon}).addTo(map); | ||
}; |