Mercurial > gemma
view client/src/components/fairway/AvailableFairwayDepthLNWL.vue @ 3381:540ef09bd6bc
fix linting
author | Thomas Junk <thomas.junk@intevation.de> |
---|---|
date | Wed, 22 May 2019 15:53:05 +0200 |
parents | d83c738e8627 |
children | 0ba142a4bf43 |
line wrap: on
line source
<template> <div class="d-flex flex-column flex-fill"> <UIBoxHeader icon="chart-area" :title="title" :closeCallback="close" /> <UISpinnerOverlay v-if="loading" /> <div class="d-flex flex-fill"> <DiagramLegend> <div v-for="(entry, index) in legendLNWL" :key="index" class="legend"> {{ entry }} </div> <div> <select @change="applyChange" v-model="form.template" class="form-control d-block custom-select-sm w-100 mt-1" > <option v-for="template in templates" :value="template" :key="template.name" > {{ template.name }} </option> </select> <button @click="downloadPDF" type="button" class="btn btn-sm btn-info d-block w-100 mt-1" > <translate>Export to PDF</translate> </button> </div> </DiagramLegend> <div ref="diagramContainer" :id="containerId" class="mx-auto my-auto diagram-container" ></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> * Fadi Abbud <fadi.abbud@intevation.de> */ import * as d3 from "d3"; import app from "@/main"; import debounce from "debounce"; import { diagram } from "@/lib/mixins"; import { mapState } from "vuex"; import filters from "@/lib/filters.js"; import jsPDF from "jspdf"; import canvg from "canvg"; import { pdfgen } from "@/lib/mixins"; import { HTTP } from "@/lib/http"; import { displayError } from "@/lib/errors"; export default { mixins: [diagram, pdfgen], components: { DiagramLegend: () => import("@/components/DiagramLegend") }, data() { return { containerId: "availablefairwaydepthlnwl", loading: false, width: 1000, height: 600, paddingRight: 100, spaceBetween: 80, labelPaddingTop: 15, scalePaddingLeft: 50, paddingTop: 10, diagram: null, yScale: null, barsWidth: 60, dimensions: null, pdf: { doc: null, width: null, height: null }, form: { template: null }, templateData: null, templates: [], defaultTemplate: { name: "Default", properties: { paperSize: "a4" }, elements: [ { type: "diagram", position: "topleft", offset: { x: 20, y: 60 }, width: 290, height: 100 }, { type: "diagramtitle", position: "topleft", offset: { x: 70, y: 20 }, fontsize: 20, color: "steelblue" }, { type: "diagramlegend", position: "topleft", offset: { x: 30, y: 160 }, color: "black" } ] } }; }, created() { window.addEventListener("resize", debounce(this.drawDiagram), 100); }, mounted() { this.drawDiagram(); this.templates[0] = this.defaultTemplate; this.form.template = this.templates[0]; this.templateData = this.form.template; HTTP.get("/templates/diagram", { headers: { "X-Gemma-Auth": localStorage.getItem("token"), "Content-type": "text/xml; charset=UTF-8" } }) .then(response => { if (response.data.length) { this.templates = response.data; this.form.template = this.templates[0]; this.templates[this.templates.length] = this.defaultTemplate; this.applyChange(); } }) .catch(e => { const { status, data } = e.response; displayError({ title: this.$gettext("Backend Error"), message: `${status}: ${data.message || data}` }); }); }, computed: { ...mapState("fairwayavailability", [ "selectedFairwayAvailabilityFeature", "fwLNWLData", "from", "to", "frequency", "legendLNWL" ]), ...mapState("user", ["user"]), fromDate() { return this.from; }, toDate() { return this.to; }, availability() { return this.plainAvailability; }, title() { return `Available Fairway Depth vs LNWL: ${ this.featureName } (${filters.surveyDate(this.fromDate)} - ${filters.surveyDate( this.toDate )}) ${this.$gettext(this.frequency)}`; }, featureName() { return this.selectedFairwayAvailabilityFeature.properties.name; } }, methods: { applyChange() { if (this.form.template.hasOwnProperty("properties")) { this.templateData = this.defaultTemplate; return; } if (this.form.template) { HTTP.get("/templates/diagram/" + this.form.template.name, { headers: { "X-Gemma-Auth": localStorage.getItem("token"), "Content-type": "text/xml; charset=UTF-8" } }) .then(response => { this.templateData = response.data.template_data; }) .catch(e => { const { status, data } = e.response; displayError({ title: this.$gettext("Backend Error"), message: `${status}: ${data.message || data}` }); }); } }, downloadPDF() { this.pdf.doc = new jsPDF( "l", "mm", this.templateData.properties.paperSize ); // pdf width and height in millimeter (landscape) this.pdf.width = this.templateData.properties.paperSize === "a3" ? 420 : 297; this.pdf.height = this.templateData.properties.paperSize === "a3" ? 297 : 210; if (this.templateData) { // default values if some are missing in template let defaultFontSize = 11, defaultColor = "black", defaultWidth = 70, defaultTextColor = "black", defaultBorderColor = "white", defaultBgColor = "white", defaultRounding = 2, defaultPadding = 2, defaultOffset = { x: 0, y: 0 }; this.templateData.elements.forEach(e => { switch (e.type) { case "diagram": { this.addDiagram( e.position, e.offset || defaultOffset, e.width, e.height ); break; } case "diagramtitle": { let title = `Available Fairway Depth vs LNWL: ${ this.featureName }`; this.addDiagramTitle( e.position, e.offset || defaultOffset, e.fontsize || defaultFontSize, e.color || defaultColor, title ); break; } case "diagramlegend": { this.addDiagramLegend( e.position, e.offset || defaultOffset, e.color || defaultColor ); break; } case "text": { this.addText( e.position, e.offset || defaultOffset, e.width || defaultWidth, e.fontsize || defaultFontSize, e.color || defaultTextColor, e.text ); break; } case "image": { this.addImage( e.url, e.format, e.position, e.offset || defaultOffset, e.width, e.height ); break; } case "box": { this.addBox( e.position, e.offset, e.width, e.height, e.rounding === 0 || e.rounding ? e.rounding : defaultRounding, e.color || defaultBgColor, e.brcolor || defaultBorderColor ); break; } case "textbox": { this.addTextBox( e.position, e.offset || defaultOffset, e.width, e.height, e.rounding === 0 || e.rounding ? e.rounding : defaultRounding, e.padding || defaultPadding, e.fontsize || defaultFontSize, e.color || defaultTextColor, e.background || defaultBgColor, e.text, e.brcolor || defaultBorderColor ); break; } } }); } this.pdf.doc.save(`Available Fairway Depth LNWL: ${this.featureName}`); }, addDiagram(position, offset, width, height) { let x = offset.x, y = offset.y; var svg = this.$refs.diagramContainer.innerHTML; if (svg) { svg = svg.replace(/\r?\n|\r/g, "").trim(); } if (!width) { width = this.templateData.properties.paperSize === "a3" ? 380 : 290; } if (!height) { height = this.templateData.properties.paperSize === "a3" ? 130 : 100; } if (["topright", "bottomright"].indexOf(position) !== -1) { x = this.pdf.width - offset.x - width; } if (["bottomright", "bottomleft"].indexOf(position) !== -1) { y = this.pdf.height - offset.y - height; } var canvas = document.createElement("canvas"); canvas.width = window.innerWidth; canvas.height = window.innerHeight / 2; canvg(canvas, svg, { ignoreMouse: true, ignoreAnimation: true, ignoreDimensions: true }); var imgData = canvas.toDataURL("image/png"); this.pdf.doc.addImage(imgData, "PNG", x, y, width, height); }, addDiagramLegend(position, offset, color) { let x = offset.x, y = offset.y; this.pdf.doc.setFontSize(10); let width = (this.pdf.doc.getStringUnitWidth(">= LDC [h]") * 10) / (72 / 25.6) + 15; // if position is on the right, x needs to be calculate with pdf width and // the size of the element if (["topright", "bottomright"].indexOf(position) !== -1) { x = this.pdf.width - offset.x - width; } if (["bottomright", "bottomleft"].indexOf(position) !== -1) { y = this.pdf.height - offset.y - this.getTextHeight(7); } this.pdf.doc.setTextColor(color); this.pdf.doc.setDrawColor("rgb(255, 133, 94)"); this.pdf.doc.setFillColor("rgb(255, 133, 94)"); this.pdf.doc.rect(x, y, 8, 4, "FD"); this.pdf.doc.text(">= LDC [h]", x + 10, y + 3); this.pdf.doc.setDrawColor("rgb(255, 66, 79)"); this.pdf.doc.setFillColor("rgb(255, 66, 79)"); this.pdf.doc.rect(x, y + 5, 8, 4, "FD"); this.pdf.doc.text("< 200.00 [h]", x + 10, y + 8); this.pdf.doc.setDrawColor("rgb(255, 115, 124)"); this.pdf.doc.setFillColor("rgb(255, 115, 124)"); this.pdf.doc.rect(x, y + 10, 8, 4, "FD"); this.pdf.doc.text(">= 200.00 [h]", x + 10, y + 13); this.pdf.doc.setDrawColor("rgb(255, 153, 160)"); this.pdf.doc.setFillColor("rgb(255, 153, 160)"); this.pdf.doc.rect(x, y + 15, 8, 4, "FD"); this.pdf.doc.text(">= 230.00 [h]", x + 10, y + 18); this.pdf.doc.setDrawColor("rgb(45, 132, 179)"); this.pdf.doc.setFillColor("rgb(45, 132, 179)"); this.pdf.doc.rect(x, y + 20, 8, 4, "FD"); this.pdf.doc.text(">= 250.00 [h]", x + 10, y + 23); }, close() { this.$store.commit("application/paneSetup", "DEFAULT"); }, drawDiagram() { this.dimensions = this.getDimensions({ main: { top: 20, right: 20, bottom: 110, left: 200 } }); this.yScale = d3 .scaleLinear() .domain([0, 100]) .range([this.dimensions.mainHeight - 30, 0]); d3.select(".diagram-container svg").remove(); this.generateDiagramContainer(); this.drawBars(); this.drawScaleLabel(); this.drawScale(); this.drawTooltip(); }, drawTooltip() { this.diagram .append("text") .text("banane") .attr("font-size", "0.8em") .attr("opacity", 0) .attr("id", "tooltip"); }, generateDiagramContainer() { const diagram = d3 .select(".diagram-container") .append("svg") .attr("width", this.dimensions.width) .attr("height", this.dimensions.mainHeight); this.diagram = diagram .append("g") .attr("transform", `translate(0 ${this.paddingTop})`); }, drawBars() { this.drawLNWL(); this.drawAFD(); }, drawAFD() { let afd = this.diagram .append("g") .attr("transform", `translate(${this.paddingRight + this.barsWidth})`); afd .selectAll("rect") .data(this.fwLNWLData.afd) .enter() .append("rect") .on("mouseover", function() { d3.select(this).attr("opacity", "0.8"); d3.select("#tooltip").attr("opacity", 1); }) .on("mouseout", function() { d3.select(this).attr("opacity", 1); d3.select("#tooltip").attr("opacity", 0); }) .on("mousemove", function(d) { let y = d3.mouse(this)[1]; const dy = document .querySelector(".diagram-container") .getBoundingClientRect().left; const value = d.percent; d3.select("#tooltip") .text(value) .attr("y", y - 10) .attr("x", d3.event.pageX - dy); //d3.event.pageX gives coordinates relative to SVG //dy gives offset of svg on page }) .attr("height", d => { return this.yScale(0) - this.yScale(d.percent); }) .attr("y", d => { return this.yScale(d.translateY); }) .attr("width", this.barsWidth) .attr("fill", (d, i) => { return this.$options.AFDCOLORS[i]; }); }, drawLNWL() { let lnwl = this.diagram .append("g") .attr("transform", `translate(${this.paddingRight})`); lnwl .selectAll("rect") .data(this.fwLNWLData.lnwl) .enter() .append("rect") .on("mouseover", function() { d3.select(this).attr("opacity", "0.8"); d3.select("#tooltip").attr("opacity", 1); }) .on("mouseout", function() { d3.select(this).attr("opacity", 1); d3.select("#tooltip").attr("opacity", 0); }) .on("mousemove", function(d) { let y = d3.mouse(this)[1]; const dy = document .querySelector(".diagram-container") .getBoundingClientRect().left; const value = d.percent; d3.select("#tooltip") .text(value) .attr("y", y - 10) .attr("x", d3.event.pageX - dy); //d3.event.pageX gives coordinates relative to SVG //dy gives offset of svg on page }) .attr("height", d => { return this.yScale(0) - this.yScale(d.percent); }) .attr("y", d => { return this.yScale(d.translateY); }) .attr("width", this.barsWidth) .attr("fill", d => { return this.$options.LWNLCOLORS[d.level]; }); }, drawScaleLabel() { const center = this.dimensions.mainHeight / 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) .selectAll(".tick text") .attr("fill", "black") .select(function() { return this.parentNode; }) .selectAll(".tick line") .attr("stroke", "black"); this.diagram.selectAll(".domain").attr("stroke", "black"); } }, watch: { fwLNWLData() { this.drawDiagram(); } }, LEGEND: app.$gettext("Percent"), AFDCOLORS: ["#782121", "#ff6c6c", "#3675ff"], LWNLCOLORS: { LDC: "#aaaaaa", HDC: "#ff6600" } }; </script>