From 3e8381e1f7f8603fba8135e6ea41c74614ef51bf Mon Sep 17 00:00:00 2001
From: mbucknell <mbucknell@usgs.gov>
Date: Fri, 5 Mar 2021 08:54:55 -0600
Subject: [PATCH] Updated to cleanup with hydrograph line rendering and to
 create a consistent set of elements that will be rendered that can be used by
 the graph server to determine when rendering is complete.

---
 assets/src/scripts/config.js                  |  2 +
 assets/src/scripts/d3-rendering/legend.js     |  5 +-
 .../src/scripts/d3-rendering/legend.test.js   |  4 +-
 .../components/hydrograph/index.js            | 26 ++++---
 .../hydrograph/time-series-graph.js           | 15 ++--
 .../hydrograph/time-series-graph.test.js      | 13 ++--
 .../hydrograph/time-series-lines.js           | 17 ++---
 .../selectors/flood-data-selector.js          | 10 +--
 .../selectors/flood-data-selector.test.js     | 68 +++++++++++--------
 .../store/hydrograph-parameters.js            |  4 +-
 assets/src/scripts/web-services/flood-data.js |  2 +-
 .../templates/monitoring_location_embed.html  |  1 -
 12 files changed, 93 insertions(+), 74 deletions(-)

diff --git a/assets/src/scripts/config.js b/assets/src/scripts/config.js
index d176d33a8..6df4977d3 100644
--- a/assets/src/scripts/config.js
+++ b/assets/src/scripts/config.js
@@ -18,6 +18,8 @@ export default {
     // Indicate a NWIS 'variable' has been modified in the application, such as a conversion from Celsius to Fahrenheit
     CALCULATED_TEMPERATURE_VARIABLE_CODE: 'F',
 
+    GAGE_HEIGHT_PARAMETER_CODE: '00065',
+
     TEMPERATURE_PARAMETERS: {
         celsius: [
             '00010',
diff --git a/assets/src/scripts/d3-rendering/legend.js b/assets/src/scripts/d3-rendering/legend.js
index c1c75dafa..de4e9032a 100644
--- a/assets/src/scripts/d3-rendering/legend.js
+++ b/assets/src/scripts/d3-rendering/legend.js
@@ -17,12 +17,11 @@ const VERTICAL_ROW_OFFSET = 18;
 export const drawSimpleLegend = function(div, {legendMarkerRows, layout}) {
     div.selectAll('.legend-svg').remove();
 
+    const svg = div.append('svg')
+        .attr('class', 'legend-svg');
     if (!legendMarkerRows.length || !layout) {
         return;
     }
-
-    const svg = div.append('svg')
-        .attr('class', 'legend-svg');
     const legend = svg
         .append('g')
             .attr('class', 'legend')
diff --git a/assets/src/scripts/d3-rendering/legend.test.js b/assets/src/scripts/d3-rendering/legend.test.js
index b0f8be8c6..3cd27c5ce 100644
--- a/assets/src/scripts/d3-rendering/legend.test.js
+++ b/assets/src/scripts/d3-rendering/legend.test.js
@@ -61,13 +61,13 @@ describe('Legend module', () => {
             container.remove();
         });
 
-        it('Does not add a legend svg if no markers are provided', () => {
+        it('If no markers are provided legend-svg will contain no groups', () => {
             drawSimpleLegend(container, {
                 legendMarkerRows: [],
                 layout: layout
             });
 
-            expect(container.select('svg').size()).toBe(0);
+            expect(container.select('svg g').size()).toBe(0);
         });
 
         it('Adds a legend when width is provided', () => {
diff --git a/assets/src/scripts/monitoring-location/components/hydrograph/index.js b/assets/src/scripts/monitoring-location/components/hydrograph/index.js
index 366d07ded..a6e677774 100644
--- a/assets/src/scripts/monitoring-location/components/hydrograph/index.js
+++ b/assets/src/scripts/monitoring-location/components/hydrograph/index.js
@@ -55,6 +55,7 @@ export const attachToNode = function(store,
                                          showOnlyGraph = false,
                                          showMLName = false
                                      } = {}) {
+    console.log('Rendering hydrograph');
     const nodeElem = select(node);
     if (!config.ivPeriodOfRecord && !config.gwPeriodOfRecord) {
         select(node).select('.graph-container').call(drawInfoAlert, {title: 'Hydrograph Alert', body: 'No IV or field visit data is available.'});
@@ -68,7 +69,7 @@ export const attachToNode = function(store,
         DateTime.fromISO(startDT, {zone: config.locationTimeZone}).toISO() : null;
     const initialEndTime = endDT ?
         DateTime.fromISO(endDT, {zone: config.locationTimeZone}).endOf('day').toISO() : null;
-    const fetchDataPromise = store.dispatch(retrieveHydrographData(siteno, {
+    const fetchHydrographDataPromise = store.dispatch(retrieveHydrographData(siteno, {
         parameterCode: parameterCode,
         period: initialPeriod === 'custom' ? null : initialPeriod,
         startTime: initialStartTime,
@@ -78,9 +79,9 @@ export const attachToNode = function(store,
     }));
 
     // if showing the controls, fetch the parameters
-    let fetchParameters;
+    let fetchParametersPromise;
     if (!showOnlyGraph) {
-        fetchParameters = store.dispatch(retrieveHydrographParameters(siteno));
+        fetchParametersPromise = store.dispatch(retrieveHydrographParameters(siteno));
 
         // Initialize all hydrograph state variables if showing the control
         store.dispatch(setSelectedParameterCode(parameterCode));
@@ -96,12 +97,16 @@ export const attachToNode = function(store,
         store.dispatch(setSelectedIVMethodID(timeSeriesId));
     }
 
-    // Fetch waterwatch flood levels - TODO: consider only fetching when gage height is requested
-    store.dispatch(floodDataActions.retrieveWaterwatchData(siteno));
+    // Fetch waterwatch flood levels
+    const fetchFloodLevelsPromise = store.dispatch(floodDataActions.retrieveWaterwatchData(siteno));
 
-    fetchDataPromise.then(() => {
+    let fetchDataPromises = [fetchHydrographDataPromise];
+    if (parameterCode === config.GAGE_HEIGHT_PARAMETER_CODE) {
+        fetchDataPromises.push(fetchFloodLevelsPromise);
+    }
+    Promise.all(fetchDataPromises).then(() => {
+        console.log('Done fetching data');
         showDataLoadingIndicator(false);
-
         let graphContainer = nodeElem.select('.graph-container');
         graphContainer.call(drawTimeSeriesGraph, store, siteno, agencyCode, sitename, showMLName, !showOnlyGraph);
 
@@ -132,12 +137,15 @@ export const attachToNode = function(store,
             nodeElem.select('#iv-data-table-container')
                 .call(drawDataTables, store);
 
-            fetchParameters.then(() => {
+            fetchParametersPromise.then(() => {
                 nodeElem.select('.select-time-series-container')
                     .call(drawSelectionTable, store, siteno);
             });
             renderTimeSeriesUrlParams(store);
         }
+    })
+    .catch(reason => {
+        console.error(reason);
+        throw reason;
     });
-
 };
diff --git a/assets/src/scripts/monitoring-location/components/hydrograph/time-series-graph.js b/assets/src/scripts/monitoring-location/components/hydrograph/time-series-graph.js
index 3c29808ad..92144abd5 100644
--- a/assets/src/scripts/monitoring-location/components/hydrograph/time-series-graph.js
+++ b/assets/src/scripts/monitoring-location/components/hydrograph/time-series-graph.js
@@ -75,12 +75,13 @@ const plotMedianPoints = function(elem, {xscale, yscale, modulo, points}) {
  */
 const plotAllMedianPoints = function(elem, {visible, xscale, yscale, seriesPoints, enableClip}) {
     elem.select('#median-points').remove();
-    if (!visible || !seriesPoints) {
-        return;
-    }
     const container = elem
         .append('g')
             .attr('id', 'median-points');
+    if (!visible || !seriesPoints) {
+        return;
+    }
+
     if (enableClip) {
         container.attr('clip-path', 'url(#graph-clip');
     }
@@ -125,13 +126,15 @@ const plotFloodLevelPoints = function(elem, {xscale, yscale, points, classes}) {
  */
 const plotAllFloodLevelPoints = function(elem, {visible, xscale, yscale, seriesPoints, enableClip}) {
     elem.select('#flood-level-points').remove();
-    if (!visible) {
-        return;
-    }
     const container = elem
         .append('g')
         .lower()
             .attr('id', 'flood-level-points');
+
+    if (!visible) {
+        return;
+    }
+
     if (enableClip) {
         container.attr('clip-path', 'url(#graph-clip');
     }
diff --git a/assets/src/scripts/monitoring-location/components/hydrograph/time-series-graph.test.js b/assets/src/scripts/monitoring-location/components/hydrograph/time-series-graph.test.js
index 8516a1aa0..51937ed37 100644
--- a/assets/src/scripts/monitoring-location/components/hydrograph/time-series-graph.test.js
+++ b/assets/src/scripts/monitoring-location/components/hydrograph/time-series-graph.test.js
@@ -91,10 +91,9 @@ describe('monitoring-location/components/hydrograph/time-series-graph', () => {
 
     it('Should render current IV Data and groundwater levels but not median steps', () => {
         drawTimeSeriesGraph(div, store, '11112222', 'USGS', 'This site', false, false);
-
-        expect(div.selectAll('.ts-primary-group').size()).toBe(1);
-        expect(div.selectAll('.ts-compare-group').size()).toBe(0);
-        expect(div.selectAll('.iv-graph-gw-levels-group').size()).toBe(1);
+        expect(div.selectAll('.ts-primary-group').html()).not.toEqual('');
+        expect(div.selectAll('.ts-compare-group').html()).toEqual('');
+        expect(div.selectAll('.iv-graph-gw-levels-group').html()).not.toEqual('');
         expect(div.selectAll('.median-stats-group').size()).toBe(0);
     });
 
@@ -102,9 +101,9 @@ describe('monitoring-location/components/hydrograph/time-series-graph', () => {
         store.dispatch(setMedianDataVisibility(true));
         drawTimeSeriesGraph(div, store, '11112222', 'USGS', 'This site', false, false);
 
-        expect(div.selectAll('.ts-primary-group').size()).toBe(1);
-        expect(div.selectAll('.ts-compare-group').size()).toBe(0);
-        expect(div.selectAll('.iv-graph-gw-levels-group').size()).toBe(1);
+        expect(div.selectAll('.ts-primary-group').html()).not.toEqual('');
+        expect(div.selectAll('.ts-compare-group').html()).toEqual('');
+        expect(div.selectAll('.iv-graph-gw-levels-group').html()).not.toEqual('');
         expect(div.selectAll('.median-stats-group').size()).toBe(1);
     });
 });
\ No newline at end of file
diff --git a/assets/src/scripts/monitoring-location/components/hydrograph/time-series-lines.js b/assets/src/scripts/monitoring-location/components/hydrograph/time-series-lines.js
index b8a4db8ab..53e9522ff 100644
--- a/assets/src/scripts/monitoring-location/components/hydrograph/time-series-lines.js
+++ b/assets/src/scripts/monitoring-location/components/hydrograph/time-series-lines.js
@@ -90,33 +90,28 @@ export const drawDataSegment = function(group, {segment, isCurrentMethod, dataKi
  * @param {Object} yScale - D3 scale for the y axis
  * @param {Boolean} enableClip - Set if lines should be clipped to the width/height of the container.
  */
-export const drawDataSegments = function(elem, {visible, currentMethodID, tsSegmentsMap, dataKind, xScale, yScale, enableClip}, container) {
-    container = container || elem.append('g');
-
+export const drawDataSegments = function(elem, {visible, currentMethodID, tsSegmentsMap, dataKind, xScale, yScale, enableClip}) {
     const elemClass = `ts-${dataKind}-group`;
     const isCurrentMethodID = function(thisMethodID) {
         return currentMethodID ? currentMethodID === thisMethodID : true;
     };
 
-    container.selectAll(`.${elemClass}`).remove();
+    elem.selectAll(`.${elemClass}`).remove();
+    const lineGroup = elem.append('g')
+        .attr('class', elemClass);
     if (!visible || !tsSegmentsMap) {
         return;
     }
-    const tsLineGroup = container
-        .append('g')
-            .attr('class', elemClass);
 
     if (enableClip) {
-        tsLineGroup.attr('clip-path', 'url(#graph-clip)');
+        lineGroup.attr('clip-path', 'url(#graph-clip)');
     }
 
     Object.keys(tsSegmentsMap).forEach(methodID => {
         const isCurrentMethod = isCurrentMethodID(methodID);
         const segments = tsSegmentsMap[methodID];
         segments.forEach(segment => {
-            drawDataSegment(tsLineGroup, {segment, isCurrentMethod, dataKind, xScale, yScale});
+            drawDataSegment(lineGroup, {segment, isCurrentMethod, dataKind, xScale, yScale});
         });
     });
-
-    return container;
 };
\ No newline at end of file
diff --git a/assets/src/scripts/monitoring-location/selectors/flood-data-selector.js b/assets/src/scripts/monitoring-location/selectors/flood-data-selector.js
index b8c623944..851a8f748 100644
--- a/assets/src/scripts/monitoring-location/selectors/flood-data-selector.js
+++ b/assets/src/scripts/monitoring-location/selectors/flood-data-selector.js
@@ -1,5 +1,8 @@
 import {createSelector} from 'reselect';
-import {getSelectedParameterCode} from './hydrograph-state-selector';
+
+import config from 'ui/config';
+
+import {getPrimaryParameter} from './hydrograph-data-selector';
 
 export const getFloodStages = state => state.floodData.stages || [];
 
@@ -31,9 +34,8 @@ export const hasWaterwatchData = createSelector(
  */
 export const isWaterwatchVisible = createSelector(
     hasWaterwatchData,
-    getSelectedParameterCode,
-    (hasFloodLevels, paramCd) =>
-        hasFloodLevels && paramCd === '00065'
+    getPrimaryParameter,
+    (hasFloodLevels, parameter) => hasFloodLevels && parameter.parameterCode === config.GAGE_HEIGHT_PARAMETER_CODE
 );
 
 /*
diff --git a/assets/src/scripts/monitoring-location/selectors/flood-data-selector.test.js b/assets/src/scripts/monitoring-location/selectors/flood-data-selector.test.js
index 2450acb4c..fab45c72c 100644
--- a/assets/src/scripts/monitoring-location/selectors/flood-data-selector.test.js
+++ b/assets/src/scripts/monitoring-location/selectors/flood-data-selector.test.js
@@ -1,5 +1,7 @@
-import {getFloodStageHeight, hasFloodData, getFloodGageHeightStageIndex,
-    hasWaterwatchData, getWaterwatchFloodLevels, isWaterwatchVisible} from './flood-data-selector';
+import {
+    getFloodStageHeight, hasFloodData, getFloodGageHeightStageIndex,
+    hasWaterwatchData, getWaterwatchFloodLevels, isWaterwatchVisible
+} from './flood-data-selector';
 
 describe('monitoring-location/selectors/flood-data-selector', () => {
 
@@ -62,7 +64,7 @@ describe('monitoring-location/selectors/flood-data-selector', () => {
     });
 
     describe('hasFloodData', () => {
-        it('Return false if no flood stages are available', () =>{
+        it('Return false if no flood stages are available', () => {
             expect(hasFloodData({
                 floodData: {
                     stages: []
@@ -79,8 +81,8 @@ describe('monitoring-location/selectors/flood-data-selector', () => {
         });
     });
 
-       describe('hasWaterwatchData', () => {
-        it('Return false if no waterwatch flood levels are available', () =>{
+    describe('hasWaterwatchData', () => {
+        it('Return false if no waterwatch flood levels are available', () => {
             expect(hasWaterwatchData({
                 floodData: {
                     floodLevels: null
@@ -103,8 +105,8 @@ describe('monitoring-location/selectors/flood-data-selector', () => {
         });
     });
 
-       describe('getWaterwatchData', () => {
-        it('Return true if waterwatch flood levels are returned', () =>{
+    describe('getWaterwatchData', () => {
+        it('Return true if waterwatch flood levels are returned', () => {
             expect(Object.values(getWaterwatchFloodLevels({
                 floodData: {
                     floodLevels: {
@@ -115,12 +117,12 @@ describe('monitoring-location/selectors/flood-data-selector', () => {
                         major_flood_stage: '26'
                     }
                 }
-            }))).toEqual([20,22,25,26]);
+            }))).toEqual([20, 22, 25, 26]);
         });
     });
 
-       describe('isWaterwatchVisible', () => {
-        it('Return false if waterwatch flood levels should not be visible due to parameter code', () =>{
+    describe('isWaterwatchVisible', () => {
+        it('Return false if waterwatch flood levels should not be visible due to parameter code', () => {
             expect(isWaterwatchVisible({
                 floodData: {
                     floodLevels: {
@@ -131,36 +133,48 @@ describe('monitoring-location/selectors/flood-data-selector', () => {
                         major_flood_stage: '26'
                     }
                 },
-                hydrographState: {
-                    selectedParameterCode: '00060'
+                hydrographData: {
+                    primaryIVData: {
+                        parameter: {
+                            parameterCode: '00060'
+                        }
+                    }
                 }
             })).toBeFalsy();
         });
 
-        it('Return false if waterwatch flood levels should not be visible due to no flood levels', () =>{
+        it('Return false if waterwatch flood levels should not be visible due to no flood levels', () => {
             expect(isWaterwatchVisible({
                 floodData: {
                     floodLevels: null
                 },
-                hydrographState: {
-                    selectedParameterCode: '00065'
+                hydrographData: {
+                    primaryIVData: {
+                        parameter: {
+                            parameterCode: '00065'
+                        }
+                    }
                 }
             })).toBeFalsy();
         });
 
-         it('Return true if waterwatch flood levels should be visible', () =>{
+        it('Return true if waterwatch flood levels should be visible', () => {
             expect(isWaterwatchVisible({
-                 floodData: {
-                     floodLevels: {
-                         site_no: '07144100',
-                         action_stage: '20',
-                         flood_stage: '22',
-                         moderate_flood_stage: '25',
-                         major_flood_stage: '26'
-                     }
-                 },
-                hydrographState: {
-                    selectedParameterCode: '00065'
+                floodData: {
+                    floodLevels: {
+                        site_no: '07144100',
+                        action_stage: '20',
+                        flood_stage: '22',
+                        moderate_flood_stage: '25',
+                        major_flood_stage: '26'
+                    }
+                },
+                hydrographData: {
+                    primaryIVData: {
+                        parameter: {
+                            parameterCode: '00065'
+                        }
+                    }
                 }
             })).toBeTruthy();
         });
diff --git a/assets/src/scripts/monitoring-location/store/hydrograph-parameters.js b/assets/src/scripts/monitoring-location/store/hydrograph-parameters.js
index 4acd6c678..347eaabfa 100644
--- a/assets/src/scripts/monitoring-location/store/hydrograph-parameters.js
+++ b/assets/src/scripts/monitoring-location/store/hydrograph-parameters.js
@@ -9,8 +9,6 @@ import {fetchTimeSeries} from 'ui/web-services/instantaneous-values';
 import {getConvertedTemperatureParameter, hasMeasuredFahrenheitParameter} from 'ml/iv-data-utils';
 import {Actions as floodStateActions} from './flood-inundation';
 
-const GAGE_HEIGHT_PARAMETER_CODE = '00065';
-
 /*
  * Synchronous Redux action - updatethe hydrograph variables
  * @param {Object} variables - keys are parameter codes.
@@ -45,7 +43,7 @@ export const retrieveHydrographParameters = function(siteno) {
                                 hasIVData: true
                             };
                             // If the parameter is for gage height set the initial flood gage height
-                            if (parameterCode === GAGE_HEIGHT_PARAMETER_CODE) {
+                            if (parameterCode === config.GAGE_HEIGHT_PARAMETER_CODE) {
                                 dispatch(floodStateActions.setGageHeight(parseFloat(ts.values[0].value[0].value)));
                             }
 
diff --git a/assets/src/scripts/web-services/flood-data.js b/assets/src/scripts/web-services/flood-data.js
index f48901696..30f7d7f52 100644
--- a/assets/src/scripts/web-services/flood-data.js
+++ b/assets/src/scripts/web-services/flood-data.js
@@ -61,7 +61,7 @@ export const fetchFloodExtent = function(siteno) {
 };
 
 /*
- * Retrieve waterwach flood levels any for siteno
+ * Retrieve waterwatch flood levels any for siteno
  * @param {String} siteno
  * @return {Promise} resolves to an array of features for the site
  */
diff --git a/wdfn-server/waterdata/templates/monitoring_location_embed.html b/wdfn-server/waterdata/templates/monitoring_location_embed.html
index 0aa9c6a55..013b6d8a4 100644
--- a/wdfn-server/waterdata/templates/monitoring_location_embed.html
+++ b/wdfn-server/waterdata/templates/monitoring_location_embed.html
@@ -5,7 +5,6 @@
 {% endblock page_css %}
 
 {% block page_script %}
-    <script src="{{ 'scripts/vendor.js' | asset_url }}"></script>
     <script async src="{{ 'bundle.js' | asset_url }}"></script>
 {% endblock %}}
 
-- 
GitLab