diff --git a/package-lock.json b/package-lock.json index 51baf51..2ff3a37 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,8 +15,10 @@ "chartjs-plugin-annotation": "^3.0.1", "chartjs-plugin-crosshair": "^2.0.0", "date-fns": "^3.6.0", + "lodash": "^4.17.21", "react": "^18.3.1", "react-dom": "^18.3.1", + "react-helmet": "^6.1.0", "react-joyride": "^2.9.2", "react-share": "^5.1.0", "styled-components": "^6.1.12" @@ -4250,6 +4252,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, "node_modules/lodash-es": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", @@ -4938,6 +4946,12 @@ "react": "^18.3.1" } }, + "node_modules/react-fast-compare": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", + "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==", + "license": "MIT" + }, "node_modules/react-floater": { "version": "0.7.9", "resolved": "https://registry.npmjs.org/react-floater/-/react-floater-0.7.9.tgz", @@ -4977,6 +4991,21 @@ "is-lite": "^0.8.2" } }, + "node_modules/react-helmet": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/react-helmet/-/react-helmet-6.1.0.tgz", + "integrity": "sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw==", + "license": "MIT", + "dependencies": { + "object-assign": "^4.1.1", + "prop-types": "^15.7.2", + "react-fast-compare": "^3.1.1", + "react-side-effect": "^2.1.0" + }, + "peerDependencies": { + "react": ">=16.3.0" + } + }, "node_modules/react-innertext": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/react-innertext/-/react-innertext-1.1.5.tgz", @@ -5048,6 +5077,15 @@ "react": "^17 || ^18" } }, + "node_modules/react-side-effect": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-2.1.2.tgz", + "integrity": "sha512-PVjOcvVOyIILrYoyGEpDN3vmYNLdy1CajSFNt4TDsVQC5KpTijDvWVoR+/7Rz2xT978D8/ZtFceXxzsPwZEDvw==", + "license": "MIT", + "peerDependencies": { + "react": "^16.3.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", diff --git a/package.json b/package.json index a92f78d..8537f2a 100644 --- a/package.json +++ b/package.json @@ -17,8 +17,10 @@ "chartjs-plugin-annotation": "^3.0.1", "chartjs-plugin-crosshair": "^2.0.0", "date-fns": "^3.6.0", + "lodash": "^4.17.21", "react": "^18.3.1", "react-dom": "^18.3.1", + "react-helmet": "^6.1.0", "react-joyride": "^2.9.2", "react-share": "^5.1.0", "styled-components": "^6.1.12" diff --git a/public/temp-disclaimer.png b/public/temp-disclaimer.png new file mode 100644 index 0000000..164c05f Binary files /dev/null and b/public/temp-disclaimer.png differ diff --git a/src/App.jsx b/src/App.jsx index 9bc7a01..ceef109 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -9,6 +9,7 @@ import { ErrorContext } from './contexts/AppContext'; import { VideoProvider } from './contexts/VideoContext'; +import { DataFetchingProvider } from './contexts/DataFetchingContext'; import config from './config.json'; import RotateOverlay from './components/RotateOverlay'; import Tour from './components/Tour'; @@ -34,22 +35,24 @@ export default function App() { - {hasWebGLError ? ( -
- Your WebGL implementation doesn't seem to - support hardware accelerated rendering. - Check your browser settings or if your GPU - is in a blocklist. -
- ) : ( - <> - - - - - - - )} + + {hasWebGLError ? ( +
+ Your WebGL implementation doesn't seem + to support hardware accelerated + rendering. Check your browser settings + or if your GPU is in a blocklist. +
+ ) : ( + <> + + + + + + + )} +
diff --git a/src/components/DataLayerModal.tsx b/src/components/DataLayerModal.tsx index 977497b..26b51a5 100644 --- a/src/components/DataLayerModal.tsx +++ b/src/components/DataLayerModal.tsx @@ -1,10 +1,13 @@ -import React, { useEffect } from 'react'; +import React, { useEffect, useState } from 'react'; export default function DataLayerModal({ closeModal, isFahrenheit, setIsFahrenheit }) { + + const [ showPageTwo, setShowPageTwo ] = useState(false); + useEffect(() => { const handleKeyDown = (event) => { if (event.key === 'Escape') { @@ -43,42 +46,127 @@ export default function DataLayerModal({
-

- How hot could it get on the hottest day in a given year, under different greenhouse gas emission scenarios?

-

- See estimates of annual maxima of daily maximum near-surface air temperature (TASMAX) from NASA Earth Exchange (NEX) Global Daily Downscaled Projections (GDDP) based on simulations of the Coupled Model Intercomparison Project Phase 6 (CMIP6).

-

- The NEX-GDDP-CMIP6 data is calculated on a 0.25°x0.25° latitude and longitude grid and temperature in major cities could be higher than what is displayed within each gridded cell.

-
- - -
+ { showPageTwo ? : } + {/* */} +
); } + +function PageTwo({}){ + // ABG: https://cdn.dribbble.com/users/716122/screenshots/14300379/media/44f698e864671ffe25b844469e40de42.jpg?resize=400x300&vertical=center + return( + <> +
+ Example of spatial average of temperature for Los Angeles, CA +
+ + + ); + +} +function PageOne({}){ + + return ( +
+

+ How hot could it get on the hottest day in a given year, under different greenhouse gas emission scenarios? +

+
+

+ See estimates of annual maxima of daily maximum near-surface air temperature (TASMAX) from NASA Earth Exchange (NEX) Global Daily Downscaled Projections (GDDP) based on simulations of the Coupled Model Intercomparison Project Phase 6 (CMIP6). +

+
+

+ The NEX-GDDP-CMIP6 data is calculated on a 0.25°x0.25° latitude and longitude grid, which is a system of lines used to map the sphere of the Earth. + In some cases, the temperature in major cities could be higher than what’s displayed in the gridded cell because it includes a larger area than just that city. + For example, if you search for a city, such as Los Angeles, CA the average will include the temperature of Los Angeles (which could be higher than average) plus the surrounding geographical area (which could be lower than average). +

+
+

+ Learn more about the + {' '} + + NEX-GDDP-CMIP6 dataset + ! +

+
+ ); +} + +function Buttons({isFahrenheit, setIsFahrenheit}){ + return ( +
+ + +
+ ); +} + +export function Disclaimer({className}){ + + return ( +

+ The NEX-GDDP-CMIP6 data is calculated on a 0.25°x0.25° latitude and longitude grid, which is a system of lines used to map the sphere of the Earth. + In some cases, the temperature in major cities could be higher than what’s displayed in the gridded cell because it includes a larger area than just that city. + For example, if you search for a city, such as Los Angeles, CA the average will include the temperature of Los Angeles (which could be higher than average) plus the surrounding geographical area (which could be lower than average). +

+ + ); + +} + +function SwapButton({setShowPageTwo}){ + return +} diff --git a/src/components/LineChart.jsx b/src/components/LineChart.jsx index d923117..867f11e 100644 --- a/src/components/LineChart.jsx +++ b/src/components/LineChart.jsx @@ -59,7 +59,7 @@ export default function LineChart({ selectedIndex, isFahrenheit }) { borderColor: selectedIndex === 0 ? '#FFFFFFBF' - : 'rgba(239, 239, 240, 0.2)', + : 'rgba(239, 239, 240, 0.4)', borderWidth: selectedIndex === 0 ? 1 : 0.5, fill: false, pointRadius: 0 @@ -72,7 +72,7 @@ export default function LineChart({ selectedIndex, isFahrenheit }) { borderColor: selectedIndex === 1 ? '#FFFFFFBF' - : 'rgba(239, 239, 240, 0.2)', + : 'rgba(239, 239, 240, 0.4)', borderWidth: selectedIndex === 1 ? 1 : 0.5, fill: false, pointRadius: 0 @@ -85,7 +85,7 @@ export default function LineChart({ selectedIndex, isFahrenheit }) { borderColor: selectedIndex === 2 ? '#FFFFFFBF' - : 'rgba(239, 239, 240, 0.2)', + : 'rgba(239, 239, 240, 0.4)', borderWidth: selectedIndex === 2 ? 1 : 0.5, fill: false, pointRadius: 0 @@ -98,7 +98,7 @@ export default function LineChart({ selectedIndex, isFahrenheit }) { borderColor: selectedIndex === 3 ? '#FFFFFFBF' - : 'rgba(239, 239, 240, 0.2)', + : 'rgba(239, 239, 240, 0.4)', borderWidth: selectedIndex === 3 ? 1 : 0.5, fill: false, pointRadius: 0 diff --git a/src/components/Map.jsx b/src/components/Map.jsx index dce9a49..4ebd4bc 100644 --- a/src/components/Map.jsx +++ b/src/components/Map.jsx @@ -16,6 +16,7 @@ import SceneView from '@arcgis/core/views/SceneView'; import Search from '@arcgis/core/widgets/Search'; import Popup from '@arcgis/core/widgets/Popup'; import { VideoContext } from '../contexts/VideoContext'; +import { DataFetchingContext } from '../contexts/DataFetchingContext'; import { ChartDataContext, MapViewContext, @@ -27,14 +28,17 @@ import { FRAME_DURATION, TOTAL_FRAMES, FPS } from '../utils/constants'; import { Transition } from '@headlessui/react'; import Expand from '@arcgis/core/widgets/Expand'; import { isMobileDevice } from '../utils/helpers'; -import { - bufferSymbol, - crosshairSymbol, - createCornerAngles -} from '../utils/sceneHelpers'; +import { crosshairSymbol, bufferSymbol } from '../utils/sceneHelpers'; +import { debounce } from 'lodash'; import ShareModal from './ShareModal'; +const defaultScenePoint = new Point({ + longitude: -77.0369, + latitude: 38.9072, + spatialReference: { wkid: 4326 } +}); + const createFeatureLayer = (url) => new FeatureLayer({ url, @@ -59,6 +63,8 @@ export default function Home() { const { mapView, setMapView } = useContext(MapViewContext); const { setChartData } = useContext(ChartDataContext); const { dataSelection } = useContext(DataSelectionContext); + const { setIsLoading, setIsInvalidData } = useContext(DataFetchingContext); + const [selectedDataset, selectedVariable] = dataSelection; const selectedDatasetVariables = config.datasets[0].variables; @@ -81,7 +87,7 @@ export default function Home() { let draggingInsideBuffer = false; let initialCamera; - let lastKnownPoint; + let lastKnownPoint = defaultScenePoint; let bufferLayer; let pointLayer; @@ -93,9 +99,22 @@ export default function Home() { return { bufferLayer, pointLayer }; }; - const createBuffer = async (point, pointLayer, bufferLayer) => { - const sideLength = 10; + const createBuffer = async (point, pointLayer, bufferLayer, view) => { + const zoomLevel = view.zoom; + + const baseMiddleRadius = 300; + const scaleFactor = zoomLevel / 3; + + const middleRadius = baseMiddleRadius / scaleFactor; + + const middleBufferSymbol = { + type: 'simple-fill', + color: [150, 50, 0, 0.0], + outline: { color: [255, 255, 255, 1], width: 2, style:"dash"} + }; + + const sideLength = 0.25*scaleFactor; const squarePolygon = { type: 'polygon', rings: [ @@ -110,52 +129,43 @@ export default function Home() { spatialReference: point.spatialReference }; - const cornerAngles = createCornerAngles(point, sideLength); - - const angleSymbol = { - type: 'simple-line', - color: [255, 255, 255], - width: 1 - }; - const bufferGraphic = new Graphic({ geometry: squarePolygon, symbol: bufferSymbol }); - if (!pointLayer.graphics.length) { - pointLayer.add( - new Graphic({ geometry: point, symbol: crosshairSymbol }) - ); - bufferLayer.add(bufferGraphic); - cornerAngles.forEach((cornerGeometry) => { - bufferLayer.add( - new Graphic({ - geometry: cornerGeometry, - symbol: angleSymbol - }) - ); - }); - } else { - pointLayer.graphics.getItemAt(0).geometry = point; + const middleCircle = await geometryEngineAsync.geodesicBuffer( + point, + middleRadius, + 'kilometers' + ); - bufferLayer.graphics.getItemAt(0).geometry = squarePolygon; - bufferLayer.graphics.getItemAt(0).symbol = bufferSymbol; + const middleBufferGraphic = new Graphic({ + geometry: middleCircle, + symbol: middleBufferSymbol + }); + + const crosshairGraphic = new Graphic({ + geometry: point, + symbol: crosshairSymbol + }); - bufferLayer.removeAll(); + if (!pointLayer.graphics.length) { + pointLayer.add(crosshairGraphic); + bufferLayer.add(middleBufferGraphic); bufferLayer.add(bufferGraphic); - cornerAngles.forEach((cornerGeometry) => { - bufferLayer.add( - new Graphic({ - geometry: cornerGeometry, - symbol: angleSymbol - }) - ); - }); + } else { + pointLayer.graphics.getItemAt(0).geometry = point; + bufferLayer.graphics.getItemAt(0).geometry = middleCircle; + bufferLayer.graphics.getItemAt(0).symbol = middleBufferSymbol; + bufferLayer.graphics.getItemAt(1).geometry = squarePolygon; + bufferLayer.graphics.getItemAt(1).symbol = bufferSymbol; } }; + const debouncedCreateBuffer = debounce(createBuffer, 100); + const handleDragStart = async (event, view, bufferLayer) => { const startPoint = view.toMap({ x: event.x, y: event.y }); const bufferGraphic = bufferLayer.graphics.getItemAt(0); @@ -180,7 +190,7 @@ export default function Home() { if (updatedPoint) { event.stopPropagation(); - await createBuffer(updatedPoint, pointLayer, bufferLayer); + await createBuffer(updatedPoint, pointLayer, bufferLayer, view); lastKnownPoint = updatedPoint; } } @@ -341,7 +351,12 @@ export default function Home() { ], zoom: 1 }); - await createBuffer(initialCenterPoint, pointLayer, bufferLayer); + await createBuffer( + initialCenterPoint, + pointLayer, + bufferLayer, + view + ); await handleMapClick({ mapPoint: initialCenterPoint }); view.on('drag', (event) => { @@ -358,11 +373,22 @@ export default function Home() { const mapPoint = view.toMap(event); if (mapPoint) { - await createBuffer(mapPoint, pointLayer, bufferLayer); + await createBuffer(mapPoint, pointLayer, bufferLayer, view); lastKnownPoint = mapPoint; await handleMapClick({ mapPoint }, view); } }); + + view.watch('zoom', () => { + if (lastKnownPoint) { + debouncedCreateBuffer( + lastKnownPoint, + pointLayer, + bufferLayer, + view + ); + } + }); }).catch((error) => { if (error.name.includes('webgl')) { setHasWebGLError(true); @@ -419,7 +445,7 @@ export default function Home() { view.graphics.removeAll(); - await createBuffer(point, pointLayer, bufferLayer); + await createBuffer(point, pointLayer, bufferLayer, view); lastKnownPoint = point; await handleMapClick({ mapPoint: point }, view); @@ -453,51 +479,63 @@ export default function Home() { const handleMapClick = async (event, view) => { const [_, selectedVariable] = dataSelection; + // round event latitude and longitude to the nearest quarter + // degree to snap to grid + event.mapPoint.latitude = Math.round(event.mapPoint.latitude * 4) / 4; + event.mapPoint.longitude = Math.round(event.mapPoint.longitude * 4) / 4; + const dataIsValid = await handleImageServiceRequest( event, selectedVariable, - setChartData + setChartData, + setIsLoading, + setIsInvalidData ); if (!dataIsValid) { - const defaultScenePoint = new Point({ - longitude: -77.0369, - latitude: 38.9072, - spatialReference: { wkid: 4326 } - }); - - if ( - Math.abs( - event.mapPoint.longitude - defaultScenePoint.longitude - ) > 0.0001 || - Math.abs(event.mapPoint.latitude - defaultScenePoint.latitude) > - 0.0001 - ) { - await view.goTo({ - center: [ - defaultScenePoint.longitude, - defaultScenePoint.latitude - ], - zoom: 10 - }); - - await createBuffer(defaultScenePoint, pointLayer, bufferLayer); - - const eventForDC = { mapPoint: defaultScenePoint }; - const dataIsValidDC = await handleImageServiceRequest( - eventForDC, - selectedVariable, - setChartData - ); + lastKnownPoint = defaultScenePoint; + + setTimeout(async () => { + if ( + Math.abs( + event.mapPoint.longitude - defaultScenePoint.longitude + ) > 0.0001 || + Math.abs( + event.mapPoint.latitude - defaultScenePoint.latitude + ) > 0.0001 + ) { + await view.goTo({ + center: [ + defaultScenePoint.longitude, + defaultScenePoint.latitude + ], + zoom: 10 + }); - if (!dataIsValidDC) { + await createBuffer( + defaultScenePoint, + pointLayer, + bufferLayer, + view + ); + + const eventForDC = { mapPoint: defaultScenePoint }; + const dataIsValidDC = await handleImageServiceRequest( + eventForDC, + selectedVariable, + setChartData, + setIsLoading, + setIsInvalidData + ); + + if (!dataIsValidDC) { + console.error('Data is invalid even for Washington DC'); + } + } else { console.error('Data is invalid even for Washington DC'); setChartData([]); } - } else { - console.error('Data is invalid even for Washington DC'); - setChartData([]); - } + }, 1000); } }; diff --git a/src/components/Panel.jsx b/src/components/Panel.jsx index 323e737..3e4de3c 100644 --- a/src/components/Panel.jsx +++ b/src/components/Panel.jsx @@ -1,11 +1,12 @@ import LineChart from './LineChart'; -import { useContext, useState, useMemo } from 'react'; +import { useContext, useState, useMemo, useEffect } from 'react'; import config from '../config.json'; import { DataSelectionContext, MapViewContext, ChartDataContext } from '../contexts/AppContext'; +import { DataFetchingContext } from '../contexts/DataFetchingContext'; import { VideoContext } from '../contexts/VideoContext'; import { PlayIcon, PauseIcon } from '@heroicons/react/24/solid'; import { FPS, TOTAL_FRAMES } from '../utils/constants'; @@ -26,6 +27,9 @@ export default function Panel() { } = useContext(VideoContext); const { mapView } = useContext(MapViewContext); const { setDataSelection } = useContext(DataSelectionContext); + const { isLoading, isInvalidData } = useContext(DataFetchingContext); + const [wasInvalidShown, setWasInvalidShown] = useState(false); + const [isFahrenheit, setIsFahrenheit] = useState(true); const { chartData } = useContext(ChartDataContext); @@ -117,6 +121,16 @@ export default function Panel() { ); }; + useEffect(() => { + if (isInvalidData) { + setWasInvalidShown(true); + } else { + // Reset wasInvalidShown after a short delay or when the invalid message is gone + const timer = setTimeout(() => setWasInvalidShown(false), 2000); // 2-second delay + return () => clearTimeout(timer); // Cleanup the timer on component unmount or update + } + }, [isInvalidData]); + return ( <> {isModalOpen && ( @@ -215,85 +229,122 @@ export default function Panel() { className="flex-1" style={{ minWidth: '600px' }} > -
- {getMaxValuesForYears.map( - (item, idx) => ( -
- {item.value === 'N/A' ? ( -
- ) : ( + {/* Show fetching message only if loading, not showing invalid message, and if the invalid message wasn't recently shown */} + {isLoading && + !isInvalidData && + !wasInvalidShown && ( +
+
+

+ Fetching temperature + information for your + selected location... +

+
+ )} + + {/* Show invalid data message if data is invalid */} + {isInvalidData && ( +
+
+

+ This dataset does not provide + temperature information for + oceans. Moving the map marker to + the default location... +

+
+ )} + + {/* Loading or Invalid data message handling */} + {!isLoading && !isInvalidData && ( + <> +
+ {getMaxValuesForYears.map( + (item, idx) => (
- handleYearClick( - item.year - ) - } + key={idx} + className="relative text-center" > -
+ ) : ( +
+ handleYearClick( + item.year ) - ) - }} - > - - {item.value} - - - ° - {isFahrenheit - ? 'F' - : 'C'} - -
- - {item.year} - +
+ + { + item.value + } + + + ° + {isFahrenheit + ? 'F' + : 'C'} + +
+ + { + item.year + } + +
+ )}
- )} -
- ) - )} -
+ ) + )} + -
- -
+
+ +
+ + )} diff --git a/src/components/Tour.jsx b/src/components/Tour.jsx index 14f7254..cd33134 100644 --- a/src/components/Tour.jsx +++ b/src/components/Tour.jsx @@ -3,6 +3,7 @@ import Joyride from 'react-joyride'; import TourButton from './TourButton'; import TourTooltip from './TourTooltip'; import useLocalStorage from '../hooks/useLocalStorage'; +import Disclaimer from './DataLayerModal'; export default function Tour() { const [tourComplete, setTourComplete] = useLocalStorage( @@ -18,14 +19,33 @@ export default function Tour() { title: 'Welcome to the', name: 'Mobile Climate Mapper', content: - 'The Mobile Climate Mapper is an extension of NASA’s Earth Information Center exhibit at the Smithsonian National Museum of Natural History. Use this tool to explore how climate change may affect temperatures at any location in the world.', + 'The Mobile Climate Mapper is an extension of NASA’s Earth Information Center exhibit at the Smithsonian National Museum of Natural History. Use this tool to explore how climate change may affect temperatures in any geographic area in the world.', placement: 'center', disableBeacon: true }, + { + target: 'body', + title: 'About the Data', + content:
+ Example of spatial average of temperature for Los Angeles, CA +

+ The NEX-GDDP-CMIP6 data is calculated on a 0.25°x0.25° latitude and longitude grid, which is a system of lines used to map the sphere of the Earth. + In some cases, the temperature in major cities could be higher than what’s displayed in the gridded cell because it includes a larger area than just that city. + For example, if you search for a city, such as Los Angeles, CA the average will include the temperature of Los Angeles (which could be higher than average) plus the surrounding geographical area (which could be lower than average). + +

+
, + placement: 'center', + disableBeacon: true + }, { target: '.map', content: - 'Tap anywhere on the map to view how temperatures are projected to change at that location', + 'Tap anywhere on the map to view how temperatures are projected to change in that geographic area', placement: 'bottom', disableBeacon: true }, diff --git a/src/contexts/DataFetchingContext.jsx b/src/contexts/DataFetchingContext.jsx new file mode 100644 index 0000000..b497f90 --- /dev/null +++ b/src/contexts/DataFetchingContext.jsx @@ -0,0 +1,26 @@ +import React, { useState, createContext } from 'react'; + +export const DataFetchingContext = createContext({ + isLoading: false, + setIsLoading: () => {}, + isInvalidData: false, + setIsInvalidData: () => {} +}); + +export const DataFetchingProvider = ({ children }) => { + const [isLoading, setIsLoading] = useState(false); + const [isInvalidData, setIsInvalidData] = useState(false); + + return ( + + {children} + + ); +}; diff --git a/src/index.css b/src/index.css index 6218bf5..37df19f 100644 --- a/src/index.css +++ b/src/index.css @@ -116,4 +116,8 @@ .chartjs-tooltip-hidden { opacity: 0; visibility: hidden; + } + + .tooltip__content{ + padding-bottom:0 !important; } \ No newline at end of file diff --git a/src/utils/sceneHelpers.ts b/src/utils/sceneHelpers.ts index d3014f7..bd4c707 100644 --- a/src/utils/sceneHelpers.ts +++ b/src/utils/sceneHelpers.ts @@ -1,14 +1,14 @@ export const bufferSymbol = { type: 'simple-fill', - color: [5, 80, 216, 0.5], - outline: { color: [255, 255, 255, 0], width: 0 } + color: [5, 80, 216, 0.4], + outline: { color: [255, 255, 255, 1], width: 0.5 } }; export const crosshairSymbol = { type: 'simple-marker', style: 'cross', color: [5, 80, 216], - size: 12, + size: 8, outline: { color: [255, 255, 255], width: 1 diff --git a/src/utils/utils.js b/src/utils/utils.js index c40505f..c89d5dc 100644 --- a/src/utils/utils.js +++ b/src/utils/utils.js @@ -1,7 +1,9 @@ - -export const handleImageServiceRequest = async (event, variable, setChartData) => { +export const handleImageServiceRequest = async (event, variable, setChartData, setIsLoading, setIsInvalidData) => { const point = event.mapPoint; + setIsLoading(true); + setIsInvalidData(false); + const url = new URL(variable.service + "/getSamples"); url.searchParams.append("geometry", `${point.longitude},${point.latitude}`); @@ -33,7 +35,7 @@ export const handleImageServiceRequest = async (event, variable, setChartData) = try { const response = await fetch(url.toString(), { method: 'GET' }); const results = await response.json(); - // const results = mockData; + // const results = mockData; // Uncomment this line to use mockData during testing let invalidData = false; @@ -97,14 +99,21 @@ export const handleImageServiceRequest = async (event, variable, setChartData) = })); setChartData(chartData); + setIsLoading(false); + setIsInvalidData(false); + return true; + } else { + setIsInvalidData(true); } } else { invalidData = true; + setIsInvalidData(true); } return !invalidData; } catch (err) { console.error('Error fetching data from ImageService:', err); + setIsLoading(false); return false; } -}; \ No newline at end of file +};