changeset 3197:9d38df37c1f8

client: implemnt pdf-template for hydrologicalconditions diagram
author Fadi Abbud <fadi.abbud@intevation.de>
date Wed, 08 May 2019 15:08:27 +0200
parents 0d76a0476a5b
children b0328646e34f
files client/src/components/gauge/HydrologicalConditions.vue
diffstat 1 files changed, 284 insertions(+), 33 deletions(-) [+]
line wrap: on
line diff
--- a/client/src/components/gauge/HydrologicalConditions.vue	Wed May 08 14:35:40 2019 +0200
+++ b/client/src/components/gauge/HydrologicalConditions.vue	Wed May 08 15:08:27 2019 +0200
@@ -25,6 +25,19 @@
           <span style="background-color: lightsteelblue"></span>
           Long-term Amplitude
         </div>
+        <select
+          @change="applyChange"
+          v-model="form.template"
+          class="form-control d-block custom-select-sm w-100"
+        >
+          <option
+            v-for="template in templates"
+            :value="template"
+            :key="template.name"
+          >
+            {{ template.name }}
+          </option>
+        </select>
         <div>
           <button
             @click="downloadPDF"
@@ -69,8 +82,12 @@
 import { startOfYear, endOfYear } from "date-fns";
 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: [pdfgen],
   components: {
     DiagramLegend: () => import("@/components/DiagramLegend")
   },
@@ -83,7 +100,47 @@
       dimensions: null,
       extent: null,
       scale: null,
-      axes: null
+      axes: null,
+      templateData: null,
+      form: {
+        template: null,
+        form: null
+      },
+      templates: [],
+      defaultTemplate: {
+        name: "Default",
+        properties: {
+          paperSize: "a4",
+          resolution: 80
+        },
+        elements: [
+          {
+            type: "diagram",
+            position: "topleft",
+            offset: { x: 15, y: 50 },
+            width: 290,
+            height: 100
+          },
+          {
+            type: "diagramlegend",
+            position: "topleft",
+            offset: { x: 30, y: 150 },
+            colot: "black"
+          },
+          {
+            type: "diagramtitle",
+            position: "topleft",
+            offset: { x: 50, y: 26 },
+            fontsize: 22,
+            color: "steelblue"
+          }
+        ]
+      },
+      pdf: {
+        doc: null,
+        width: 420,
+        height: 297
+      }
     };
   },
   computed: {
@@ -122,11 +179,115 @@
       );
     },
     downloadPDF() {
+      if (this.templateData) {
+        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;
+        // 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": {
+              this.addDiagramTitle(e.position, e.offset, e.fontsize, e.color);
+              break;
+            }
+            case "diagramlegend": {
+              this.addDiagramLegend(
+                e.position,
+                e.offset || defaultOffset,
+                e.color || defaultColor
+              );
+              break;
+            }
+            case "image": {
+              this.addImage(
+                e.url,
+                e.format,
+                e.position,
+                e.offset || defaultOffset,
+                e.width,
+                e.height
+              );
+              break;
+            }
+            case "text": {
+              this.addText(
+                e.position,
+                e.offset || defaultOffset,
+                e.width || defaultWidth,
+                e.fontSize || defaultFontSize,
+                e.color || defaultTextColor,
+                e.text
+              );
+              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(
+        this.selectedGauge.properties.objname +
+          " Hydrological-condition Diagram.pdf"
+      );
+    },
+    addDiagram(position, offset, width, height) {
+      let x = offset.x,
+        y = offset.y;
       var svg = document.getElementById(this.containerId).innerHTML;
       if (svg) {
         svg = svg.replace(/\r?\n|\r/g, "").trim();
       }
-      var pdf = new jsPDF("l", "mm", "a3");
       var canvas = document.createElement("canvas");
       canvas.width = window.innerWidth;
       canvas.height = window.innerHeight / 2;
@@ -136,16 +297,50 @@
         ignoreDimensions: true
       });
       var imgData = canvas.toDataURL("image/png");
