Mercurial > gemma
changeset 2604:85f9bf4a6eba
client: gauge waterlevel diagram: draw reference waterlevels
author | Markus Kottlaender <markus@intevation.de> |
---|---|
date | Tue, 12 Mar 2019 17:08:07 +0100 |
parents | 8d767359fddb |
children | e12df0bf2f8d |
files | client/src/components/gauge/Gauges.vue client/src/components/gauge/Waterlevel.vue client/src/store/gauges.js client/src/store/map.js |
diffstat | 4 files changed, 147 insertions(+), 63 deletions(-) [+] |
line wrap: on
line diff
--- a/client/src/components/gauge/Gauges.vue Tue Mar 12 16:16:43 2019 +0100 +++ b/client/src/components/gauge/Gauges.vue Tue Mar 12 17:08:07 2019 +0100 @@ -20,7 +20,7 @@ </div> <select @change="moveToGauge" - v-model="selectedGauge" + v-model="selectedGaugeName" class="form-control font-weight-bold" > <option :value="null"> @@ -34,7 +34,7 @@ {{ g.properties.objname }} </option> </select> - <div v-if="selectedGauge" class="mt-2"> + <div v-if="selectedGaugeName" class="mt-2"> <hr class="mb-1" /> <small class="text-muted"> <translate>Time period</translate>: @@ -90,7 +90,7 @@ * Author(s): * Markus Kottländer <markus.kottlaender@intevation.de> */ -import { mapState } from "vuex"; +import { mapState, mapGetters } from "vuex"; export default { data() { @@ -101,13 +101,14 @@ }, computed: { ...mapState("application", ["showGauges"]), - ...mapState("gauges", ["gauges", "selectedGauge"]), - selectedGauge: { + ...mapState("gauges", ["gauges"]), + ...mapGetters("gauges", ["selectedGauge"]), + selectedGaugeName: { get() { - return this.$store.state.gauges.selectedGauge; + return this.$store.state.gauges.selectedGaugeName; }, set(name) { - this.$store.dispatch("gauges/selectedGauge", name); + this.$store.dispatch("gauges/selectedGaugeName", name); } } }, @@ -116,34 +117,27 @@ this.$store.commit("application/showGauges", false); }, moveToGauge() { - let gauge = this.gauges.find( - g => g.properties.objname === this.selectedGauge - ); - if (!gauge) return; + if (!this.selectedGauge) return; this.$store.commit("map/moveToExtent", { - feature: gauge, + feature: this.selectedGauge, zoom: 17, preventZoomOut: true }); }, showWaterlevelDiagram() { - let gauge = this.gauges.find( - g => g.properties.objname === this.selectedGauge - ); - // configure splitscreen let splitscreenConf = { id: "gauge-waterlevel", component: "waterlevel", - title: this.selectedGauge, + title: this.selectedGaugeName, icon: "ruler-vertical", closeCallback: () => { - this.$store.commit("gauges/selectedGauge", null); + this.$store.commit("gauges/selectedGaugeName", null); this.$store.commit("gauges/waterlevels", []); }, expandCallback: () => { this.$store.commit("map/moveMap", { - coordinates: gauge.geometry.coordinates, + coordinates: this.selectedGauge.geometry.coordinates, zoom: 17, preventZoomOut: true });
--- a/client/src/components/gauge/Waterlevel.vue Tue Mar 12 16:16:43 2019 +0100 +++ b/client/src/components/gauge/Waterlevel.vue Tue Mar 12 17:08:07 2019 +0100 @@ -4,16 +4,30 @@ <style lang="sass" scoped> .diagram-container - /deep/ .area - stroke: steelblue - stroke-width: 2 - fill: transparent - clip-path: url(#clip) + /deep/ + .area + stroke: steelblue + stroke-width: 2 + fill: transparent + clip-path: url(#clip) + + .zoom + cursor: move + fill: none + pointer-events: all - /deep/ .zoom - cursor: move - fill: none - pointer-events: all + .hdc-line, + .ldc-line, + .mw-line + stroke-width: 1 + fill: transparent + clip-path: url(#clip) + .hdc-line + stroke: red + .ldc-line + stroke: green + .mw-line + stroke: grey </style> <script> @@ -31,13 +45,14 @@ * Markus Kottländer <markus.kottlaender@intevation.de> */ -import { mapState } from "vuex"; +import { mapState, mapGetters } from "vuex"; import * as d3 from "d3"; import debounce from "debounce"; export default { computed: { - ...mapState("gauges", ["selectedGauge", "waterlevels"]) + ...mapState("gauges", ["waterlevels"]), + ...mapGetters("gauges", ["selectedGauge"]) }, watch: { waterlevels() { @@ -46,10 +61,16 @@ }, methods: { drawDiagram() { - var svgWidth = document.querySelector(".diagram-container").clientWidth; - var svgHeight = document.querySelector(".diagram-container").clientHeight; + if (!this.selectedGauge || !this.waterlevels.length) return; + + let refWaterLevels = JSON.parse( + this.selectedGauge.properties.reference_water_levels + ); + + let svgWidth = document.querySelector(".diagram-container").clientWidth; + let svgHeight = document.querySelector(".diagram-container").clientHeight; d3.select(".diagram-container svg").remove(); - var svg = d3.select(".diagram-container").append("svg"); + let 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 = { @@ -62,28 +83,52 @@ height = +svgHeight - margin.top - margin.bottom, height2 = +svgHeight - margin2.top - margin2.bottom; - var x = d3.scaleTime().range([0, width]), + let 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), + let xAxis = d3.axisBottom(x), xAxis2 = d3.axisBottom(x2), yAxis = d3.axisLeft(y); - var brush = d3 + // find min/max values for the waterlevel axis + // based on hdc/ldc +/- 100 cm + let xMinMax = d3.extent( + [ + ...this.waterlevels, + { waterlevel: refWaterLevels.HDC + 100 }, + { waterlevel: Math.max(refWaterLevels.LDC - 100, 0) } + ], + function(d) { + return d.waterlevel; + } + ); + + x.domain( + d3.extent(this.waterlevels, function(d) { + return d.date; + }) + ); + y.domain(xMinMax); + x2.domain(x.domain()); + y2.domain(y.domain()); + + let brush = d3 .brushX() + .handleSize(4) .extent([[0, 0], [width, height2]]) .on("brush end", brushed); - var zoom = d3 + let zoom = d3 .zoom() .scaleExtent([1, Infinity]) .translateExtent([[0, 0], [width, height]]) .extent([[0, 0], [width, height]]) .on("zoom", zoomed); - var area = d3 + // waterlevel line in big chart + let area = d3 .line() .curve(d3.curveMonotoneX) .x(function(d) { @@ -93,7 +138,8 @@ return y(d.waterlevel); }); - var area2 = d3 + // waterlevel line in small chart + let area2 = d3 .line() .curve(d3.curveMonotoneX) .x(function(d) { @@ -103,6 +149,11 @@ return y2(d.waterlevel); }); + let refWaterlevelLine = d3 + .line() + .x(d => x(d.x)) + .y(d => y(d.y)); + svg .append("defs") .append("clipPath") @@ -111,12 +162,12 @@ .attr("width", width) .attr("height", height); - var focus = svg + let focus = svg .append("g") .attr("class", "focus") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); - var context = svg + let context = svg .append("g") .attr("class", "context") .attr( @@ -124,15 +175,6 @@ "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) @@ -140,6 +182,42 @@ .attr("d", area); focus + .append("path") + .datum([ + { x: 0, y: refWaterLevels.HDC }, + { + x: this.waterlevels[this.waterlevels.length - 1].date, + y: refWaterLevels.HDC + } + ]) + .attr("class", "hdc-line") + .attr("d", refWaterlevelLine); + + focus + .append("path") + .datum([ + { x: 0, y: refWaterLevels.LDC }, + { + x: this.waterlevels[this.waterlevels.length - 1].date, + y: refWaterLevels.LDC + } + ]) + .attr("class", "ldc-line") + .attr("d", refWaterlevelLine); + + focus + .append("path") + .datum([ + { x: 0, y: refWaterLevels.MW }, + { + x: this.waterlevels[this.waterlevels.length - 1].date, + y: refWaterLevels.MW + } + ]) + .attr("class", "mw-line") + .attr("d", refWaterlevelLine); + + focus .append("g") .attr("class", "axis axis--x") .attr("transform", "translate(0," + height + ")") @@ -179,7 +257,7 @@ function brushed() { if (d3.event.sourceEvent && d3.event.sourceEvent.type === "zoom") return; // ignore brush-by-zoom - var s = d3.event.selection || x2.range(); + let 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); @@ -194,7 +272,7 @@ function zoomed() { if (d3.event.sourceEvent && d3.event.sourceEvent.type === "brush") return; // ignore zoom-by-brush - var t = d3.event.transform; + let t = d3.event.transform; x.domain(t.rescaleX(x2).domain()); focus.select(".area").attr("d", area); focus.select(".axis--x").call(xAxis);
--- a/client/src/store/gauges.js Tue Mar 12 16:16:43 2019 +0100 +++ b/client/src/store/gauges.js Tue Mar 12 17:08:07 2019 +0100 @@ -17,7 +17,7 @@ const init = () => { return { gauges: [], - selectedGauge: null, + selectedGaugeName: null, waterlevels: [], loading: false }; @@ -27,12 +27,19 @@ init, namespaced: true, state: init(), + getters: { + selectedGauge: state => { + return state.gauges.find( + g => g.properties.objname === state.selectedGaugeName + ); + } + }, mutations: { gauges: (state, gauges) => { state.gauges = gauges; }, - selectedGauge: (state, gauge) => { - state.selectedGauge = gauge; + selectedGaugeName: (state, name) => { + state.selectedGaugeName = name; }, waterlevels: (state, data) => { state.waterlevels = data; @@ -42,8 +49,8 @@ } }, actions: { - selectedGauge: ({ commit }, name) => { - commit("selectedGauge", name); + selectedGaugeName: ({ commit }, name) => { + commit("selectedGaugeName", name); commit("application/showGauges", true, { root: true }); commit("application/showSplitscreen", false, { root: true }); }, @@ -77,11 +84,11 @@ }, loadWaterlevels({ state, commit }, timePeriod) { return new Promise(resolve => { - if (state.selectedGauge && timePeriod) { + if (state.selectedGaugeName && timePeriod) { // generate some demo values setTimeout(() => { let data = []; - let waterlevel = 2.5; + let waterlevel = 380; for (let i = 1; i <= 365; i++) { let date = new Date(); date.setFullYear(2018);
--- a/client/src/store/map.js Tue Mar 12 16:16:43 2019 +0100 +++ b/client/src/store/map.js Tue Mar 12 17:08:07 2019 +0100 @@ -794,11 +794,16 @@ // get selected gauge if (/^gauges/.test(id)) { if ( - rootState.gauges.selectedGauge !== feature.get("objname") + rootState.gauges.selectedGaugeName !== + feature.get("objname") ) { - dispatch("gauges/selectedGauge", feature.get("objname"), { - root: true - }); + dispatch( + "gauges/selectedGaugeName", + feature.get("objname"), + { + root: true + } + ); commit("moveMap", { coordinates: getCenter( feature