Skip to content

Commit

Permalink
Merge pull request #43 from NASA-IMPACT/eic-address-findings
Browse files Browse the repository at this point in the history
Addressing a few findings
  • Loading branch information
dzole0311 authored Oct 3, 2024
2 parents 0115b46 + 31d0a7b commit 532d05c
Show file tree
Hide file tree
Showing 7 changed files with 145 additions and 58 deletions.
8 changes: 6 additions & 2 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,20 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="./src/assets/eic.svg" />
<link rel='icon' sizes='any' href='https://earth.gov/meta/favicon.ico' />
<link rel='icon' type='image/svg+xml' href='https://earth.gov/meta/icon.svg' />
<link rel='apple-touch-icon' sizes='180x180' href='https://earth.gov/meta/apple-touch-icon.png' />

<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Manrope:[email protected]&display=swap" rel="stylesheet">
<title>EIC Mobile</title>
<title>Mobile Climate Mapper</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="./src/main.jsx"></script>
</body>
</html>


2 changes: 1 addition & 1 deletion src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import Tour from './components/Tour';

export default function App() {
const defaultDataset = config.datasets[0];
const defaultVariable = defaultDataset.variables[0];
const defaultVariable = defaultDataset.variables[1];
const [dataSelection, setDataSelection] = useState([
defaultDataset,
defaultVariable
Expand Down
154 changes: 112 additions & 42 deletions src/components/Map.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
} from '../contexts/AppContext';
import * as geometryEngineAsync from '@arcgis/core/geometry/geometryEngineAsync';
import { handleImageServiceRequest } from '../utils/utils';
import { FPS, FRAME_DURATION, TOTAL_FRAMES } from '../utils/constants';
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';
Expand Down Expand Up @@ -59,13 +59,21 @@ export default function Home() {
const { mapView, setMapView } = useContext(MapViewContext);
const { setChartData } = useContext(ChartDataContext);
const { dataSelection } = useContext(DataSelectionContext);
const [selectedDataset, selectedVariable] = dataSelection;

const selectedDatasetVariables = config.datasets[0].variables;

const selectedVariableIndex = selectedDatasetVariables.findIndex(
(variable) => variable.name === selectedVariable.name
);

const [showTransition, setShowTransition] = useState(true);
const [isShareMenuOpen, setIsShareMenuOpen] = useState(false);
const [isBlurActive, setIsBlurActive] = useState(false);

const mapDiv = useRef(null);
const blurOverlayRef = useRef(null);
const searchExpandRef = useRef(null);

const [allVideosLoaded, setAllVideosLoaded] = useState(false);
let totalVideos = 4;
Expand Down Expand Up @@ -209,7 +217,7 @@ export default function Home() {

const fallbackImageUrl = variable.fallbackImage;

const element = new VideoElement({
const videoElement = new VideoElement({
video: videoUrl,
georeference: new ExtentAndRotationGeoreference({
extent: new Extent({
Expand All @@ -235,24 +243,32 @@ export default function Home() {
})
});

const mediaLayer = new MediaLayer({
source: [imageElement, element],
title: variable.name,
zIndex: index,
opacity: variable.name === '126 - Low' ? 1 : 0
const imageMediaLayer = new MediaLayer({
source: [imageElement],
title: `${variable.name}_image`,
zIndex: index * 2,
opacity: variable.name === 'Intermediate' ? 1 : 0
});

layerList.push(mediaLayer);
const videoMediaLayer = new MediaLayer({
source: [videoElement],
title: `${variable.name}_video`,
zIndex: index * 2 + 1,
opacity: variable.name === 'Intermediate' ? 1 : 0
});

layerList.push(imageMediaLayer, videoMediaLayer);

console.log(
`Initializing video for: ${import.meta.env.BASE_URL}${variable.name}`,
`Initializing video for: ${import.meta.env.BASE_URL}${
variable.name
}`,
variable.video
);

element
.when((status) => {
const videoElement = element.content;
videoRefs.current[videoIndex] = videoElement;
videoElement
.when(() => {
videoRefs.current[index] = videoElement.content;
loadedVideos++;
console.log(
`Video initialized for: ${variable.name}`,
Expand All @@ -263,7 +279,6 @@ export default function Home() {
videoElement.currentTime = currentFrame;
videoIndex++;

console.log(loadedVideos, totalVideos);
if (loadedVideos === totalVideos) {
setAllVideosLoaded(true);
}
Expand Down Expand Up @@ -365,25 +380,32 @@ export default function Home() {
mode: 'floating'
});

searchExpandRef.current = searchExpand;
view.ui.add(searchExpand, 'top-right');

// Toggle blur state when searchExpand is expanded or collapsed
searchExpand.watch('expanded', (isExpanded) => {
const blurOverlay = blurOverlayRef.current;

if (isExpanded && blurOverlay) {
if (!blurOverlay) return;

if (isExpanded) {
setIsBlurActive(true);
blurOverlay.classList.add('active');
} else if (blurOverlay) {
} else {
setIsBlurActive(false);
blurOverlay.classList.remove('active');
}
});

if (blurOverlayRef.current) {
blurOverlayRef.current.addEventListener('click', () => {
searchExpand.collapse();
});
}
// Reset blur state when a search starts
searchWidget.on('search-start', () => {
const blurOverlay = blurOverlayRef.current;
if (blurOverlay) {
setIsBlurActive(false);
blurOverlay.classList.remove('active');
}
});

searchWidget.on('select-result', async (event) => {
const result = event.result;
Expand Down Expand Up @@ -480,7 +502,7 @@ export default function Home() {
};

function isSeekable(videoElement, time) {
for (var i = 0; i < videoElement.seekable.length; i++) {
for (let i = 0; i < videoElement.seekable.length; i++) {
if (
time >= videoElement.seekable.start(i) &&
time <= videoElement.seekable.end(i)
Expand All @@ -502,9 +524,7 @@ export default function Home() {
useEffect(() => {
let animationFrameId;

console.log(allVideosLoaded);
if (isPlaying && allVideosLoaded) {
// Only start the animation frame if all videos are loaded
const totalFrames = TOTAL_FRAMES;
const frameDuration = FRAME_DURATION;
let lastFrameTime = 0;
Expand All @@ -524,22 +544,24 @@ export default function Home() {
const newFrame = prevFrame + framesToAdvance;

if (newFrame >= totalFrames) {
videoRefs.current.forEach((videoElement) => {
if (videoElement) {
videoElement.currentTime = 0;
}
});
const currentVideo =
videoRefs.current[selectedVariableIndex];

if (currentVideo) {
currentVideo.currentTime = 0;
}
lastFrameTime = timestamp;
return 0;
} else {
videoRefs.current.forEach((videoElement) => {
if (
videoElement &&
videoElement.readyState >= 2
) {
videoElement.currentTime = newFrame / FPS;
const currentVideo =
videoRefs.current[selectedVariableIndex];

if (currentVideo && currentVideo.readyState >= 2) {
const seekTime = newFrame / FPS;
if (isSeekable(currentVideo, seekTime)) {
currentVideo.currentTime = seekTime;
}
});
}
lastFrameTime += framesToAdvance * frameDuration;
return newFrame;
}
Expand All @@ -555,23 +577,71 @@ export default function Home() {
return () => {
if (animationFrameId) cancelAnimationFrame(animationFrameId);
};
}, [isPlaying, videoRefs, allVideosLoaded, setCurrentFrame]);
}, [
isPlaying,
videoRefs,
allVideosLoaded,
setCurrentFrame,
selectedVariableIndex
]);

// (sigh) We need the blur overlay to make the search more prominent, but the map attributions
// still show up on top of the blur. To avoid that, we manually hide the attributions when
// the blur is active, and bring them back once the blur is off.
useEffect(() => {
const attribution = document.querySelector('.esri-attribution');
if ((isBlurActive || showTransition) && attribution) {
attribution.style.display = 'none';
} else if (attribution) {
attribution.style.display = 'flex';

if (attribution) {
attribution.style.display =
isBlurActive || showTransition ? 'none' : 'flex';
}

const handleDocumentClick = (event) => {
const searchExpand = searchExpandRef.current;
const blurOverlay = blurOverlayRef.current;

if (!searchExpand || !blurOverlay) return;

const isClickInsideSearchExpand = searchExpand.domNode.contains(
event.target
);
const isClickInsideBlurOverlay = blurOverlay.contains(event.target);

if (
isBlurActive &&
!isClickInsideSearchExpand &&
!isClickInsideBlurOverlay
) {
searchExpand.collapse();
}
};

const handleBlurOverlayClick = () => {
const searchExpand = searchExpandRef.current;
if (searchExpand) {
searchExpand.collapse();
}
};

document.addEventListener('click', handleDocumentClick);
blurOverlayRef.current?.addEventListener(
'click',
handleBlurOverlayClick
);

return () => {
document.removeEventListener('click', handleDocumentClick);
blurOverlayRef.current?.removeEventListener(
'click',
handleBlurOverlayClick
);
};
}, [isBlurActive, showTransition]);

return (
<div>
<Transition
show={showTransition}
show={!allVideosLoaded}
enter="transition-opacity duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
Expand Down
11 changes: 4 additions & 7 deletions src/components/Panel.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export default function Panel() {
const { chartData } = useContext(ChartDataContext);

const [selectedDatasetIndex, setSelectedDatasetIndex] = useState(0);
const [selectedVariableIndex, setSelectedVariableIndex] = useState(0);
const [selectedVariableIndex, setSelectedVariableIndex] = useState(1);

const [isModalOpen, setIsModalOpen] = useState(false);
const [isDataLayerModalOpen, setIsDataLayerModalOpen] = useState(false);
Expand Down Expand Up @@ -68,12 +68,9 @@ export default function Panel() {
setDataSelection([selectedDataset, selectedVariable]);

mapView.map.layers.forEach((layer) => {
if (
layer.title === selectedVariable.name ||
layer.title === 'World Countries' ||
layer.title === 'Geodesic-Buffer' ||
layer.title === 'Geodesic-Point'
) {
if (layer.type !== 'media') return;

if (layer.title.includes(selectedVariable.name)) {
layer.opacity = 1;
} else {
layer.opacity = 0;
Expand Down
18 changes: 17 additions & 1 deletion src/components/ScenarioPickerModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,10 @@ export default function ScenarioPickerModal({
? 'bg-[#010E26BF] text-white'
: 'hover:bg-[#FFFFFF1A] bg-transparent'
}`}
onClick={() => changeVariable(variableIndex)}
onClick={() => {
changeVariable(variableIndex);
closeModal()
}}
>
<div className="w-[24px] h-[24px] flex-shrink-0 flex items-center justify-center md:w-[32px] md:h-[32px]">
<div
Expand Down Expand Up @@ -90,6 +93,19 @@ export default function ScenarioPickerModal({
</div>
</div>
))}

<div className="w-full border-t border-[#FFFFFF1A] mt-10"></div>

<div className="mt-2 text-left">
<a
href="https://earth.gov/stories/si_nmnh"
target="_blank"
rel="noopener noreferrer"
className="text-[14px] leading-[21px] font-normal text-white opacity-50"
>
Learn more at https://earth.gov/stories/si_nmnh
</a>
</div>
</div>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/components/Tour.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export default function Tour() {
{
target: 'body',
title: 'Welcome to the',
name: 'Mobile Climate Mapper!',
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.',
placement: 'center',
Expand Down
8 changes: 4 additions & 4 deletions src/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"datasetVariablesTagline": "GHG Emissions Scenario",
"variables": [
{
"name": "126 - Low",
"name": "Low",
"description": "Carbon dioxide emissions decline to net zero around 2070, followed by varying levels of reductions in existing carbon dioxide in the atmosphere.",
"variable": "tasmax_ssp126",
"unit": "Heatmax",
Expand Down Expand Up @@ -37,7 +37,7 @@
]
},
{
"name": "245 - Intermediate",
"name": "Intermediate",
"description": "Carbon dioxide emissions remain around current levels until the middle of the 21st century.",
"unit": "Heatmax",
"variable": "tasmax_ssp245",
Expand Down Expand Up @@ -69,7 +69,7 @@
]
},
{
"name": "370 - High",
"name": "High",
"description": "Carbon dioxide emissions roughly double from current levels by 2100.",
"unit": "Heatmax",
"variable": "tasmax_ssp370",
Expand Down Expand Up @@ -101,7 +101,7 @@
]
},
{
"name": "585 - Very High",
"name": "Very High",
"description": "Carbon dioxide emissions roughly double from current levels by 2050.",
"unit": "Heatmax",
"video": "./tasmax_monthly_ssp585_max12_8192_1024x512.mp4",
Expand Down

0 comments on commit 532d05c

Please sign in to comment.