-      pdf.addImage(imgData, "PNG", 40, 60, 380, 130);
-      this.addDiagramTitle(pdf, 108, 30, 22, "steelblue");
-      this.addDiagramLegend(pdf, 60, 190, "black");
-      pdf.save(
-        this.selectedGauge.properties.objname +
-          " Hydrological-condition Diagram.pdf"
-      );
+      // landscape format is used for both a3,a4 papersize
+      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;
+      }
+      this.pdf.doc.addImage(imgData, "PNG", x, y, width, height);
+    },
+    applyChange() {
+      if (this.form.template.hasOwnProperty("properties")) {
+        this.templateData = this.defaultTemplate;
+        return;
+      }
+      if (this.form.template) {
+        HTTP.get("/templates/print/" + 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;
+            this.form.paperSize = this.templateData.properties.paperSize;
+          })
+          .catch(e => {
+            const { status, data } = e.response;
+            displayError({
+              title: this.$gettext("Backend Error"),
+              message: `${status}: ${data.message || data}`
+            });
+          });
+      }
     },
     // Gauge info as title
-    addDiagramTitle(pdf, x, y, size, color) {
+    addDiagramTitle(position, offset, size, color) {
+      let x = offset.x,
+        y = offset.y;
       let gaugeInfo =
         this.selectedGauge.properties.objname +
         " (" +
@@ -155,31 +350,63 @@
           .split(",")[3] +
         "): Hydrological Conditions " +
         this.longtermInterval.join(" - ");
-      pdf.setTextColor(color);
-      pdf.setFontSize(22);
-      pdf.setFontStyle("bold");
-      pdf.text(gaugeInfo, 108, 30);
+      let width =
+        (this.pdf.doc.getStringUnitWidth(gaugeInfo) * 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(gaugeInfo, x, y, { baseline: "hanging" });
+    },
+    getTextHeight(numberOfLines) {
+      return (
+        numberOfLines *
+        ((this.pdf.doc.getFontSize() * 25.4) / 80) *
+        this.pdf.doc.getLineHeightFactor()
+      );
     },
     // Diagram legend
-    addDiagramLegend(pdf, x, y, color) {
-      pdf.setFontSize(10);
-      pdf.setTextColor(color);
-      pdf.setDrawColor("white");
-      pdf.setFillColor("red");
-      pdf.circle(x, y, 2, "FD");
-      pdf.text(x + 3, y + 1, "" + this.yearCompare);
-      pdf.setFillColor("orange");
-      pdf.circle(x, y + 5, 2, "FD");
-      pdf.text(x + 3, y + 6, "Q25%");
-      pdf.setFillColor("black");
-      pdf.circle(x, y + 10, 2, "FD");
-      pdf.text(x + 3, y + 11, "Median ");
-      pdf.setFillColor("purple");
-      pdf.circle(x, y + 15, 2, "FD");
-      pdf.text(x + 3, y + 16, "Q75%");
-      pdf.setFillColor("lightsteelblue");
-      pdf.circle(x, y + 20, 2, "FD");
-      pdf.text(x + 3, y + 21, "Long-term Amplitude");
+    addDiagramLegend(position, offset, color) {
+      let x = offset.x,
+        y = offset.y;
+      let width =
+        (this.pdf.doc.getStringUnitWidth("Long-term Amplitude") * 10) /
+          (72 / 25.6) +
+        5;
+      // 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(4);
+      }
+      this.pdf.doc.setFontSize(10);
+      this.pdf.doc.setTextColor(color);
+      this.pdf.doc.setDrawColor("white");
+      this.pdf.doc.setFillColor("red");
+      this.pdf.doc.circle(x, y, 2, "FD");
+      this.pdf.doc.text(x + 3, y + 1, "" + this.yearCompare);
+      this.pdf.doc.setFillColor("orange");
+      this.pdf.doc.circle(x, y + 5, 2, "FD");
+      this.pdf.doc.text(x + 3, y + 6, "Q25%");
+      this.pdf.doc.setFillColor("black");
+      this.pdf.doc.circle(x, y + 10, 2, "FD");
+      this.pdf.doc.text(x + 3, y + 11, "Median ");
+      this.pdf.doc.setFillColor("purple");
+      this.pdf.doc.circle(x, y + 15, 2, "FD");
+      this.pdf.doc.text(x + 3, y + 16, "Q75%");
+      this.pdf.doc.setFillColor("lightsteelblue");
+      this.pdf.doc.circle(x, y + 20, 2, "FD");
+      this.pdf.doc.text(x + 3, y + 21, "Long-term Amplitude");
     },
     drawDiagram() {
       // remove old diagram
@@ -847,6 +1074,30 @@
   },
   mounted() {
     this.drawDiagram();
+    this.templates[0] = this.defaultTemplate;
+    this.form.template = this.templates[0];
+    this.templateData = this.form.template;
+    HTTP.get("/templates/print", {
+      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}`
+        });
+      });
   },
   updated() {
     this.drawDiagram();