Mercurial > gemma
view client/src/components/fairway/AvailableFairwayDepth.vue @ 3159:4f4905b57fcf
toolbar: added statistics dialog component
author | Thomas Junk <thomas.junk@intevation.de> |
---|---|
date | Mon, 06 May 2019 13:02:25 +0200 |
parents | 8159bd2aaf93 |
children | 429e28295902 |
line wrap: on
line source
<template> <div> <h1>Available Fairway Depth</h1> <UISpinnerOverlay v-if="loading" /> <div class="d-flex flex-row"> <div class="ml-3 mr-auto"> <ul> <li v-for="(entry, index) in legend" :key="index">{{ entry }}</li> </ul> </div> <div class="d-flex flex-column mr-auto"> <div class="d-flex flex-row"> <div class="mr-3 ml-auto"> <select class="mr-3"> <option>Monthly</option> <option>Quaterly</option> <option>Yearly</option> </select> </div> <div class="mr-3"> <label for="from" class="mr-3"><translate>from</translate></label ><input /> </div> <div class="mr-auto"> <label for="to" class="mr-3"><translate>to</translate></label ><input /> </div> </div> <div class="diagram-container"></div> </div> </div> </div> </template> <style></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): * Thomas Junk <thomas.junk@intevation.de> * Markus Kottländer <markus.kottlaender@intevation.de> */ import * as d3 from "d3"; import app from "@/main"; import { displayError } from "@/lib/errors"; import { HTTP } from "@/lib/http"; const MOCKDATA = `#label,# >= LDC [h],# < 200.00 [h],# >= 200.00 [h],# >= 230.00 [h],# >= 250.00 [h] 01-2019, 22.000,1.000, 4.000,6.000, 20.000 02-2019, 24.000,0.000,0.000,0.000, 23.000 03-2019, 30.000,0.000,0.000,0.000, 30.000 04-2019, 30.000,0.000,0.000,0.000, 30.000 05-2019, 30.000,0.000,0.000,0.000, 30.000`; export default { data() { return { loading: false, fwData: null, width: 1000, height: 600, paddingRight: 100, spaceBetween: 80, labelPaddingTop: 15, scalePaddingLeft: 50, paddingTop: 10, legend: "", diagram: null, yScale: null, barsWidth: 60 }; }, mounted() { this.yScale = d3 .scaleLinear() .domain([-33, 33]) .range([this.height - 30, 0]); this.loadData(); }, computed: { availability() { return this.plainAvailability; } }, methods: { prepareLegend(header) { const headerEntries = header.split(","); headerEntries.shift(); return headerEntries.map(x => { return x.split("#")[1].trim(); }); }, prepare(data) { const csv = data.split("\n"); this.legend = this.prepareLegend(csv.shift()); let transformed = csv.map(e => { const result = e.split(","); const label = result.shift(); const ldc = result.shift(); const highestLevel = result.pop(); return { label: label, ldc: ldc, highestLevel: highestLevel, lowerLevels: result }; }); this.fwData = transformed; }, loadData() { const URL = "/data/bottleneck/fairway-depth/Furt%20Wendeplatz%20Theben?from=2019-01-01T15:04:05%2b00:00&to=2019-05-02T15:04:05%2b07:00&mode=monthly"; HTTP.get(URL, { headers: { "X-Gemma-Auth": localStorage.getItem("token") } }) .then(() => { // const { data } = response; this.prepare(MOCKDATA); this.drawDiagram(); }) .catch(error => { console.log(error); const { status, data } = error.response; displayError({ title: this.$gettext("Backend Error"), message: `${status}: ${data.message || data}` }); }); }, drawDiagram() { d3.select(".diagram-container svg").remove(); this.generateDiagramContainer(); this.drawBars(); this.drawScaleLabel(); this.drawScale(); }, generateDiagramContainer() { const diagram = d3 .select(".diagram-container") .append("svg") .attr("width", this.width) .attr("height", this.height); this.diagram = diagram .append("g") .attr("transform", `translate(0 ${this.paddingTop})`); }, drawBars() { const everyBar = this.diagram .selectAll("g") .data(this.fwData) .enter() .append("g") .attr("transform", (d, i) => { const dx = this.paddingRight + i * this.spaceBetween; return `translate(${dx})`; }); this.drawSingleBars(everyBar); this.drawLabelPerBar(everyBar); }, drawSingleBars(everyBar) { this.drawLDC(everyBar); this.drawHighestLevel(everyBar); this.drawLowerLevels(everyBar); }, drawLowerLevels(everyBar) { everyBar .selectAll("g") .data(d => d.lowerLevels.reverse()) .enter() .append("rect") .attr("y", this.yScale(0)) .attr("height", d => { return this.yScale(0) - this.yScale(d); }) .attr("width", this.barsWidth) .attr("fill", (d, i) => { return this.$options.COLORS.REST[i]; }); }, fnheight(name) { return d => this.yScale(0) - this.yScale(d[name]); }, drawLDC(everyBar) { const height = this.fnheight("ldc"); everyBar .append("rect") .attr("y", this.yScale(0)) .attr("height", height) .attr("width", this.barsWidth) .attr("transform", d => `translate(0 ${-1 * height(d)})`) .attr("fill", this.$options.COLORS.LDC); }, drawHighestLevel(everyBar) { const height = this.fnheight("highestLevel"); everyBar .append("rect") .attr("y", this.yScale(0)) .attr("height", height) .attr("width", this.barsWidth) .attr("transform", d => `translate(0 ${-1 * height(d)})`) .attr("fill", this.$options.COLORS.HIGHEST); }, drawLabelPerBar(everyBar) { everyBar .append("text") .text(d => d.label) .attr("y", this.yScale(0) + this.labelPaddingTop); }, drawScaleLabel() { const center = this.height / 2; this.diagram .append("text") .text(this.$options.LEGEND) .attr("text-anchor", "middle") .attr("x", 0) .attr("y", 0) .attr("dy", "1em") .attr("transform", `translate(0, ${center}), rotate(-90)`); }, drawScale() { const yAxis = d3.axisLeft().scale(this.yScale); this.diagram .append("g") .attr("transform", `translate(${this.scalePaddingLeft})`) .call(yAxis); } }, LEGEND: app.$gettext("sum of days / Summe der Tage"), COLORS: { LDC: "#59C6FF", HIGHEST: "#2D84B3", REST: ["#FF424F", "#FF737C", "#FF99A0"] } }; </script>