changeset 2775:2feb9f8f6c66

client: waterlevel diagram: implemented display of forecast data
author Markus Kottlaender <markus@intevation.de>
date Fri, 22 Mar 2019 13:00:10 +0100
parents 6c1c4f55d99b
children a0b63e2fca99
files client/src/components/gauge/Waterlevel.vue client/src/store/gauges.js
diffstat 2 files changed, 108 insertions(+), 28 deletions(-) [+]
line wrap: on
line diff
--- a/client/src/components/gauge/Waterlevel.vue	Fri Mar 22 12:45:53 2019 +0100
+++ b/client/src/components/gauge/Waterlevel.vue	Fri Mar 22 13:00:10 2019 +0100
@@ -41,7 +41,19 @@
       font-size: 11px
       fill: #999
     .hdc-ldc-area
-      fill: rgba(0, 255, 0, 0.15)
+      fill: rgba(0, 255, 0, 0.1)
+    .now-line
+      stroke: #999
+      stroke-width: 1
+      stroke-dasharray: 5, 5
+      clip-path: url(#clip)
+    .now-line-label
+      font-size: 11px
+      fill: #999
+    .prediction-area
+      fill: steelblue
+      fill-opacity: 0.2
+      clip-path: url(#clip)
 
     path.nash-sutcliffe
       fill: none
@@ -219,6 +231,15 @@
       const isNext = (prev, current) =>
         current.date - prev.date === 15 * 60 * 1000;
 
+      const preditionStyle = {
+        predicted: {
+          pointStyles: {
+            fill: "steelblue",
+            "fill-opacity": 0.6
+          }
+        }
+      };
+
       // waterlevel line in big chart
       // d3-line-chunked plugin: https://github.com/pbeshai/d3-line-chunked
       var mainLineChart = d3
@@ -227,7 +248,9 @@
         .y(d => y(d.waterlevel))
         .curve(d3.curveLinear)
         .isNext(isNext)
-        .pointAttrs({ r: 2.2 });
+        .pointAttrs({ r: 2.2 })
+        .chunk(d => (d.predicted ? "predicted" : "line"))
+        .chunkDefinitions(preditionStyle);
       // waterlevel line in small chart
       let navLineChart = d3
         .lineChunked()
@@ -235,12 +258,42 @@
         .y(d => y2(d.waterlevel))
         .curve(d3.curveMonotoneX)
         .isNext(isNext)
-        .pointAttrs({ r: 1.7 });
+        .pointAttrs({ r: 1.7 })
+        .chunk(d => (d.predicted ? "predicted" : "line"))
+        .chunkDefinitions(preditionStyle);
       // hdc/ldc/mw
       let refWaterlevelLine = d3
         .line()
         .x(d => x(d.x))
         .y(d => y(d.y));
+      // now
+      let nowLine = d3
+        .line()
+        .x(d => x(d.x))
+        .y(d => y(d.y));
+      let nowLineNav = d3
+        .line()
+        .x(d => x2(d.x))
+        .y(d => y2(d.y));
+      let nowLineLabel = selection => {
+        selection.attr(
+          "transform",
+          `translate(${x(new Date())}, ${y(WaterlevelMinMax[1] - 16)})`
+        );
+      };
+      // prediction area
+      let predictionArea = d3
+        .area()
+        .defined(d => d.predicted && d.min && d.max)
+        .x(d => x(d.date))
+        .y0(d => y(d.min))
+        .y1(d => y(d.max));
+      let predictionAreaNav = d3
+        .area()
+        .defined(d => d.predicted && d.min && d.max)
+        .x(d => x2(d.date))
+        .y0(d => y2(d.min))
+        .y1(d => y2(d.max));
 
       // DRAWING MAINCHART
 
@@ -334,6 +387,29 @@
         .attr("x", x(dateTo) - 20)
         .attr("y", y(refWaterLevels.MW) - 3);
 
+      // now
+      mainChart
+        .append("path")
+        .datum([
+          { x: new Date(), y: WaterlevelMinMax[0] },
+          { x: new Date(), y: WaterlevelMinMax[1] - 20 }
+        ])
+        .attr("class", "now-line")
+        .attr("d", nowLine);
+      mainChart // label
+        .append("text")
+        .text(this.$gettext("Now"))
+        .attr("class", "now-line-label")
+        .attr("text-anchor", "middle")
+        .call(nowLineLabel);
+
+      // prediction area
+      mainChart
+        .append("path")
+        .datum(this.waterlevels)
+        .attr("class", "prediction-area")
+        .attr("d", predictionArea);
+
       // waterlevel chart
       mainChart
         .append("g")
@@ -355,6 +431,23 @@
         .attr("transform", `translate(0, ${navHeight})`)
         .call(xAxis2);
 
+      // now
+      navChart
+        .append("path")
+        .datum([
+          { x: new Date(), y: WaterlevelMinMax[0] },
+          { x: new Date(), y: WaterlevelMinMax[1] - 20 }
+        ])
+        .attr("class", "now-line")
+        .attr("d", nowLineNav);
+
+      // prediction area
+      navChart
+        .append("path")
+        .datum(this.waterlevels)
+        .attr("class", "prediction-area")
+        .attr("d", predictionAreaNav);
+
       // waterlevel chart
       navChart
         .append("g")
@@ -391,10 +484,10 @@
           .attr("y", mainHeight - (15 * days + 0.5) + 12);
       };
 
-      // Show nash-sutcliffe only when x-axis extent is smaller than 31 days
-      // (2678400000 ms). Since it shows squares representing 1, 2 and 3 days
+      // Show nash-sutcliffe only when x-axis extent is smaller than 35 days
+      // (3024000000 ms). Since it shows squares representing 1, 2 and 3 days
       // it does not make sense to show them on a x-axis with hundres of days.
-      if (this.nashSutcliffe && x.domain()[1] - x.domain()[0] < 2678400000) {
+      if (this.nashSutcliffe && x.domain()[1] - x.domain()[0] < 3024000000) {
         if (nashSut24.samples) {
           mainChart
             .append("path")
@@ -467,6 +560,9 @@
           let s = d3.event.selection || x2.range();
           x.domain(s.map(x2.invert, x2));
           mainChart.select(".line").call(mainLineChart);
+          mainChart.select(".now-line").attr("d", nowLine);
+          mainChart.select(".now-line-label").call(nowLineLabel);
+          mainChart.select(".prediction-area").attr("d", predictionArea);
           mainChart
             .select("path.nash-sutcliffe.ns24")
             .attr("d", nashSutcliffeBox(24));
@@ -510,6 +606,9 @@
           let t = d3.event.transform;
           x.domain(t.rescaleX(x2).domain());
           mainChart.select(".line").call(mainLineChart);
+          mainChart.select(".now-line").attr("d", nowLine);
+          mainChart.select(".now-line-label").call(nowLineLabel);
+          mainChart.select(".prediction-area").attr("d", predictionArea);
           mainChart
             .select("path.nash-sutcliffe.ns24")
             .attr("d", nashSutcliffeBox(24));
--- a/client/src/store/gauges.js	Fri Mar 22 12:45:53 2019 +0100
+++ b/client/src/store/gauges.js	Fri Mar 22 13:00:10 2019 +0100
@@ -17,6 +17,8 @@
 
 let dateFrom = new Date();
 dateFrom.setDate(dateFrom.getDate() - 30);
+let dateTo = new Date();
+dateTo.setDate(dateTo.getDate() + 3);
 
 const init = () => {
   return {
@@ -26,7 +28,7 @@
     meanWaterlevels: [],
     nashSutcliffe: null,
     dateFrom: dateFrom,
-    dateTo: new Date()
+    dateTo: dateTo
   };
 };
 
@@ -163,27 +165,6 @@
         })
           .then(response => {
             commit("nashSutcliffe", response.data);
-            // dest data
-            // commit("nashSutcliffe", {
-            //   when: "2019-03-20T10:38:05.687",
-            //   coeffs: [
-            //     {
-            //       value: 0.814,
-            //       samples: 18,
-            //       hours: 24
-            //     },
-            //     {
-            //       value: 0.319,
-            //       samples: 36,
-            //       hours: 48
-            //     },
-            //     {
-            //       value: -0.20546757,
-            //       samples: 54,
-            //       hours: 72
-            //     }
-            //   ]
-            // });
             resolve(response.data);
           })
           .catch(error => {