diff --git a/assets/src/scripts/components/hydrograph/index.js b/assets/src/scripts/components/hydrograph/index.js index 190b649069c8fd67b8c2c96a9149b650fdc71603..3c3cf715c9cb1e673ec97f6f59c2450e903274f7 100644 --- a/assets/src/scripts/components/hydrograph/index.js +++ b/assets/src/scripts/components/hydrograph/index.js @@ -355,6 +355,13 @@ const controlDisplay = function (elem, showElem) { elem.attr('hidden', showElem ? null : true); }; +const loadingIndicator = function(elem, {showLoadingIndicator, sizeClass}) { + elem.select('.loading-indicator').remove(); + if (showLoadingIndicator) { + elem.append('i') + .attr('class', `loading-indicator fas ${sizeClass} fa-spin fa-spinner`); + } +}; const createDaterangeControls = function(elem, {siteno, showControls}) { const DATE_RANGE = [{ @@ -372,10 +379,17 @@ const createDaterangeControls = function(elem, {siteno, showControls}) { }]; elem.select('#ts-daterange-select-container').remove(); if (showControls) { - const container = elem.insert('ul', ':first-child') - .attr('id', 'ts-daterange-select-container') + const container = elem.insert('div', ':nth-child(2)') + .attr('id', 'ts-daterange-select-container'); + const listContainer = container.append('ul') .attr('class', 'usa-fieldset-inputs usa-unstyled-list'); - const li = container.selectAll('li') + container.append('div') + .attr('class', 'loading-indicator-container') + .call(link(loadingIndicator, createStructuredSelector({ + showLoadingIndicator: isLoadingTS('current'), + sizeClass:() => 'fa-lg' + }))); + const li = listContainer.selectAll('li') .data(DATE_RANGE) .enter().append('li'); li.append('input') @@ -408,14 +422,11 @@ const attachToNode = function (store, node, {siteno} = {}) { store.dispatch(Actions.resizeUI(window.innerWidth, node.offsetWidth)); select(node) .call(provide(store)); - select(node) - .call(link(function(elem, isLoadingCurrentTS) { - elem.select('.loading-indicator').remove(); - if (isLoadingCurrentTS) { - select(elem).append('i') - .attr('class', 'fas fa-spinner fa-spin'); - } - }, isLoadingTS('current:P7D'))); + select(node).select('.loading-indicator-container') + .call(link(loadingIndicator, createStructuredSelector({ + showLoadingIndicator: isLoadingTS('current', 'P7D'), + sizeClass: () =>'fa-3x' + }))); select(node) .call(link(createDaterangeControls, createStructuredSelector({ siteno: () => siteno, diff --git a/assets/src/scripts/selectors/timeSeriesSelector.js b/assets/src/scripts/selectors/timeSeriesSelector.js index f5ded6053a3d1e786d2b5d98d9e38079a9c1356e..30e642027ff95ed8b9343dbbf53042a75c5d539d 100644 --- a/assets/src/scripts/selectors/timeSeriesSelector.js +++ b/assets/src/scripts/selectors/timeSeriesSelector.js @@ -115,7 +115,8 @@ export const getRequestTimeRange = memoize((tsKey, period, parmCd) => createSele } )); -export const isLoadingTS = memoize(tsKey => createSelector( +export const isLoadingTS = memoize((tsKey, period, parmCd) => createSelector( getLoadingTsKeys, - (loadingTSKeys) => loadingTSKeys.includes(tsKey) + getTsRequestKey(tsKey, period, parmCd), + (loadingTSKeys, tsRequestKey) => loadingTSKeys.includes(tsRequestKey) )); diff --git a/assets/src/scripts/store/index.js b/assets/src/scripts/store/index.js index defa7856fdbf4f34ba103404fe5fb6781e3b22b3..f36eb3c6229e5dc354fe4b7710e792977a178536 100644 --- a/assets/src/scripts/store/index.js +++ b/assets/src/scripts/store/index.js @@ -55,7 +55,6 @@ export const Actions = { const timeSeries = getTimeSeries({sites: [siteno], params}).then( series => { - dispatch(Actions.removeTimeSeriesLoading([requestKey])); const collection = normalize(series, requestKey); // Get the start/end times of this request's range. @@ -69,6 +68,8 @@ export const Actions = { // Update the series data for the 'current' series dispatch(Actions.addSeriesCollection('current', collection)); + dispatch(Actions.removeTimeSeriesLoading([requestKey])); + // Update the application state dispatch(Actions.toggleTimeSeries('current', true)); @@ -80,8 +81,9 @@ export const Actions = { return {collection, startTime, endTime}; }, () => { - dispatch(Actions.removeTimeSeriesLoading([requestKey])); dispatch(Actions.resetTimeSeries(getTsRequestKey('current', 'P7D')(currentState))); + dispatch(Actions.removeTimeSeriesLoading([requestKey])); + dispatch(Actions.toggleTimeSeries('current', false)); return { collection: null, @@ -90,7 +92,14 @@ export const Actions = { }; } ); + + const medianRequestKey = getTsRequestKey('median')(currentState); + dispatch(Actions.addTimeSeriesLoading([medianRequestKey])); const medianStatistics = getMedianStatistics({sites: [siteno]}); + medianStatistics.finally(() => { + dispatch(Actions.removeTimeSeriesLoading([medianRequestKey])); + }); + return Promise.all([timeSeries, medianStatistics]).then(([{collection, endTime}, stats]) => { if (endTime) { let medianCollection = parseMedianData(stats, endTime, collection && collection.variables ? collection.variables : {}); @@ -102,13 +111,18 @@ export const Actions = { }, retrieveCompareTimeSeries(site, period, startTime, endTime) { return function (dispatch, getState) { + const requestKey = getTsRequestKey('compare', period)(getState()); + dispatch(Actions.addTimeSeriesLoading([requestKey])); return getPreviousYearTimeSeries({site, startTime, endTime}).then( series => { - const requestKey = getTsRequestKey('compare', period)(getState()); const collection = normalize(series, requestKey); dispatch(Actions.addSeriesCollection(requestKey, collection)); + dispatch(Actions.removeTimeSeriesLoading([requestKey])); }, - () => dispatch(Actions.resetTimeSeries(getTsRequestKey('compare', period)(getState()))) + () => { + dispatch(Actions.resetTimeSeries(getTsRequestKey('compare', period)(getState()))); + dispatch(Actions.removeTimeSeriesLoading([requestKey])); + } ); }; }, @@ -122,7 +136,8 @@ export const Actions = { const endTime = new Date(getRequestTimeRange('current', 'P7D')(state).end); let startTime = calcStartTime(period, endTime); - return getTimeSeries({ + dispatch(Actions.addTimeSeriesLoading([requestKey])); + const currentTimeSeries = getTimeSeries({ sites: [site], params: [parmCd], startDate: startTime, @@ -131,13 +146,16 @@ export const Actions = { series => { const collection = normalize(series, requestKey); dispatch(Actions.addSeriesCollection(requestKey, collection)); - dispatch(Actions.retrieveCompareTimeSeries(site, period, startTime, endTime)); + dispatch(Actions.removeTimeSeriesLoading([requestKey])); }, () => { console.log(`Unable to fetch data for period ${period} and parameter code ${parmCd}`); dispatch(Actions.addSeriesCollection(requestKey, {})); + dispatch(Actions.removeTimeSeriesLoading([requestKey])); } ); + dispatch(Actions.retrieveCompareTimeSeries(site, period, startTime, endTime)); + return currentTimeSeries; } }; }, diff --git a/assets/src/scripts/store/timeSeriesStateReducer.js b/assets/src/scripts/store/timeSeriesStateReducer.js index 46529150e8925f9a73e057296a254a4fe6ab1863..ab76dd176e63b0bc5b77bab93ed03bae1efa0837 100644 --- a/assets/src/scripts/store/timeSeriesStateReducer.js +++ b/assets/src/scripts/store/timeSeriesStateReducer.js @@ -51,14 +51,14 @@ const timeSeriesPlayStop = function(timeSeriesState) { const addLoadingTimeSeries = function(timeSeriesState, action) { return { ...timeSeriesState, - loadingTSKeys: timeSeriesState.loadingTSKeys.concat([action.tsKeys]) + loadingTSKeys: timeSeriesState.loadingTSKeys.concat(action.tsKeys) }; }; const removeLoadingTimeSeries = function(timeSeriesState, action) { return { ...timeSeriesState, - loadingTSKeys: timeSeriesState.loadingTSKeys.filter((tsKey) => action.tsKeys.includes(tsKey)) + loadingTSKeys: timeSeriesState.loadingTSKeys.filter((tsKey) => !action.tsKeys.includes(tsKey)) }; }; diff --git a/assets/src/styles/components/hydrograph/_app.scss b/assets/src/styles/components/hydrograph/_app.scss index 835bd9eda07744dc6ad5ea68c9656fa962073aa4..d0d5fbcaadb038b2bb614cdbe29064c8b34a62b9 100644 --- a/assets/src/styles/components/hydrograph/_app.scss +++ b/assets/src/styles/components/hydrograph/_app.scss @@ -4,10 +4,16 @@ @import './variables'; #ts-daterange-select-container { - li { + .loading-indicator-container { display: inline-block; - label { - width: 110px; + } + ul { + display: inline-block; + li { + display: inline-block; + label { + width: 110px; + } } } } @@ -136,6 +142,14 @@ } } +.loading-indicator-container { + i { + text-align: center; + vertical: middle; + width: 100%; + } +} + .watermark { position: absolute; opacity: .08; @@ -167,7 +181,6 @@ button { font-size: 1em; } - .graph-controls-container { display: inline-block; @include media($medium-screen) { diff --git a/wdfn-server/waterdata/templates/macros/components.html b/wdfn-server/waterdata/templates/macros/components.html index a4d33be14e391ac3f726786a15b15c704c30c4f9..a1cb753367e18d725832fc82c3ba58343fde6552 100644 --- a/wdfn-server/waterdata/templates/macros/components.html +++ b/wdfn-server/waterdata/templates/macros/components.html @@ -1,5 +1,6 @@ {% macro TimeSeriesComponent(site_no) -%} <div class="wdfn-component" data-component="hydrograph" data-siteno="{{ site_no }}"> + <div class="loading-indicator-container"></div> <div class="graph-container"></div> <div class="select-time-series-container"></div> <div class="usa-alert usa-alert-info provisional-data-alert" role="alert" hidden>