From 1141c99c08f0aeb02566330362b275ac2fd4715d Mon Sep 17 00:00:00 2001
From: gpetrochenkov-usgs <gpetrochenkov@usgs.gov>
Date: Mon, 25 May 2020 20:25:42 -0400
Subject: [PATCH] Added water levels to gage height graph

---
 .../components/hydrograph/drawing-data.js     |  43 ++++++-
 .../hydrograph/drawing-data.spec.js           | 113 +++++++++++++++++-
 .../scripts/components/hydrograph/index.js    |   1 +
 .../scripts/components/hydrograph/legend.js   |  20 ++--
 .../components/hydrograph/legend.spec.js      |   9 +-
 .../hydrograph/time-series-graph.js           |  69 ++++++++++-
 .../hydrograph/time-series-graph.spec.js      |  28 ++++-
 .../scripts/selectors/flood-data-selector.js  |  12 +-
 .../selectors/flood-data-selector.spec.js     |  48 +++++++-
 assets/src/scripts/store/flood-inundation.js  |   8 +-
 .../scripts/web-services/flood-data.spec.js   |   1 -
 .../styles/components/hydrograph/_graph.scss  |  22 ++++
 12 files changed, 348 insertions(+), 26 deletions(-)

diff --git a/assets/src/scripts/components/hydrograph/drawing-data.js b/assets/src/scripts/components/hydrograph/drawing-data.js
index 40cd82603..22f305c6d 100644
--- a/assets/src/scripts/components/hydrograph/drawing-data.js
+++ b/assets/src/scripts/components/hydrograph/drawing-data.js
@@ -6,6 +6,7 @@ import {createSelector} from 'reselect';
 import {format} from 'd3-format';
 
 import {getCurrentVariableMedianStatistics} from '../../selectors/median-statistics-selector';
+import {getWaterwatchFloodLevels} from '../../selectors/flood-data-selector';
 import {getVariables, getCurrentMethodID, getTimeSeries, getCurrentVariableTimeSeries, getTimeSeriesForTsKey,
     getTsRequestKey, getRequestTimeRange} from '../../selectors/time-series-selector';
 import {getIanaTimeZone} from '../../selectors/time-zone-selector';
@@ -165,7 +166,7 @@ export const classesForPoint = point => {
 };
 
 /*
- * @ return {Array of Arrays of Objects} where the properties are date (universal), class,  and value
+ * @ return {Array of Arrays of Objects} where the properties are date (universal), and value
 */
 export const getCurrentVariableMedianStatPoints = createSelector(
     getCurrentVariableMedianStatistics,
@@ -220,6 +221,46 @@ export const getCurrentVariableMedianStatPoints = createSelector(
         });
     });
 
