diff client/src/components/gauge/Waterlevel.vue @ 2590:1686ec185155

client: added gauge waterlevel example diagram
author Markus Kottlaender <markus@intevation.de>
date Tue, 12 Mar 2019 08:37:09 +0100
parents
children 8774054959a7
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/src/components/gauge/Waterlevel.vue	Tue Mar 12 08:37:09 2019 +0100
@@ -0,0 +1,222 @@
+<template>
+  <div class="flex-fill diagram-container"></div>
+</template>
+
+<style lang="sass" scoped>
+.diagram-container
+  /deep/ .area
+    stroke: steelblue
+    stroke-width: 2
+    fill: transparent
+    clip-path: url(#clip)
+
+  /deep/ .zoom
+    cursor: move
+    fill: none
+    pointer-events: all
+</style>
+
+<script>
+/* This is Free Software under GNU Affero General Public License v >= 3.0
+ * without warranty, see README.md and license for details.
+ *
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ * License-Filename: LICENSES/AGPL-3.0.txt
+ *
+ * Copyright (C) 2018 by via donau
+ *   – Österreichische Wasserstraßen-Gesellschaft mbH
+ * Software engineering by Intevation GmbH
+ *
+ * Author(s):
+ * Markus Kottländer <markus.kottlaender@intevation.de>
+ */
+
+import { mapState } from "vuex";
+import * as d3 from "d3";
+import debounce from "debounce";
+
+export default {
+  computed: {
+    ...mapState("gauges", ["selectedGauge"]),
+    waterlevels() {
+      let data = [];
+      let waterlevel = 2.5;
+      for (let i = 1; i <= 365; i++) {
+        let date = new Date();
+        date.setFullYear(2018);
+        date.setDate(date.getDate() + i);
+        waterlevel *= Math.random() * (1.02 - 0.98) + 0.98;
+        data.push({ date, waterlevel });
+      }
+      return data;
+    }
+  },
+  methods: {
+    drawDiagram() {
+      var svgWidth = document.querySelector(".diagram-container").clientWidth;
+      var svgHeight = document.querySelector(".diagram-container").clientHeight;
+      d3.select(".diagram-container svg").remove();
+      var svg = d3.select(".diagram-container").append("svg");
+      svg.attr("width", "100%").attr("height", "100%");
+      let margin = { top: 20, right: 20, bottom: 110, left: 40 },
+        margin2 = {
+          top: svgHeight - margin.top - 50,
+          right: 20,
+          bottom: 30,
+          left: 40
+        },
+        width = +svgWidth - margin.left - margin.right,
+        height = +svgHeight - margin.top - margin.bottom,
+        height2 = +svgHeight - margin2.top - margin2.bottom;
+
+      var x = d3.scaleTime().range([0, width]),
+        x2 = d3.scaleTime().range([0, width]),
+        y = d3.scaleLinear().range([height, 0]),
+        y2 = d3.scaleLinear().range([height2, 0]);
+
+      var xAxis = d3.axisBottom(x),
+        xAxis2 = d3.axisBottom(x2),
+        yAxis = d3.axisLeft(y);
+
+      var brush = d3
+        .brushX()
+        .extent([[0, 0], [width, height2]])
+        .on("brush end", brushed);
+
+      var zoom = d3
+        .zoom()
+        .scaleExtent([1, Infinity])
+        .translateExtent([[0, 0], [width, height]])
+        .extent([[0, 0], [width, height]])
+        .on("zoom", zoomed);
+
+      var area = d3
+        .line()
+        .curve(d3.curveMonotoneX)
+        .x(function(d) {
+          return x(d.date);
+        })
+        .y(function(d) {
+          return y(d.waterlevel);
+        });
+
+      var area2 = d3
+        .line()
+        .curve(d3.curveMonotoneX)
+        .x(function(d) {
+          return x2(d.date);
+        })
+        .y(function(d) {
+          return y2(d.waterlevel);
+        });
+
+      svg
+        .append("defs")
+        .append("clipPath")
+        .attr("id", "clip")
+        .append("rect")
+        .attr("width", width)
+        .attr("height", height);
+
+      var focus = svg
+        .append("g")
+        .attr("class", "focus")
+        .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
+
+      var context = svg
+        .append("g")
+        .attr("class", "context")
+        .attr(
+          "transform",
+          "translate(" + margin2.left + "," + margin2.top + ")"
+        );
+
+      x.domain(
+        d3.extent(this.waterlevels, function(d) {
+          return d.date;
+        })
+      );
+      y.domain([0, 5]);
+      x2.domain(x.domain());
+      y2.domain(y.domain());
+
+      focus
+        .append("path")
+        .datum(this.waterlevels)
+        .attr("class", "area")
+        .attr("d", area);
+
+      focus
+        .append("g")
+        .attr("class", "axis axis--x")
+        .attr("transform", "translate(0," + height + ")")
+        .call(xAxis);
+
+      focus
+        .append("g")
+        .attr("class", "axis axis--y")
+        .call(yAxis);
+
+      context
+        .append("path")
+        .datum(this.waterlevels)
+        .attr("class", "area")
+        .attr("d", area2);
+
+      context
+        .append("g")
+        .attr("class", "axis axis--x")
+        .attr("transform", "translate(0," + height2 + ")")
+        .call(xAxis2);
+
+      context
+        .append("g")
+        .attr("class", "brush")
+        .call(brush)
+        .call(brush.move, x.range());
+
+      svg
+        .append("rect")
+        .attr("class", "zoom")
+        .attr("width", width)
+        .attr("height", height)
+        .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
+        .call(zoom);
+
+      function brushed() {
+        if (d3.event.sourceEvent && d3.event.sourceEvent.type === "zoom")
+          return; // ignore brush-by-zoom
+        var s = d3.event.selection || x2.range();
+        x.domain(s.map(x2.invert, x2));
+        focus.select(".area").attr("d", area);
+        focus.select(".axis--x").call(xAxis);
+        svg
+          .select(".zoom")
+          .call(
+            zoom.transform,
+            d3.zoomIdentity.scale(width / (s[1] - s[0])).translate(-s[0], 0)
+          );
+      }
+
+      function zoomed() {
+        if (d3.event.sourceEvent && d3.event.sourceEvent.type === "brush")
+          return; // ignore zoom-by-brush
+        var t = d3.event.transform;
+        x.domain(t.rescaleX(x2).domain());
+        focus.select(".area").attr("d", area);
+        focus.select(".axis--x").call(xAxis);
+        context.select(".brush").call(brush.move, x.range().map(t.invertX, t));
+      }
+    }
+  },
+  created() {
+    window.addEventListener("resize", debounce(this.drawDiagram), 100);
+  },
+  mounted() {
+    this.drawDiagram();
+  },
+  updated() {
+    this.drawDiagram();
+  }
+};
+</script>