Skip to content
Snippets Groups Projects
index.js 10.3 KiB
Newer Older
 * Hydrograph charting module.
 */
import {select} from 'd3-selection';
import {bindActionCreators} from 'redux';
import ReduxConnectVue from 'redux-connect-vue';
import {createStructuredSelector} from 'reselect';
import config from 'ui/config.js';
import {drawInfoAlert} from 'd3render/alerts';
import {renderTimeSeriesUrlParams} from 'ml/url-params';
import {getInputsForRetrieval} from 'ml/selectors/hydrograph-state-selector';

import {retrieveGroundwaterLevelData} from 'ml/store/groundwater-level-field-visits';
import {retrieveHydrographData} from 'ml/store/hydrograph-data';
import {retrieveHydrographParameters} from 'ml/store/hydrograph-parameters';
import {setSelectedParameterCode, setCompareDataVisibility, setSelectedTimeSpan,
Briggs, Aaron Shane's avatar
Briggs, Aaron Shane committed
    setSelectedIVMethodID
} from 'ml/store/hydrograph-state';
import {Actions as floodDataActions} from 'ml/store/flood-data';
Williams, Darius Shamar's avatar
Williams, Darius Shamar committed
import {getPreferredIVMethodID} from './selectors/time-series-data';

import {showDataIndicators} from './data-indicator';
import {initializeTimeSeriesGraph, drawTimeSeriesGraphData} from './time-series-graph';
import DataTablesApp from './DataTablesApp.vue';
import GraphControlsApp from './GraphControlsApp.vue';
import HydrographApp from './HydrographApp.vue';
import ParameterSelectionApp from './ParameterSelectionApp.vue';
Williams, Darius Shamar's avatar
Williams, Darius Shamar committed
import StatisticsTableApp from './StatisticsTableApp.vue';
import TimeDownloadGraphControlsApp from './TimeDownloadGraphControlsApp.vue';
/* eslint-disable vue/one-component-per-file */
/*
 * Renders the hydrograph on the node element using the Redux store for state information. The siteno, latitude, and
 * longitude are required parameters. All others are optional and are used to set the initial state of the hydrograph.
 * @param {Redux store} store
 * @param {DOM node} node
 * @param {Object} - string properties to set initial state information. The property siteno is required
 * @param {Promise} loadPromise - will resolve when any data needed by this module
 *                                that is fetched by the caller has been fetched
 * */
