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"),