+/*
+ * @ return {Array of Arrays of Objects} where the properties are date (universal), and value
+*/
+export const getWaterwatchFloodLevelDataPoints = createSelector(
+    getWaterwatchFloodLevels,
+    getRequestTimeRange('current'),
+    getIanaTimeZone,
+    (floodLevels, timeRange, ianaTimeZone) => {
+        if (!floodLevels || !timeRange) {
+            return [];
+        }
+
+        let datesOfInterest = [];
+        let nextDateTime = DateTime.fromMillis(timeRange.start, {zone: ianaTimeZone});
+        datesOfInterest.push({
+            year: nextDateTime.year,
+            month: nextDateTime.month.toString(),
+            day: nextDateTime.day.toString(),
+            utcDate: timeRange.start
+        });
+        nextDateTime = DateTime.fromMillis(timeRange.end, {zone: ianaTimeZone});
+        datesOfInterest.push({
+            year: nextDateTime.year,
+            month: nextDateTime.month.toString(),
+            day: nextDateTime.day.toString(),
+            utcDate: timeRange.end
+        });
+
+        return floodLevels.map((floodLevel) => {
+            return datesOfInterest
+                .map((date) => {
+                    return {
+                        value: floodLevel,
+                        date: date.utcDate
+                    };
+                })
+        });
+    }
+);
+
 
 /**
  * Factory function create a function that
diff --git a/assets/src/scripts/components/hydrograph/drawing-data.spec.js b/assets/src/scripts/components/hydrograph/drawing-data.spec.js
index c2e95ce6a..82ae49f7a 100644
--- a/assets/src/scripts/components/hydrograph/drawing-data.spec.js
+++ b/assets/src/scripts/components/hydrograph/drawing-data.spec.js
@@ -1,6 +1,6 @@
 
 import {DateTime} from 'luxon';
-import {lineSegmentsSelector, pointsSelector, allPointsSelector, pointsByTsKeySelector, classesForPoint, lineSegmentsByParmCdSelector, currentVariableLineSegmentsSelector, currentVariablePointsSelector, currentVariablePointsByTsIdSelector, visiblePointsSelector, getCurrentVariableMedianStatPoints, MAX_LINE_POINT_GAP} from './drawing-data';
+import {lineSegmentsSelector, pointsSelector, allPointsSelector, pointsByTsKeySelector, classesForPoint, lineSegmentsByParmCdSelector, currentVariableLineSegmentsSelector, currentVariablePointsSelector, currentVariablePointsByTsIdSelector, visiblePointsSelector, getCurrentVariableMedianStatPoints, MAX_LINE_POINT_GAP, getWaterwatchFloodLevelDataPoints} from './drawing-data';
 
 const TEST_DATA = {
     ivTimeSeriesData: {
@@ -195,6 +195,12 @@ const TEST_DATA = {
         currentIVVariableID: '45807197',
         currentIVDateRangeKind: 'P7D',
         currentIVMethodID: 69928
+    },
+    floodState: {
+        actionStage: 1,
+        floodStage: 2,
+        moderateFloodStage: 3,
+        majorFloodStage: 4
     }
 };
 
@@ -1029,5 +1035,110 @@ describe('drawingData module', () => {
             };
             expect(getCurrentVariableMedianStatPoints(newTestState)).toEqual([]);
         });
+
+        describe('getWaterwatchtFloodLevelPoints', () => {
+            const TEST_VARS = {
+                '45807042': {
+                    variableCode: {
+                        'value': '00060'
+                    }
+                },
+                '45807142': {
+                    variableCode: {
+                        'value': '00010'
+                    }
+                }
+            };
+
+            const TEST_STATE = {
+                ivTimeSeriesData: {
+                    queryInfo: {
+                        'current:P7D': {
+                            notes: {
+                                requestDT: 1488388500000,
+                                'filter:timeRange': {
+                                    mode: 'PERIOD',
+                                    periodDays: '7',
+                                    modifiedSince: null
+                                }
+                            }
+                        }
+                    },
+                    variables: TEST_VARS,
+                    timeSeries: {
+                        '69928:00060': {
+                            tsKey: 'current:P7D',
+                            startTime: new Date('2018-03-06T15:45:00.000Z'),
+                            endTime: new Date('2018-03-13t13:45:00.000Z'),
+                            variable: '45807197',
+                            method: 69928,
+                            points: [{
+                                value: 10,
+                                qualifiers: ['P'],
+                                approved: false,
+                                estimated: false
+                            }, {
+                                value: null,
+                                qualifiers: ['P', 'ICE'],
+                                approved: false,
+                                estimated: false
+                            }, {
+                                value: null,
+                                qualifiers: ['P', 'FLD'],
+                                approved: false,
+                                estimated: false
+                            }]
+                        }
+                    }
+                },
+                ianaTimeZone: 'America/Chicago',
+                ivTimeSeriesState: {
+                    currentIVVariableID: '45807142',
+                    currentIVDateRangeKind: 'P7D'
+                },
+                floodState: {
+                    actionStage: 1,
+                    floodStage: 2,
+                    moderateFloodStage: 3,
+                    majorFloodStage: 4
+                },
+            };
+
+            it('Return the expected data points', () => {
+                let result = getWaterwatchFloodLevelDataPoints(TEST_STATE);
+                expect(result.length).toBe(1);
+                expect(result[0].length).toBe(2);
+                expect(result[0][0]).toEqual({
+                    value: 1,
+                    date: DateTime.fromObject({
+                        year: 2018,
+                        month: 3,
+                        day: 6,
+                        hour: 15,
+                        minute: 45,
+                        second: 0,
+                        zone: 'America/Chicago'
+                    }).valueOf()
+                });
+            });
+
+            it('Return the expected data points', () => {
+                let result = getWaterwatchFloodLevelDataPoints(TEST_STATE);
+                expect(result.length).toBe(1);
+                expect(result[0].length).toBe(2);
+                expect(result[0][1]).toEqual({
+                    value: 1,
+                    date: DateTime.fromObject({
+                        year: 2018,
+                        month: 3,
+                        day: 13,
+                        hour: 13,
+                        minute: 45,
+                        second: 0,
+                        zone: 'America/Chicago'
+                    }).valueOf()
+                });
+            });
+        });
     });
 });
diff --git a/assets/src/scripts/components/hydrograph/index.js b/assets/src/scripts/components/hydrograph/index.js
index e09961905..427ba40e5 100644
--- a/assets/src/scripts/components/hydrograph/index.js
+++ b/assets/src/scripts/components/hydrograph/index.js
@@ -149,6 +149,7 @@ export const attachToNode = function (store,
                         .call(drawDateRangeControls, store, siteno);
 
                     nodeElem.select('.ts-legend-controls-container')
+
                         .call(drawGraphControls, store);
 
                     nodeElem.select('.select-time-series-container')
diff --git a/assets/src/scripts/components/hydrograph/legend.js b/assets/src/scripts/components/hydrograph/legend.js
index 665c989b9..173444017 100644
--- a/assets/src/scripts/components/hydrograph/legend.js
+++ b/assets/src/scripts/components/hydrograph/legend.js
@@ -7,8 +7,9 @@ import {drawSimpleLegend} from '../../d3-rendering/legend';
 import {defineLineMarker, defineTextOnlyMarker, defineRectangleMarker} from '../../d3-rendering/markers';
 import {link} from '../../lib/d3-redux';
 import {getCurrentVariableMedianMetadata} from '../../selectors/median-statistics-selector';
-import {hasWaterwatchData, getWaterwatchFloodLevels} from '../../selectors/flood-data-selector';
-import {getCurrentVariable} from '../../selectors/time-series-selector';
+import {hasWaterwatchData, getWaterwatchFloodLevels,
+    waterwatchVisible} from '../../selectors/flood-data-selector';
+import {getCurrentParmCd} from '../../selectors/time-series-selector';
 
 import {currentVariableLineSegmentsSelector, HASH_ID, MASK_DESC} from './drawing-data';
 import {getMainLayout} from './layout';
@@ -107,15 +108,15 @@ const createLegendMarkers = function(displayItems) {
 
     if (displayItems.floodLevels) {
         const floodLevels = displayItems.floodLevels;
-        console.log(floodLevels);
         const labels = ['Action Stage: ', 'Flood Stage: ', 'Moderate Flood Stage: ', 'Major Flood Stage: ']
-        const classes = ['action-stage-data-series', 'flood-stage-data-series',
-            'moderate-flood-stage-data-series', 'major-flood-stage-data-series']
+        const wwSeriesClass = 'waterwatch-data-series';
+        const classes = ['action-stage', 'flood-stage', 'moderate-flood-stage', 'major-flood-stage']
 
         for (let index = 0; index < floodLevels.length; index++) {
             legendMarkers.push([
                 defineTextOnlyMarker(labels[index]),
-                defineLineMarker(null, classes[index], `${floodLevels[index]} ft`)]);
+                defineLineMarker(null, `${wwSeriesClass} ${classes[index]}`,
+                    `${floodLevels[index]} ft`)]);
         }
     }
 
@@ -148,15 +149,14 @@ const legendDisplaySelector = createSelector(
     getCurrentVariableMedianMetadata,
     uniqueClassesSelector('current'),
     uniqueClassesSelector('compare'),
-    hasWaterwatchData,
+    waterwatchVisible,
     getWaterwatchFloodLevels,
-    getCurrentVariable,
-    (showSeries, medianSeries, currentClasses, compareClasses, hasWW, getWW, getVar) => {
+    (showSeries, medianSeries, currentClasses, compareClasses, visible, getWW) => {
         return {
             current: showSeries.current ? currentClasses : undefined,
             compare: showSeries.compare ? compareClasses : undefined,
             median: showSeries.median ? medianSeries : undefined,
-            floodLevels: hasWW && getVar.variableCode.value == "00065" ? getWW : undefined,
+            floodLevels: visible ? getWW : undefined,
         };
     }
 );
diff --git a/assets/src/scripts/components/hydrograph/legend.spec.js b/assets/src/scripts/components/hydrograph/legend.spec.js
index 46e622f1d..d271dce10 100644
--- a/assets/src/scripts/components/hydrograph/legend.spec.js
+++ b/assets/src/scripts/components/hydrograph/legend.spec.js
@@ -94,6 +94,12 @@ describe('UV: Legend module', () => {
                 compare: true,
                 median: true
             }
+        },
+        floodState: {
+            actionStage: 1,
+            floodStage: 2,
+            moderateFloodStage: 3,
+            majorFloodStage: 4
         }
     };
 
@@ -106,7 +112,8 @@ describe('UV: Legend module', () => {
                     ...TEST_DATA.ivTimeSeriesData,
                     timeSeries: {}
                 },
-                statisticsData: {}
+                statisticsData: {},
+                floodState: {}
             };
 
             expect(legendMarkerRowsSelector(newData)).toEqual([]);
diff --git a/assets/src/scripts/components/hydrograph/time-series-graph.js b/assets/src/scripts/components/hydrograph/time-series-graph.js
index 554f01fc5..3c7ea7129 100644
--- a/assets/src/scripts/components/hydrograph/time-series-graph.js
+++ b/assets/src/scripts/components/hydrograph/time-series-graph.js
@@ -7,17 +7,19 @@ import {addSVGAccessibility} from '../../d3-rendering/accessibility';
 import {appendAxes} from '../../d3-rendering/axes';
 import {renderMaskDefs} from '../../d3-rendering/data-masks';
 import {link} from '../../lib/d3-redux';
-import {getAgencyCode, getMonitoringLocationName} from '../../selectors/time-series-selector';
+import {getAgencyCode, getCurrentParmCd, getMonitoringLocationName} from '../../selectors/time-series-selector';
+import {waterwatchVisible} from '../../selectors/flood-data-selector';
 import {mediaQuery}  from '../../utils';
 
 import {getAxes}  from './axes';
 import {
     currentVariableLineSegmentsSelector,
     getCurrentVariableMedianStatPoints,
+    getWaterwatchFloodLevelDataPoints,
     HASH_ID
 } from './drawing-data';
 import {getMainLayout} from './layout';
-import {getMainXScale, getMainYScale} from './scales';
+import {getMainXScale, getMainYScale, getBrushXScale} from './scales';
 import {descriptionSelector, isVisibleSelector, titleSelector} from './time-series';
 import {drawDataLines} from './time-series-data';
 import {drawTooltipFocus, drawTooltipText}  from './tooltip';
@@ -86,6 +88,63 @@ const plotAllMedianPoints = function (elem, {visible, xscale, yscale, seriesPoin
     });
 };
 
+/**
+ * Plots the Waterwatch flood level points for a multiple time series.
+ * @param  {Object} elem
+ * @param  {Function} xscale
+ * @param  {Function} yscale
+ * @param  {Number} modulo
+ * @param  {Array} points
+ */
+const plotFloodLevelPoints = function(elem, {xscale, yscale, points, classes}) {
+    const stepFunction = d3Line()
+        .curve(curveStepAfter)
+        .x(function (d) {
+            return xscale(d.date);
+        })
+        .y(function (d) {
+            return yscale(d.value);
+        });
+    const floodLevelGrp = elem.append('g');
+    floodLevelGrp.append('path')
+        .datum(points)
+        .classed(classes[0], true)
+        .classed(classes[1], true)
+        .attr('d', stepFunction);
+};
+
+/**
+ * Plots the Waterwatch points for all flood levels for the current variable.
+ * @param  {Object} elem
+ * @param  {Boolean} visible
+ * @param  {Function} xscale
+ * @param  {Function} yscale
+ * @param  {Array} seriesPoints
+ * @param {Boolean} enableClip
+ */
+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 (enableClip) {
+        container.attr('clip-path', 'url(#graph-clip');
+    }
+    const classes = [['waterwatch-data-series','action-stage'],
+        ['waterwatch-data-series','flood-stage'],
+        ['waterwatch-data-series','moderate-flood-stage'],
+        ['waterwatch-data-series','major-flood-stage']];
+
+    seriesPoints.forEach((points, index) => {
+        plotFloodLevelPoints(container, {xscale, yscale, points: points, classes: classes[index]});
+    });
+};
+
+
 const createTitle = function(elem, store, siteNo, showMLName) {
     let titleDiv = elem.append('div')
         .classed('time-series-graph-title', true);
@@ -196,6 +255,12 @@ export const drawTimeSeriesGraph = function(elem, store, siteNo, showMLName, sho
             xscale: getMainXScale('current'),
             yscale: getMainYScale,
             seriesPoints: getCurrentVariableMedianStatPoints
+        })))
+       .call(link(store, plotAllFloodLevelPoints, createStructuredSelector({
+            visible: waterwatchVisible,
+            xscale: getBrushXScale('current'),
+            yscale: getMainYScale,
+            seriesPoints: getWaterwatchFloodLevelDataPoints
         })));
     if (showTooltip) {
         dataGroup.call(drawTooltipFocus, store);
diff --git a/assets/src/scripts/components/hydrograph/time-series-graph.spec.js b/assets/src/scripts/components/hydrograph/time-series-graph.spec.js
index a059bcbf5..39d57b6fb 100644
--- a/assets/src/scripts/components/hydrograph/time-series-graph.spec.js
+++ b/assets/src/scripts/components/hydrograph/time-series-graph.spec.js
@@ -97,11 +97,11 @@ const TEST_STATE = {
         variables: {
             '45807197': {
                 variableCode: {
-                    value: '00060'
+                    value: '00065'
                 },
                 oid: '45807197',
-                variableName: 'Test title for 00060',
-                variableDescription: 'Test description for 00060',
+                variableName: 'Test title for 00065',
+                variableDescription: 'Test description for 00065',
                 unit: {
                     unitCode: 'unitCode'
                 }
@@ -276,6 +276,28 @@ describe('time series graph', () => {
         });
     });
 
+    describe('flood level lines', () => {
+
+        beforeEach(() => {
+            div.call(drawTimeSeriesGraph, store, '12345678', false, false);
+        });
+
+        it('Should render four lines', () => {
+            expect(selectAll('#flood-level-points .action-stage').size()).toBe(1);
+            expect(selectAll('#flood-level-points .flood-stage').size()).toBe(1);
+            expect(selectAll('#flood-level-points .moderate-flood-stage').size()).toBe(1);
+            expect(selectAll('#flood-level-points .major-flood-stage').size()).toBe(1);
+        });
+
+        it('Should remove the lines when removing the median statistics data', (done) => {
+            store.dispatch(Actions.setCurrentIVVariable(45807190));
+            window.requestAnimationFrame(() => {
+                expect(selectAll('#flood-level-points').size()).toBe(0);
+                done();
+            });
+        });
+    });
+
     describe('monitoring location name', () => {
         it('Should not render the monitoring location name if showMLName is false', () => {
             div.call(drawTimeSeriesGraph, store, '12345678', false, false);
diff --git a/assets/src/scripts/selectors/flood-data-selector.js b/assets/src/scripts/selectors/flood-data-selector.js
index d5fe4b2b9..8a68c7acd 100644
--- a/assets/src/scripts/selectors/flood-data-selector.js
+++ b/assets/src/scripts/selectors/flood-data-selector.js
@@ -1,5 +1,5 @@
 import { createSelector } from 'reselect';
-
+import { getCurrentParmCd } from './time-series-selector';
 
 export const getFloodStages = state => state.floodData.stages || [];
 
@@ -35,6 +35,16 @@ export const hasWaterwatchData = createSelector(
         majorFloodStage != null
 );
 
+/*
+ * Provides a function which returns True if waterwatch flood levels should be visible.
+ */
+export const waterwatchVisible = createSelector(
+    hasWaterwatchData,
+    getCurrentParmCd,
+    (hasWW, paramCd) =>
+        hasWW && paramCd == "00065"
+);
+
 /*
  * Provides a function which returns the stage closest to the gageHeight
  */
diff --git a/assets/src/scripts/selectors/flood-data-selector.spec.js b/assets/src/scripts/selectors/flood-data-selector.spec.js
index db3d7b288..e9f4173cf 100644
--- a/assets/src/scripts/selectors/flood-data-selector.spec.js
+++ b/assets/src/scripts/selectors/flood-data-selector.spec.js
@@ -1,5 +1,5 @@
 import { getFloodStageHeight, hasFloodData, getFloodGageHeightStageIndex,
-    hasWaterwatchData, getWaterwatchFloodLevels} from './flood-data-selector';
+    hasWaterwatchData, getWaterwatchFloodLevels, waterwatchVisible} from './flood-data-selector';
 
 describe('flood-data-selector', () => {
 
@@ -105,7 +105,7 @@ describe('flood-data-selector', () => {
 
        describe('getWaterwatchData', () => {
         it('Return true if waterwatch flood levels are returned', () =>{
-            expect(hasWaterwatchData({
+            expect(getWaterwatchFloodLevels({
                 floodState: {
                     actionStage: 1,
                     floodStage: 2,
@@ -116,6 +116,50 @@ describe('flood-data-selector', () => {
         });
     });
 
+       describe('waterwatchVisible', () => {
+        it('Return false if waterwatch flood levels should not be visible', () =>{
+            expect(waterwatchVisible({
+                floodState: {
+                    actionStage: 1,
+                    floodStage: 2,
+                    moderateFloodStage: 3,
+                    majorFloodStage: 4
+                },
+                ivTimeSeriesState: {
+                    currentIVVariableID: '45807197',
+                },
+                ivTimeSeriesData: {
+                    variables: {
+                        '45807197': {
+                            variableCode: {value: '00060'},
+                        }
+                    }
+                }
+            })).toBeFalsy();
+        });
+
+         it('Return true if waterwatch flood levels should be visible', () =>{
+            expect(waterwatchVisible({
+                floodState: {
+                    actionStage: 1,
+                    floodStage: 2,
+                    moderateFloodStage: 3,
+                    majorFloodStage: 4
+                },
+                ivTimeSeriesState: {
+                    currentIVVariableID: '45807197',
+                },
+                ivTimeSeriesData: {
+                    variables: {
+                        '45807197': {
+                            variableCode: {value: '00065'},
+                        }
+                    }
+                }
+            })).toBeTruthy();
+        });
+    });
+
     describe('getFloodGageHeightStageIndex', () => {
         it('If stages is empty,null is returned', () => {
             expect(getFloodGageHeightStageIndex({
diff --git a/assets/src/scripts/store/flood-inundation.js b/assets/src/scripts/store/flood-inundation.js
index 8e104532f..27711cab3 100644
--- a/assets/src/scripts/store/flood-inundation.js
+++ b/assets/src/scripts/store/flood-inundation.js
@@ -112,10 +112,10 @@ export const floodStateReducer = function(floodState={}, action) {
         case 'SET_WATERWACH_FLOOD_LEVELS':
             return {
                 ...floodState,
-                actionStage: parseInt(action.floodLevels[0].action_stage),
-                floodStage: parseInt(action.floodLevels[0].flood_stage),
-                moderateFloodStage: parseInt(action.floodLevels[0].moderate_flood_stage),
-                majorFloodStage: parseInt(action.floodLevels[0].major_flood_stage)
+                actionStage: action.floodLevels[0] ? parseInt(action.floodLevels[0].action_stage) : null,
+                floodStage: action.floodLevels[0] ? parseInt(action.floodLevels[0].flood_stage) : null,
+                moderateFloodStage: action.floodLevels[0] ? parseInt(action.floodLevels[0].moderate_flood_stage) : null,
+                majorFloodStage: action.floodLevels[0] ? parseInt(action.floodLevels[0].major_flood_stage) : null
             };
         default: return floodState;
     }
diff --git a/assets/src/scripts/web-services/flood-data.spec.js b/assets/src/scripts/web-services/flood-data.spec.js
index 22c644bec..7a041752e 100644
--- a/assets/src/scripts/web-services/flood-data.spec.js
+++ b/assets/src/scripts/web-services/flood-data.spec.js
@@ -1,7 +1,6 @@
 import {fetchFloodExtent, fetchFloodFeatures,
     fetchWaterwatchFloodLevels} from './flood-data';
 import MOCK_WATERWATCH_FLOOD_LEVELS from '../mock-service-data';
-import {} from './waterwatch-data';
 
 
 describe('flood_data module', () => {
diff --git a/assets/src/styles/components/hydrograph/_graph.scss b/assets/src/styles/components/hydrograph/_graph.scss
index ab247782b..779a99e8d 100644
--- a/assets/src/styles/components/hydrograph/_graph.scss
+++ b/assets/src/styles/components/hydrograph/_graph.scss
@@ -180,6 +180,28 @@ svg {
     }
   }
 
+  .waterwatch-data-series {
+    fill: none;
+    stroke-width: 1px;
+    stroke: #001aff;
+
+    &.action-stage {
+      stroke-dasharray: 3, 3;
+    }
+
+    &.flood-stage {
+      stroke-dasharray: 7, 3;
+    }
+
+    &.moderate-flood-stage {
+      stroke-dasharray: 13, 5;
+    }
+
+    &.major-flood-stage {
+      stroke-dasharray: 20, 7;
+    }
+  }
+
   .mask {
     opacity: 0.2;
   }
-- 
GitLab