Mercurial > gemma
changeset 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 | 563bcd8b7d7b |
children | cfd9ac0c92ee |
files | client/src/components/gauge/Gauges.vue client/src/components/gauge/HydrologicalConditions.vue client/src/store/gauges.js |
diffstat | 3 files changed, 118 insertions(+), 66 deletions(-) [+] |
line wrap: on
line diff
--- a/client/src/components/gauge/Gauges.vue Mon Mar 25 11:42:31 2019 +0100 +++ b/client/src/components/gauge/Gauges.vue Mon Mar 25 12:07:00 2019 +0100 @@ -71,7 +71,6 @@ <button @click="showHydrologicalConditionsDiagram()" class="btn btn-sm btn-info d-block w-100 mt-2" - disabled > <translate>Show Hydrological Conditions</translate> </button>
--- 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));
--- a/client/src/store/gauges.js Mon Mar 25 11:42:31 2019 +0100 +++ b/client/src/store/gauges.js Mon Mar 25 12:07:00 2019 +0100 @@ -137,26 +137,36 @@ }); }); }, - loadMeanWaterlevels({ /*state,*/ commit }) { - return new Promise(resolve => { - setTimeout(() => { - commit("meanWaterlevels", [1]); - resolve(); - }, 2000); + loadMeanWaterlevels({ state, commit }) { + return new Promise((resolve, reject) => { + HTTP.get(`/data/average-waterlevels/${state.selectedGaugeISRS}`, { + headers: { "X-Gemma-Auth": localStorage.getItem("token") } + }) + .then(response => { + let data = response.data + .split("\n") + .filter((wl, i) => wl && i) // remove empty rows and first row + .map(wl => { + wl = wl.split(","); + return { + date: new Date(wl[0]), + min: Number(wl[1]), + max: Number(wl[2]), + mean: Number(wl[3]), + median: Number(wl[4]), + q25: Number(wl[5]), + q75: Number(wl[6]) + }; + }); + data = data.sort((a, b) => a.date - b.date); + commit("meanWaterlevels", data); + resolve(data); + }) + .catch(error => { + commit("meanWaterlevels", []); + reject(error); + }); }); - // return new Promise((resolve, reject) => { - // HTTP.get(`/data/mean-waterlevels/${state.selectedGaugeISRS}`, { - // headers: { "X-Gemma-Auth": localStorage.getItem("token") } - // }) - // .then(response => { - // commit("meanWaterlevels", response.data); - // resolve(response.data); - // }) - // .catch(error => { - // commit("meanWaterlevels", []); - // reject(error); - // }) - // }); }, loadNashSutcliffe({ state, commit }) { return new Promise((resolve, reject) => {