export const attachToNode = function(store,
                                     node,
                                     {
                                         siteno,
                                         agencyCd,
                                         parameterCode,
                                         compare,
                                         period,
                                         startDT,
                                         endDT,
                                         timeSeriesId,
                                         showOnlyGraph = false,
                                         showMLName = false
Briggs, Aaron Shane's avatar
Briggs, Aaron Shane committed
    const addTimeDownloadGraphControlsApp = function() {
        const timeDownloadGraphControlsApp = createApp(TimeDownloadGraphControlsApp, {});
        timeDownloadGraphControlsApp.use(ReduxConnectVue, {
            store,
            mapDispatchToPropsFactory: (actionCreators) => (dispatch) => bindActionCreators(actionCreators, dispatch),
            mapStateToPropsFactory: createStructuredSelector
        });
        timeDownloadGraphControlsApp.provide('store', store);
        timeDownloadGraphControlsApp.provide('siteno', siteno);
        timeDownloadGraphControlsApp.provide('agencyCd', agencyCd);
        timeDownloadGraphControlsApp.mount('#time-download-graph-controls-anchor');
    };

    if (!config.ivPeriodOfRecord && !config.gwPeriodOfRecord) {
Briggs, Aaron Shane's avatar
Briggs, Aaron Shane committed
        addTimeDownloadGraphControlsApp();
        select(node).select('.graph-container').call(drawInfoAlert, {title: 'Hydrograph Alert', body: 'No IV or field visit data is available.'});
    const initialLoadCompare = compare === 'true' || compare === true ? true : false;
    const thisShowOnlyGraph = showOnlyGraph === 'true' || showOnlyGraph === true ? true : false;
    const thisShowMLName = showMLName === 'true' || showMLName === true ? true : false;
    // Initialize all hydrograph state variables
    store.dispatch(setSelectedParameterCode(parameterCode));
    store.dispatch(setCompareDataVisibility(initialLoadCompare));
    if (period) {
        store.dispatch(setSelectedTimeSpan(period));
        store.dispatch(setSelectedTimeSpan({
            start: startDT,
            end: endDT
        }));
        store.dispatch(setSelectedTimeSpan(config.ivPeriodOfRecord && config.ivPeriodOfRecord[parameterCode] ?
            'P7D' : 'P1Y'));
    // Fetch all data needed to render the hydrograph
    const fetchHydrographDataPromise = store.dispatch(retrieveHydrographData(siteno, agencyCd,
        getInputsForRetrieval(store.getState()), true));
    let fetchDataPromises = [fetchHydrographDataPromise];
    // if showing only graph make a call to retrieve all of the groundwater level data. Otherwise,
    // this is done when retrieving all hydrograph parameter meta data.
    if (thisShowOnlyGraph) {
        if (config.gwPeriodOfRecord) {
            fetchDataPromises.push(store.dispatch(retrieveGroundwaterLevelData(siteno, agencyCd)));
        }
    } else {
        fetchDataPromises.push(store.dispatch(retrieveHydrographParameters(siteno, agencyCd)));
    if (config.ivPeriodOfRecord && config.GAGE_HEIGHT_PARAMETER_CODE in config.ivPeriodOfRecord) {
        const fetchFloodLevelsPromise =  store.dispatch(floodDataActions.retrieveFloodLevels(siteno));
        // If flood levels are to be shown then wait to render the hydrograph until those have been fetched.
        if (parameterCode === config.GAGE_HEIGHT_PARAMETER_CODE) {
            fetchDataPromises.push(fetchFloodLevelsPromise);
        }
    // Render initial UI elements prior to completion of data fetching
    if (!showOnlyGraph) {
Briggs, Aaron Shane's avatar
Briggs, Aaron Shane committed
        addTimeDownloadGraphControlsApp();
    const graphContainer = nodeElem.select('.graph-container');
    graphContainer.call(initializeTimeSeriesGraph, store, siteno, agencyCd, sitename, thisShowMLName, !thisShowOnlyGraph);
    showDataIndicators(true, store);
    if (!showOnlyGraph) {
        //TODO: The tooltips, legend and  the main hydrograph can be added to the HydrographApp.
        // The main hydrograph should be converted to a Vue component last. As part of that task we
        // will figure out how to handle the loading indicator and the no data overlay
        // The addition of the hydrograph-brush-container is merely to create the brush in the correct location
        // This will change as we add things and eventually we won't need to do this.
        graphContainer.append('div').attr('id', 'hydrograph-brush-container');

        const hydrographApp = createApp(HydrographApp, {});
        hydrographApp.use(ReduxConnectVue, {
            store,
            mapDispatchToPropsFactory: (actionCreators) => (dispatch) => bindActionCreators(actionCreators, dispatch),
            mapStateToPropsFactory: createStructuredSelector
        });
        hydrographApp.provide('store', store);
        hydrographApp.provide('siteno', siteno);
        hydrographApp.provide('initialLoadingComplete', initialLoadingComplete);
        hydrographApp.mount('#hydrograph-brush-container');
        // const graphControlsApp = createApp(GraphControlsApp, {});
        // graphControlsApp.use(ReduxConnectVue, {
        //     store,
        //     mapDispatchToPropsFactory: (actionCreators) => (dispatch) => bindActionCreators(actionCreators, dispatch),
        //     mapStateToPropsFactory: createStructuredSelector
        // });
        // graphControlsApp.provide('store', store);
        // graphControlsApp.provide('siteno', siteno);
        // graphControlsApp.mount('.ts-legend-controls-container');
        const parameterSelectionApp = createApp(ParameterSelectionApp, {});
        parameterSelectionApp.use(ReduxConnectVue, {
            store,
            mapDispatchToPropsFactory: (actionCreators) => (dispatch) => bindActionCreators(actionCreators, dispatch),
            mapStateToPropsFactory: createStructuredSelector
        });
        parameterSelectionApp.provide('store', store);
        parameterSelectionApp.provide('siteno', siteno);
        parameterSelectionApp.provide('agencyCode', agencyCd);
        parameterSelectionApp.mount('.select-time-series-container');
    }

    // Once hydrograph data has been fetched, render the time series data.
    Promise.all(fetchDataPromises).then(() => {
        // selectedIVMethodID should be set regardless of whether we are showing only the graph but the preferred method ID
        // can not be determined until the data is fetched so that is done here.
        const initialIVMethodID = timeSeriesId || getPreferredIVMethodID('primary')(store.getState());
        store.dispatch(setSelectedIVMethodID(initialIVMethodID));
        graphContainer.call(drawTimeSeriesGraphData, store, !thisShowOnlyGraph);
            // eslint-disable-next-line vue/one-component-per-file
            const dataTablesApp = createApp(DataTablesApp, {});
            dataTablesApp.use(ReduxConnectVue, {
                store,
                mapDispatchToPropsFactory: (actionCreators) => (dispatch) => bindActionCreators(actionCreators, dispatch),
                mapStateToPropsFactory: createStructuredSelector
            });
            dataTablesApp.provide('store', store);
            // data for DownLoadData component
            dataTablesApp.provide('siteno', siteno);
            dataTablesApp.provide('agencyCd', agencyCd);

            dataTablesApp.mount('#iv-data-table-container');

Williams, Darius Shamar's avatar
Williams, Darius Shamar committed
            const statisticsTableApp = createApp(StatisticsTableApp, {});
            statisticsTableApp.use(ReduxConnectVue, {
Williams, Darius Shamar's avatar
Williams, Darius Shamar committed
                store,
                mapDispatchToPropsFactory: (actionCreators) => (dispatch) => bindActionCreators(actionCreators, dispatch),
                mapStateToPropsFactory: createStructuredSelector
            });
Williams, Darius Shamar's avatar
Williams, Darius Shamar committed
            statisticsTableApp.mount('.daily-statistical-data');
    })
    .catch(reason => {
        console.error(reason);
        throw reason;