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