Mercurial > gemma
changeset 3267:b07b4cca5e34
client: diagram-template: implement pdf-template for fairway availability diagram
* implement default template
* add some template elements
* fit d3-styles to get renderd on pdf
author | Fadi Abbud <fadi.abbud@intevation.de> |
---|---|
date | Wed, 15 May 2019 13:18:33 +0200 |
parents | 3dee5cf16a58 |
children | 1a97a079ef1b |
files | client/src/components/fairway/AvailableFairwayDepth.vue |
diffstat | 1 files changed, 210 insertions(+), 5 deletions(-) [+] |
line wrap: on
line diff
--- a/client/src/components/fairway/AvailableFairwayDepth.vue Wed May 15 13:05:19 2019 +0200 +++ b/client/src/components/fairway/AvailableFairwayDepth.vue Wed May 15 13:18:33 2019 +0200 @@ -14,8 +14,33 @@ {{ entry }} </li> </ul> + <div class="my-auto mx-auto"> + <select + 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> </div> - <div :id="containerId" class="mx-auto my-auto diagram-container"></div> + <div + ref="diagramContainer" + :id="containerId" + class="mx-auto my-auto diagram-container" + ></div> </div> </div> </template> @@ -43,11 +68,14 @@ 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"; const hoursInDays = x => x / 24; export default { - mixins: [diagram], + mixins: [diagram, pdfgen], data() { return { containerId: "availablefairwaydepth", @@ -62,7 +90,45 @@ diagram: null, yScale: null, barsWidth: 60, - dimensions: null + dimensions: null, + pdf: { + doc: null, + width: null, + height: null + }, + form: { + template: null + }, + templateData: null, + templates: [], + defaultemplate: { + 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: 20, y: 20 }, + fontsize: 20, + color: "steelblue" + }, + { + type: "diagramlegend", + position: "topleft", + offset: { x: 30, y: 160 }, + color: "black" + } + ] + } }; }, created() { @@ -70,6 +136,9 @@ }, mounted() { this.drawDiagram(); + this.templates[0] = this.defaultemplate; + this.form.template = this.templates[0]; + this.templateData = this.templates[0]; }, computed: { ...mapState("fairwayavailability", [ @@ -94,13 +163,141 @@ this.featureName } (${filters.surveyDate(this.fromDate)} - ${filters.surveyDate( this.toDate - )}) ${this.$gettext(this.frequency)}`; + )}) ${this.$gettext(this.fre40quency)}`; }, featureName() { return this.selectedFairwayAvailabilityFeature.properties.name; } }, methods: { + 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) { + let defaultOffset = { x: 0, y: 0 }, + defaultFontSize = 10, + defaultColor = "black"; + this.templateData.elements.forEach(e => { + switch (e.type) { + case "diagram": { + this.addDiagram( + e.position, + e.offset || defaultOffset, + e.width, + e.height + ); + break; + } + case "diagramtitle": { + this.addDiagramTitle( + e.position, + e.offset || defaultOffset, + e.fontsize || defaultFontSize, + e.color || defaultColor + ); + break; + } + case "diagramlegend": { + this.addDiagramLegend( + e.position, + e.offset || defaultOffset, + e.color || defaultColor + ); + } + } + }); + } + this.pdf.doc.save(`Available Fairway Depth: ${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); + }, + addDiagramTitle(position, offset, size, color) { + let x = offset.x, + y = offset.y; + let title = this.title; + let width = + (this.pdf.doc.getStringUnitWidth(title) * size) / (72 / 25.6) + + size / 2; + // 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(1); + } + this.pdf.doc.setTextColor(color); + this.pdf.doc.setFontSize(size); + this.pdf.doc.setFontStyle("bold"); + this.pdf.doc.text(title, x, y, { baseline: "hanging" }); + }, + addDiagramLegend(position, offset, color) { + let x = offset.x, + y = offset.y; + + this.pdf.doc.setFontSize(10); + 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); + }, legendStyle(index) { if (index == 0) return `background-color: ${this.$options.COLORS.LDC};`; if (index < 4) @@ -213,7 +410,15 @@ this.diagram .append("g") .attr("transform", `translate(${this.scalePaddingLeft})`) - .call(yAxis); + .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"); } }, LEGEND: app.$gettext("Sum of days"),