diff client/src/components/gauge/HydrologicalConditions.vue @ 2791:2b79c0871138

client: spuc8: draw diagrams The line and area charts from spuc 8 are being drawn but there's a lot missing like tooltips and toggeling individual charts.
author Markus Kottlaender <markus@intevation.de>
date Mon, 25 Mar 2019 12:07:00 +0100
parents 71e7237110ba
children 49c1570919ae
line wrap: on
line diff
--- a/client/src/components/gauge/HydrologicalConditions.vue	Mon Mar 25 11:42:31 2019 +0100
+++ b/client/src/components/gauge/HydrologicalConditions.vue	Mon Mar 25 12:07:00 2019 +0100
@@ -11,8 +11,24 @@
 <style lang="sass" scoped>
 .diagram-container
   /deep/
+    .hide
+      opacity: 0
     .line
       clip-path: url(#clip)
+      stroke-width: 2
+      fill: none
+      &.mean
+        stroke: steelblue
+      &.median
+        stroke: black
+      &.q25
+        stroke: orange
+      &.q75
+        stroke: purple
+    .area
+      clip-path: url(#clip)
+      stroke: none
+      fill: lightsteelblue
 
     .hdc-line,
     .ldc-line,
@@ -64,15 +80,10 @@
  */
 
 import { mapState, mapGetters } from "vuex";
-import * as d3Base from "d3";
+import * as d3 from "d3";
 import debounce from "debounce";
-import { lineChunked } from "d3-line-chunked";
 import { startOfYear, endOfYear } from "date-fns";
 
-// we should load only d3 modules we need but for now we'll go with the lazy way
-// https://www.giacomodebidda.com/how-to-import-d3-plugins-with-webpack/
-const d3 = Object.assign(d3Base, { lineChunked });
-
 export default {
   computed: {
     ...mapState("gauges", ["meanWaterlevels"]),
@@ -158,6 +169,9 @@
         .tickSizeInner(mainHeight)
         .tickSizeOuter(0)
         .tickFormat(date => {
+          // make the x-axis label formats dynamic, based on zoom
+          // but never display year numbers since they don't make any sense in
+          // this diagram
           return (d3.timeSecond(date) < date
             ? d3.timeFormat(".%L")
             : d3.timeMinute(date) < date
@@ -180,27 +194,28 @@
 
       // PREPARING CHART FUNCTIONS
 
-      // points are "next to each other" when they are exactly 1 day apart
-      const isNext = (prev, current) =>
-        current.date - prev.date === 24 * 60 * 60 * 1000;
+      // waterlevel line charts in big chart
+      const lineChart = type =>
+        d3
+          .line()
+          .x(d => x(d.date))
+          .y(d => y(d[type]))
+          .curve(d3.curveLinear);
 
-      // waterlevel line in big chart
-      // d3-line-chunked plugin: https://github.com/pbeshai/d3-line-chunked
-      var mainLineChart = d3
-        .lineChunked()
+      // overall min/max area chart
+      const areaChart = d3
+        .area()
         .x(d => x(d.date))
-        .y(d => y(d.waterlevel))
-        .curve(d3.curveLinear)
-        .isNext(isNext)
-        .pointAttrs({ r: 2.2 });
-      // waterlevel line in small chart
-      let navLineChart = d3
-        .lineChunked()
+        .y0(d => y(d.min))
+        .y1(d => y(d.max));
+
+      // overall min/max area chart in nav
+      const areaChartNav = d3
+        .area()
         .x(d => x2(d.date))
-        .y(d => y2(d.waterlevel))
-        .curve(d3.curveMonotoneX)
-        .isNext(isNext)
-        .pointAttrs({ r: 1.7 });
+        .y0(d => y2(d.min))
+        .y1(d => y2(d.max));
+
       // hdc/ldc/mw
       let refWaterlevelLine = d3
         .line()
@@ -243,6 +258,13 @@
         .selectAll(".tick text")
         .attr("x", -25);
 
+      // overall min/max area chart
+      mainChart
+        .append("path")
+        .datum(this.meanWaterlevels)
+        .attr("class", "area")
+        .attr("d", areaChart);
+
       // reference waterlevels
       // HDC
       mainChart
@@ -290,12 +312,30 @@
         .attr("x", x(yearEnd) - 20)
         .attr("y", y(refWaterLevels.MW) - 3);
 
-      // waterlevel chart
+      // mean waterlevel chart
+      mainChart
+        .append("path")
+        .attr("class", "line mean")
+        .datum(this.meanWaterlevels)
+        .attr("d", lineChart("mean"));
+      // median waterlevel chart
       mainChart
-        .append("g")
-        .attr("class", "line")
-        .datum([])
-        .call(mainLineChart);
+        .append("path")
+        .attr("class", "line median")
+        .datum(this.meanWaterlevels)
+        .attr("d", lineChart("median"));
+      // q25 waterlevel chart
+      mainChart
+        .append("path")
+        .attr("class", "line q25")
+        .datum(this.meanWaterlevels)
+        .attr("d", lineChart("q25"));
+      // q75 waterlevel chart
+      mainChart
+        .append("path")
+        .attr("class", "line q75")
+        .datum(this.meanWaterlevels)
+        .attr("d", lineChart("q75"));
 
       // DRAWING NAVCHART
 
@@ -311,15 +351,28 @@
         .attr("transform", `translate(0, ${navHeight})`)
         .call(xAxis2);
 
-      // waterlevel chart
+      // overall min/max area chart
       navChart
-        .append("g")
-        .attr("class", "line")
-        .datum([])
-        .call(navLineChart);
+        .append("path")
+        .datum(this.meanWaterlevels)
+        .attr("class", "area")
+        .attr("d", areaChartNav);
 
       // INTERACTIVITY
 
+      const updateChart = () => {
+        mainChart.select(".line.mean").attr("d", lineChart("mean"));
+        mainChart.select(".line.median").attr("d", lineChart("median"));
+        mainChart.select(".line.q25").attr("d", lineChart("q25"));
+        mainChart.select(".line.q75").attr("d", lineChart("q75"));
+        mainChart.select(".area").attr("d", areaChart);
+        mainChart
+          .select(".axis--x")
+          .call(xAxis)
+          .selectAll(".tick text")
+          .attr("y", 15);
+      };
+
       // selecting time period in nav chart
       let brush = d3
         .brushX()
@@ -330,12 +383,7 @@
             return; // ignore brush-by-zoom
           let s = d3.event.selection || x2.range();
           x.domain(s.map(x2.invert, x2));
-          mainChart.select(".line").call(mainLineChart);
-          mainChart
-            .select(".axis--x")
-            .call(xAxis)
-            .selectAll(".tick text")
-            .attr("y", 15);
+          updateChart();
           svg
             .select(".zoom")
             .call(
@@ -355,12 +403,7 @@
             return; // ignore zoom-by-brush
           let t = d3.event.transform;
           x.domain(t.rescaleX(x2).domain());
-          mainChart.select(".line").call(mainLineChart);
-          mainChart
-            .select(".axis--x")
-            .call(xAxis)
-            .selectAll(".tick text")
-            .attr("y", 15);
+          updateChart();
           navChart
             .select(".brush")
             .call(brush.move, x.range().map(t.invertX, t));