diff client/src/lib/mixins.js @ 3963:feb53713bc2f diagram-cleanup

client: moved duplicated code to mixins and unified code patterns in diagram components [WIP]
author Markus Kottlaender <markus@intevation.de>
date Fri, 12 Jul 2019 15:14:16 +0200
parents 3c468ed76daf
children afc7bca44df4
line wrap: on
line diff
--- a/client/src/lib/mixins.js	Fri Jul 12 11:58:20 2019 +0200
+++ b/client/src/lib/mixins.js	Fri Jul 12 15:14:16 2019 +0200
@@ -16,8 +16,11 @@
 import jsPDF from "jspdf-yworks";
 import svg2pdf from "svg2pdf.js";
 import locale2 from "locale2";
+import debounce from "debounce";
 import { mapState } from "vuex";
 import { HTTP } from "@/lib/http";
+import { displayError } from "@/lib/errors";
+import { defaultDiagramTemplate } from "@/lib/DefaultDiagramTemplate";
 
 export const sortTable = {
   data() {
@@ -37,25 +40,55 @@
 };
 
 export const diagram = {
+  data() {
+    return {
+      resizeListenerFunction: null
+    };
+  },
   methods: {
-    getDimensions({ svgWidth, svgHeight, main, nav }) {
-      const mainMargin = main || {
+    getDimensions({ svgWidth, svgHeight, main, nav, DPI }) {
+      const mainMargin = {
         top: 20,
         right: 80,
         bottom: 60,
-        left: 80
+        left: 80,
+        ...main
       };
-      const navMargin = nav || {
+      const navMargin = {
         top: svgHeight - mainMargin.top - 65,
         right: 20,
         bottom: 30,
-        left: 80
+        left: 80,
+        ...nav
       };
+      if (DPI) {
+        ["top", "right", "bottom", "left"].forEach(x => {
+          mainMargin[x] = this.millimeter2pixels(mainMargin[x], DPI);
+          navMargin[x] = this.millimeter2pixels(navMargin[x], DPI);
+        });
+      }
       const width = Number(svgWidth) - mainMargin.left - mainMargin.right;
       const mainHeight = Number(svgHeight) - mainMargin.top - mainMargin.bottom;
       const navHeight = Number(svgHeight) - navMargin.top - navMargin.bottom;
       return { width, mainHeight, navHeight, mainMargin, navMargin };
     }
+  },
+  created() {
+    this.resizeListenerFunction = debounce(this.drawDiagram, 100);
+    window.addEventListener("resize", this.resizeListenerFunction);
+  },
+  mounted() {
+    // Nasty but necessary if we don't want to use the updated hook to re-draw
+    // the diagram because this would re-draw it also for irrelevant reasons.
+    // In this case we need to wait for the child component (DiagramLegend) to
+    // render. According to the docs (https://vuejs.org/v2/api/#mounted) this
+    // should be possible with $nextTick() but it doesn't work because it does
+    // not guarantee that the DOM is not only updated but also re-painted on the
+    // screen.
+    setTimeout(this.drawDiagram, 150);
+  },
+  destroyed() {
+    window.removeEventListener("resize", this.resizeListenerFunction);
   }
 };
 
@@ -129,6 +162,21 @@
 };
 
 export const pdfgen = {
+  data() {
+    return {
+      pdf: {
+        doc: null,
+        width: null,
+        height: null
+      },
+      templates: [],
+      defaultTemplate: defaultDiagramTemplate,
+      templateData: null,
+      form: {
+        template: null
+      }
+    };
+  },
   computed: {
     ...mapState("application", ["logoForPDF"]),
     ...mapState("user", ["user"])
@@ -137,8 +185,9 @@
     addDiagram(position, offset, width, height) {
       let x = offset.x,
         y = offset.y;
-      const svgWidth = this.millimeter2pixels(width, 80);
-      const svgHeight = this.millimeter2pixels(height, 80);
+      const DPI = this.templateData.properties.resoltion || 80;
+      const svgWidth = this.millimeter2pixels(width, DPI);
+      const svgHeight = this.millimeter2pixels(height, DPI);
       // draw the diagram in a separated html element to get the full size
       const offScreen = document.querySelector("#offScreen");
       offScreen.style.width = `${svgWidth}px`;
@@ -149,7 +198,8 @@
         dimensions: this.getDimensions({
           svgWidth: svgWidth,
           svgHeight: svgHeight,
-          ...layout
+          ...layout,
+          DPI: DPI
         })
       });
       var svg = offScreen.querySelector("svg");
@@ -162,7 +212,7 @@
       svg2pdf(svg, this.pdf.doc, {
         xOffset: x,
         yOffset: y,
-        scale: 0.354
+        scale: this.pixel2millimeter(1, DPI)
       });
       offScreen.removeChild(svg);
     },
@@ -468,6 +518,58 @@
         color,
         text
       );
+    },
+    applyChange() {
+      if (this.form.template.hasOwnProperty("properties")) {
+        this.templateData = this.defaultTemplate;
+        return;
+      }
+      if (this.form.template) {
+        this.loadTemplates("/templates/diagram/" + this.form.template.name)
+          .then(response => {
+            this.prepareImages(response.data.template_data.elements).then(
+              values => {
+                values.forEach(v => {
+                  response.data.template_data.elements[v.index].url = v.url;
+                });
+                this.templateData = response.data.template_data;
+              }
+            );
+          })
+          .catch(e => {
+            const { status, data } = e.response;
+            displayError({
+              title: this.$gettext("Backend Error"),
+              message: `${status}: ${data.message || data}`
+            });
+          });
+      }
     }
+  },
+  mounted() {
+    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}`
+        });
+      });
   }
 };