diff --git a/src/components/SessionArea/sessionSlice.js b/src/components/SessionArea/sessionSlice.js index db807a5..3f375c1 100755 --- a/src/components/SessionArea/sessionSlice.js +++ b/src/components/SessionArea/sessionSlice.js @@ -27,6 +27,7 @@ export const initialState = { selectedTimeEntity: undefined, currentAvailableTimeRange: undefined, + populatedDates: undefined, currentData: undefined, // the index in the array of currently available dates currentStartDate: undefined, @@ -144,6 +145,9 @@ const SessionSlice = createSlice({ setCurrentAvailableTimeRange: (state, action) => { state.currentAvailableTimeRange = action?.payload }, + setPopulatedDates: (state, action) => { + state.populatedDates = action?.payload + }, // args: currentData - the data for the currently selected time unit in the bottom slider setCurrentData: (state, action) => { state.currentData = action?.payload @@ -214,6 +218,7 @@ export const { setSelectedTimeEntity, setCurrentAvailableTimeRange, + setPopulatedDates, setCurrentData, setCurrentStartDate, setCurrentEndDate, diff --git a/src/components/SessionArea/sessionSlice.selectors.js b/src/components/SessionArea/sessionSlice.selectors.js index 1ff7ffa..28940c0 100644 --- a/src/components/SessionArea/sessionSlice.selectors.js +++ b/src/components/SessionArea/sessionSlice.selectors.js @@ -26,6 +26,7 @@ const selectCurrentTemporalResolution = state => state.session.currentTemporalRe const selectSelectedTimeRangeForCurrentData = state => state.session.selectedTimeRangeForCurrentData const selectSelectedTimeEntity = state => state.session.selectedTimeEntity const selectCurrentAvailableTimeRange = state => state.session.currentAvailableTimeRange +const selectPopulatedDates = state => state.session.populatedDates const selectCurrentData = state => state.session.currentData const selectCurrentStartDate = state => state.session.currentStartDate const selectCurrentEndDate = state => state.session.currentEndDate @@ -126,6 +127,7 @@ const session = { selectSpatialResolutionsForCurrentCategory, selectTemporalResolutionsForCurrentCategory, selectCurrentAvailableTimeRange, + selectPopulatedDates, selectCurrentData, selectCurrentBoundaries, diff --git a/src/pages/Dashboard/Dashboard.js b/src/pages/Dashboard/Dashboard.js index 33e2063..c73f008 100644 --- a/src/pages/Dashboard/Dashboard.js +++ b/src/pages/Dashboard/Dashboard.js @@ -37,6 +37,7 @@ import { setCurrentMaxValue, setRedrawKey, setCurrentAvailableTimeRange, + setPopulatedDates, setModal } from "../../components/SessionArea/sessionSlice" import session from "../../components/SessionArea/sessionSlice.selectors" @@ -415,6 +416,7 @@ const Dashboard = () => { } const availableTimeRange = response.all_dates dispatch(setCurrentAvailableTimeRange(availableTimeRange)) + dispatch(setPopulatedDates(response.populated_dates || response.all_dates)) console.debug("Available time range: ", availableTimeRange) // set the selected time range to the first x as defined by the temporal resolution config diff --git a/src/pages/Dashboard/components/CurrentTimeUnitSlider/CurrentTimeUnitSlider.js b/src/pages/Dashboard/components/CurrentTimeUnitSlider/CurrentTimeUnitSlider.js index dedff5c..0b3e983 100755 --- a/src/pages/Dashboard/components/CurrentTimeUnitSlider/CurrentTimeUnitSlider.js +++ b/src/pages/Dashboard/components/CurrentTimeUnitSlider/CurrentTimeUnitSlider.js @@ -1,7 +1,7 @@ // This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. // If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. -import React, { useState, useEffect } from "react" +import React, { useState, useEffect, useMemo } from "react" import { DateTime } from "luxon" import { useSelector, useDispatch } from "react-redux" import styles from "./CurrentTimeUnitSlider.module.css" @@ -24,6 +24,8 @@ const CurrentTimeUnitSlider = () => { const currentIndicator = useSelector(session.selectCurrentIndicator) const currentSpatialResolution = useSelector(session.selectCurrentSpatialResolution) const currentTemporalResolution = useSelector(session.selectCurrentTemporalResolution) + const populatedDates = useSelector(session.selectPopulatedDates) + const populatedDatesSet = useMemo(() => populatedDates ? new Set(populatedDates) : null, [populatedDates]) // local state const [previouslySelectedTimeRangeForCurrentData, setPreviouslySelectedTimeRangeForCurrentData] = @@ -168,8 +170,36 @@ const CurrentTimeUnitSlider = () => { min={selectedTimeRangeForCurrentData[0]} max={selectedTimeRangeForCurrentData[1]} onChange={values => { - setPreviouslySelectedTimeEntity(selectedTimeEntity) - dispatch(setSelectedTimeEntity(values)) + const newIndex = values[0] + const prevIndex = Array.isArray(selectedTimeEntity) ? selectedTimeEntity[0] : selectedTimeEntity + const newDate = currentAvailableTimeRange[newIndex] + + if (!populatedDatesSet || populatedDatesSet.has(newDate)) { + setPreviouslySelectedTimeEntity(selectedTimeEntity) + dispatch(setSelectedTimeEntity(values)) + return + } + + // Snap to nearest populated date in the direction of travel + const movingRight = newIndex > prevIndex + const [rangeMin, rangeMax] = selectedTimeRangeForCurrentData + if (movingRight) { + for (let i = newIndex + 1; i <= rangeMax; i++) { + if (populatedDatesSet.has(currentAvailableTimeRange[i])) { + setPreviouslySelectedTimeEntity(selectedTimeEntity) + dispatch(setSelectedTimeEntity([i])) + return + } + } + } else { + for (let i = newIndex - 1; i >= rangeMin; i--) { + if (populatedDatesSet.has(currentAvailableTimeRange[i])) { + setPreviouslySelectedTimeEntity(selectedTimeEntity) + dispatch(setSelectedTimeEntity([i])) + return + } + } + } }} labels={labels} isRange={false}