comparison 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
comparison
equal deleted inserted replaced
2589:f4c399a496cb 2590:1686ec185155
1 <template>
2 <div class="flex-fill diagram-container"></div>
3 </template>
4
5 <style lang="sass" scoped>
6 .diagram-container
7 /deep/ .area
8 stroke: steelblue
9 stroke-width: 2
10 fill: transparent
11 clip-path: url(#clip)
12
13 /deep/ .zoom
14 cursor: move
15 fill: none
16 pointer-events: all
17 </style>
18
19 <script>
20 /* This is Free Software under GNU Affero General Public License v >= 3.0
21 * without warranty, see README.md and license for details.
22 *
23 * SPDX-License-Identifier: AGPL-3.0-or-later
24 * License-Filename: LICENSES/AGPL-3.0.txt
25 *
26 * Copyright (C) 2018 by via donau
27 * – Österreichische Wasserstraßen-Gesellschaft mbH
28 * Software engineering by Intevation GmbH
29 *
30 * Author(s):
31 * Markus Kottländer <markus.kottlaender@intevation.de>
32 */
33
34 import { mapState } from "vuex";
35 import * as d3 from "d3";
36 import debounce from "debounce";
37
38 export default {
39 computed: {
40 ...mapState("gauges", ["selectedGauge"]),
41 waterlevels() {
42 let data = [];
43 let waterlevel = 2.5;
44 for (let i = 1; i <= 365; i++) {
45 let date = new Date();
46 date.setFullYear(2018);
47 date.setDate(date.getDate() + i);
48 waterlevel *= Math.random() * (1.02 - 0.98) + 0.98;
49 data.push({ date, waterlevel });
50 }
51 return data;
52 }
53 },
54 methods: {
55 drawDiagram() {
56 var svgWidth = document.querySelector(".diagram-container").clientWidth;
57 var svgHeight = document.querySelector(".diagram-container").clientHeight;
58 d3.select(".diagram-container svg").remove();
59 var svg = d3.select(".diagram-container").append("svg");
60 svg.attr("width", "100%").attr("height", "100%");
61 let margin = { top: 20, right: 20, bottom: 110, left: 40 },
62 margin2 = {
63 top: svgHeight - margin.top - 50,
64 right: 20,
65 bottom: 30,
66 left: 40
67 },
68 width = +svgWidth - margin.left - margin.right,
69 height = +svgHeight - margin.top - margin.bottom,
70 height2 = +svgHeight - margin2.top - margin2.bottom;
71
72 var x = d3.scaleTime().range([0, width]),
73 x2 = d3.scaleTime().range([0, width]),
74 y = d3.scaleLinear().range([height, 0]),
75 y2 = d3.scaleLinear().range([height2, 0]);
76
77 var xAxis = d3.axisBottom(x),
78 xAxis2 = d3.axisBottom(x2),
79 yAxis = d3.axisLeft(y);
80
81 var brush = d3
82 .brushX()
83 .extent([[0, 0], [width, height2]])
84 .on("brush end", brushed);
85
86 var zoom = d3
87 .zoom()
88 .scaleExtent([1, Infinity])
89 .translateExtent([[0, 0], [width, height]])
90 .extent([[0, 0], [width, height]])
91 .on("zoom", zoomed);
92
93 var area = d3
94 .line()
95 .curve(d3.curveMonotoneX)
96 .x(function(d) {
97 return x(d.date);
98 })
99 .y(function(d) {
100 return y(d.waterlevel);
101 });
102
103 var area2 = d3
104 .line()
105 .curve(d3.curveMonotoneX)
106 .x(function(d) {
107 return x2(d.date);
108 })
109 .y(function(d) {
110 return y2(d.waterlevel);
111 });
112
113 svg
114 .append("defs")
115 .append("clipPath")
116 .attr("id", "clip")
117 .append("rect")
118 .attr("width", width)
119 .attr("height", height);
120
121 var focus = svg
122 .append("g")
123 .attr("class", "focus")
124 .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
125
126 var context = svg
127 .append("g")
128 .attr("class", "context")
129 .attr(
130 "transform",
131 "translate(" + margin2.left + "," + margin2.top + ")"
132 );
133
134 x.domain(
135 d3.extent(this.waterlevels, function(d) {
136 return d.date;
137 })
138 );
139 y.domain([0, 5]);
140 x2.domain(x.domain());
141 y2.domain(y.domain());
142
143 focus
144 .append("path")
145 .datum(this.waterlevels)
146 .attr("class", "area")
147 .attr("d", area);
148
149 focus
150 .append("g")
151 .attr("class", "axis axis--x")
152 .attr("transform", "translate(0," + height + ")")
153 .call(xAxis);
154
155 focus
156 .append("g")
157 .attr("class", "axis axis--y")
158 .call(yAxis);
159
160 context
161 .append("path")
162 .datum(this.waterlevels)
163 .attr("class", "area")
164 .attr("d", area2);
165
166 context
167 .append("g")
168 .attr("class", "axis axis--x")
169 .attr("transform", "translate(0," + height2 + ")")
170 .call(xAxis2);
171
172 context
173 .append("g")
174 .attr("class", "brush")
175 .call(brush)
176 .call(brush.move, x.range());
177
178 svg
179 .append("rect")
180 .attr("class", "zoom")
181 .attr("width", width)
182 .attr("height", height)
183 .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
184 .call(zoom);
185
186 function brushed() {
187 if (d3.event.sourceEvent && d3.event.sourceEvent.type === "zoom")
188 return; // ignore brush-by-zoom
189 var s = d3.event.selection || x2.range();
190 x.domain(s.map(x2.invert, x2));
191 focus.select(".area").attr("d", area);
192 focus.select(".axis--x").call(xAxis);
193 svg
194 .select(".zoom")
195 .call(
196 zoom.transform,
197 d3.zoomIdentity.scale(width / (s[1] - s[0])).translate(-s[0], 0)
198 );
199 }
200
201 function zoomed() {
202 if (d3.event.sourceEvent && d3.event.sourceEvent.type === "brush")
203 return; // ignore zoom-by-brush
204 var t = d3.event.transform;
205 x.domain(t.rescaleX(x2).domain());
206 focus.select(".area").attr("d", area);
207 focus.select(".axis--x").call(xAxis);
208 context.select(".brush").call(brush.move, x.range().map(t.invertX, t));
209 }
210 }
211 },
212 created() {
213 window.addEventListener("resize", debounce(this.drawDiagram), 100);
214 },
215 mounted() {
216 this.drawDiagram();
217 },
218 updated() {
219 this.drawDiagram();
220 }
221 };
222 </script>