diff --git a/package-lock.json b/package-lock.json
index ae68edf9..eebaf534 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,17 +9,19 @@
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.5",
"@fontsource/inter": "^5.0.16",
- "@mui/icons-material": "^5.15.11",
- "@mui/joy": "^5.0.0-beta.32",
- "@mui/material": "^5.15.11",
+ "@mui/icons-material": "^5.15.15",
+ "@mui/joy": "^5.0.0-beta.36",
+ "@mui/material": "^5.15.15",
"axios": "^1.6.7",
"core-js": "^3.36.0",
"d3": "^7.8.5",
"dotenv": "^16.4.5",
"leaflet": "^1.9.4",
"mapbox-gl": "^3.1.2",
+ "prop-types": "^15.8.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
+ "react-draggable": "^4.4.6",
"react-leaflet": "^4.2.1",
"react-map-gl": "^7.1.7",
"react-query": "^3.39.3",
@@ -15670,6 +15672,27 @@
"react": "^18.3.1"
}
},
+ "node_modules/react-draggable": {
+ "version": "4.4.6",
+ "resolved": "https://registry.npmjs.org/react-draggable/-/react-draggable-4.4.6.tgz",
+ "integrity": "sha512-LtY5Xw1zTPqHkVmtM3X8MUOxNDOUhv/khTgBgrUvwaS064bwVvxT+q5El0uUFNx5IEPKXuRejr7UqLwBIg5pdw==",
+ "dependencies": {
+ "clsx": "^1.1.1",
+ "prop-types": "^15.8.1"
+ },
+ "peerDependencies": {
+ "react": ">= 16.3.0",
+ "react-dom": ">= 16.3.0"
+ }
+ },
+ "node_modules/react-draggable/node_modules/clsx": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz",
+ "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/react-is": {
"version": "18.3.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz",
diff --git a/package.json b/package.json
index ec59f33c..5abcda2f 100644
--- a/package.json
+++ b/package.json
@@ -47,17 +47,19 @@
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.5",
"@fontsource/inter": "^5.0.16",
- "@mui/icons-material": "^5.15.11",
- "@mui/joy": "^5.0.0-beta.32",
- "@mui/material": "^5.15.11",
+ "@mui/icons-material": "^5.15.15",
+ "@mui/joy": "^5.0.0-beta.36",
+ "@mui/material": "^5.15.15",
"axios": "^1.6.7",
"core-js": "^3.36.0",
"d3": "^7.8.5",
"dotenv": "^16.4.5",
"leaflet": "^1.9.4",
"mapbox-gl": "^3.1.2",
+ "prop-types": "^15.8.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
+ "react-draggable": "^4.4.6",
"react-leaflet": "^4.2.1",
"react-map-gl": "^7.1.7",
"react-query": "^3.39.3",
diff --git a/src/app.js b/src/app.js
index 0794220e..fb5a61dd 100644
--- a/src/app.js
+++ b/src/app.js
@@ -1,12 +1,26 @@
import React, { Fragment } from 'react';
import { Map } from '@components/map';
+import ObservationDialog from "@components/map/observation-dialog";
+import { useLayers } from '@context';
import { Sidebar } from '@components/sidebar';
export const App = () => {
- return (
+ // install the selected observation list from the layer context
+ const {
+ selectedObservations
+ } = useLayers();
+
+ return (
-
-
-
- );
+ {
+ // for each observation selected
+ selectedObservations.map (function (obs) {
+ // render the observation
+ return ;
+ })
+ }
+
+
+
+ );
};
diff --git a/src/components/map/default-layers.js b/src/components/map/default-layers.js
index 36d2aacc..0b3b9f0d 100644
--- a/src/components/map/default-layers.js
+++ b/src/components/map/default-layers.js
@@ -27,6 +27,7 @@ export const DefaultLayers = () => {
const {
defaultModelLayers,
setDefaultModelLayers,
+ setSelectedObservations
} = useLayers();
// Create the authorization header
@@ -81,6 +82,9 @@ export const DefaultLayers = () => {
// from the feature.properties.csv_url and create a fancy plot
console.log("Observation Station '" + feature.properties.location_name + "' clicked");
markClicked(map, e);
+
+ // populate selectedObservations list with the newly selected observation point
+ setSelectedObservations(previous => [...previous, feature.properties]);
});
}
};
diff --git a/src/components/map/observation-dialog.js b/src/components/map/observation-dialog.js
new file mode 100644
index 00000000..4d0ab9d6
--- /dev/null
+++ b/src/components/map/observation-dialog.js
@@ -0,0 +1,33 @@
+import React, {Fragment} from 'react';
+import PropTypes from 'prop-types';
+import BaseFloatingDialog from "@utils/base-floating-dialog";
+
+// define the properties of this component
+ObservationDialog.propTypes = {
+ obs_data: PropTypes.object
+};
+
+export default function ObservationDialog(obs_data) {
+ // TODO: the url is put in here but it will eventually
+ // return a graph using data from this url
+ const graphObj = (url) => {
+ return (
+
+
+ {url}
+
+
+ );
+ };
+
+ // create an object for the base dialog
+ const floaterArgs = {title: obs_data.obs.station_name, description: obs_data.obs.location_name, openDialogImmediately:true, "dialogObject": {...graphObj(obs_data.obs.csvurl)}};
+
+ // render the dialog.
+ // the key here will be used to remove the dialog from the selected observation list when the dialog is closed
+ return (
+
+
+
+ );
+};
\ No newline at end of file
diff --git a/src/context/map-context.js b/src/context/map-context.js
index e185f0e7..c2632def 100644
--- a/src/context/map-context.js
+++ b/src/context/map-context.js
@@ -7,6 +7,10 @@ export const useLayers = () => useContext(LayersContext);
export const LayersProvider = ({ children }) => {
const [defaultModelLayers, setDefaultModelLayers] = useState([]);
const [filteredModelLayers, setFilteredModelLayers] = useState([]);
+
+ // this object contains data for graph rendering
+ const [selectedObservations, setSelectedObservations] = useState([]);
+
const [map, setMap] = useState(null);
const toggleLayerVisibility = id => {
@@ -35,6 +39,8 @@ export const LayersProvider = ({ children }) => {
filteredModelLayers,
setFilteredModelLayers,
toggleLayerVisibility,
+ selectedObservations,
+ setSelectedObservations
}}
>
{children}
diff --git a/src/utils/base-floating-dialog.js b/src/utils/base-floating-dialog.js
new file mode 100644
index 00000000..8c598e82
--- /dev/null
+++ b/src/utils/base-floating-dialog.js
@@ -0,0 +1,104 @@
+import React, {Fragment} from 'react';
+import Draggable from 'react-draggable';
+import PropTypes from 'prop-types';
+
+import Button from '@mui/material/Button';
+import CssBaseline from '@mui/material/CssBaseline';
+import Dialog from '@mui/material/Dialog';
+import DialogActions from '@mui/material/DialogActions';
+import DialogContent from '@mui/material/DialogActions';
+import DialogContentText from '@mui/material/DialogContentText';
+import DialogTitle from '@mui/material/DialogTitle';
+import Paper from '@mui/material/Paper';
+import Slide from '@mui/material/Slide';
+
+import { useLayers } from '@context';
+
+// define the properties of this component
+BaseFloatingDialog.propTypes = {
+ title: PropTypes.string,
+ description: PropTypes.string,
+ openDialogImmediately: PropTypes.bool,
+ dialogObject: PropTypes.any
+};
+
+/**
+ * This is a component that displays a floating dialog with the content passed
+ *
+ * @param title: string
+ * @param description: string
+ * @param openDialogImmediately: boolean
+ * @param dialogObject: {JSX.Element}
+ * @returns {JSX.Element}
+ */
+export default function BaseFloatingDialog({ title, description, openDialogImmediately, dialogObject} ) {
+ // define the dialog open/close session state
+ const [open, setOpen] = React.useState(openDialogImmediately);
+
+ const {
+ selectedObservations,
+ setSelectedObservations
+ } = useLayers();
+
+ /**
+ * the close dialog handler
+ */
+ const handleClose = () => {
+ // close the dialog
+ setOpen(false);
+
+ // remove this item from the selected observations list
+ setSelectedObservations(selectedObservations.filter(item => item.station_name !== title));
+ };
+
+ /**
+ * configure and render the floating dialog
+ */
+ return (
+
+
+
+
+ );
+};
+
+/**
+ * This creates a 3D dialog.
+ *
+ * @param props
+ * @returns {JSX.Element}
+ * @constructor
+ */
+function PaperComponent(props) {
+ return (
+
+
+
+ );
+}
+
+/**
+ * This creates an animated transition for the dialog that pops up
+ * @type {React.ForwardRefExoticComponent & React.RefAttributes>}
+ */
+const Transition = React.forwardRef(function Transition(props, ref) {
+ return ;
+});
\ No newline at end of file