view client/src/lib/mixins.js @ 3862:ecf2e5ea1464

Backed out changeset 55e503270f38
author Thomas Junk <thomas.junk@intevation.de>
date Tue, 09 Jul 2019 15:37:42 +0200
parents 55e503270f38
children 7db6999962db
line wrap: on
line source

/* 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, 2019 by via donau
 *   – Österreichische Wasserstraßen-Gesellschaft mbH
 * Software engineering by Intevation GmbH
 *
 * Author(s):
 * * Markus Kottländer <markus.kottlaender@intevation.de>
 * * Fadi Abbud <fadi.abbud@intevation.de>
 * * Bernhard Reiter <bernhard.reiter@intevation.de>
 */
import jsPDF from "jspdf-yworks";
import locale2 from "locale2";
import { mapState } from "vuex";
import { HTTP } from "@/lib/http";

export const sortTable = {
  data() {
    return {
      sortColumn: "",
      sortDirection: "ASC",
      pageSize: 20,
      page: 1
    };
  },
  methods: {
    sortTable(sorting) {
      this.sortColumn = sorting.sortColumn;
      this.sortDirection = sorting.sortDirection;
    }
  }
};

export const diagram = {
  methods: {
    getDimensions({ main, nav }) {
      //dimensions and margins
      const elem = document.querySelector("#" + this.containerId);
      const svgWidth = elem != null ? elem.clientWidth : 0;
      const svgHeight = elem != null ? elem.clientHeight : 0;
      const mainMargin = main || { top: 20, right: 20, bottom: 110, left: 80 };
      const navMargin = nav || {
        top: svgHeight - mainMargin.top - 65,
        right: 20,
        bottom: 30,
        left: 80
      };
      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 };
    }
  }
};

export const pane = {
  computed: {
    paneId() {
      return this.$parent.pane.id;
    }
  }
};

export const templateLoader = {
  methods: {
    loadTemplates(url) {
      return new Promise((resolve, reject) => {
        HTTP.get(url, {
          headers: {
            "X-Gemma-Auth": localStorage.getItem("token"),
            "Content-type": "text/xml; charset=UTF-8"
          }
        })
          .then(response => {
            resolve(response);
          })
          .catch(error => {
            reject(error);
          });
      });
    },
    prepareImages(elements) {
      /**
       * In order to render the images from the template, we need to convert
       * each image to dataURIs. Since this happens asynchronous,
       * we need to wrap each image into its own promise and only after all are
       * finished, we continue with the flow.
       */
      return new Promise(resolve => {
        const imageElementLoaders = elements.reduce((o, n, i) => {
          if (n.type === "image") {
            o.push(
              new Promise(resolve => {
                const image = new Image();
                image.onload = function() {
                  var canvas = document.createElement("canvas");
                  canvas.width = this.naturalWidth; // or 'width' if you want a special/scaled size
                  canvas.height = this.naturalHeight; // or 'height' if you want a special/scaled size
                  canvas.getContext("2d").drawImage(this, 0, 0);
                  resolve({
                    index: i,
                    url: canvas.toDataURL("image/png")
                  });
                };
                image.src = n.url;
              })
            );
          }
          return o;
        }, []);
        Promise.all(imageElementLoaders).then(values => {
          resolve(values);
        });
      });
    }
  }
};

export const pdfgen = {
  computed: {
    ...mapState("application", ["logoForPDF"]),
    ...mapState("user", ["user"])
  },
  methods: {
    gaugeInfo(selectedGauge) {
      // returns string with formatted gauge info
      return (
        selectedGauge.properties.objname +
        " (" +
        selectedGauge.id
          .split(".")[1]
          .replace(/[()]/g, "")
          .split(",")[3] +
        ")"
      );
    },
    generatePDF(params) {
      // creates a new jsPDF object into this.pdf.doc
      // will call functions that the calling context has to provide
      // as specified in the templateData
      let templateData = params["templateData"];
      let diagramTitle = params["diagramTitle"];

      this.pdf.doc = new jsPDF("l", "mm", templateData.properties.paperSize);
      // pdf width and height in millimeter (landscape)
      if (templateData.properties.paperSize === "a3") {
        this.pdf.width = 420;
        this.pdf.height = 297;
      } else {
        this.pdf.width = 297;
        this.pdf.height = 210;
      }
      // check the template elements
      if (templateData) {
        this.pdf.doc.setFont("linbiolinum", "normal");
        let defaultFontSize = 11,
          defaultColor = "black",
          defaultWidth = 70,
          defaultTextColor = "black",
          defaultBorderColor = "white",
          defaultBgColor = "white",
          defaultRounding = 2,
          defaultPadding = 2,
          defaultOffset = { x: 0, y: 0 };
        templateData.elements.forEach(e => {
          switch (e.type) {
            case "diagram": {
              this.addDiagram(
                e.position,
                e.offset || defaultOffset,
                e.width || 200,
                e.height || 100
              );
              break;
            }
            case "diagramlegend": {
              this.addDiagramLegend(
                e.position,
                e.offset || defaultOffset,
                e.color || defaultColor
              );
              break;
            }
            case "diagramtitle": {
              this.addDiagramTitle(
                e.position,
                e.offset || defaultOffset,
                e.fontsize || defaultFontSize,
                e.color || defaultColor,
                diagramTitle
              );
              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 || 90,
                e.height || 60
              );
              break;
            }
            case "box": {
              this.addBox(
                e.position,
                e.offset || defaultOffset,
                e.width || 90,
                e.height || 60,
                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;
            }
          }
        });
      }
    },
    // add text at specific coordinates and do line breaks
    addText(position, offset, width, fontSize, color, text) {
      text = this.replacePlaceholders(text);
      // split the incoming string to an array, each element is a string of
      // words in a single line
      this.pdf.doc.setFontStyle("normal");
      this.pdf.doc.setTextColor(color);
      this.pdf.doc.setFontSize(fontSize);
      var textLines = this.pdf.doc.splitTextToSize(text, width);
      // x/y defaults to offset for topleft corner (normal x/y coordinates)
      let x = offset.x;
      let y = offset.y;
      // 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(textLines.length);
      }
      this.pdf.doc.text(textLines, x, y, { baseline: "hanging" });
    },
    replacePlaceholders(text) {
      if (text.includes("{date}")) {
        text = text.replace("{date}", new Date().toLocaleString(locale2));
      }
      // get only day,month and year from the Date object
      if (text.includes("{date-minor}")) {
        var date = new Date();
        var dt =
          (date.getDate() < 10 ? "0" : "") +
          date.getDate() +
          "." +
          (date.getMonth() + 1 < 10 ? "0" : "") +
          (date.getMonth() + 1) +
          "." +
          date.getFullYear();
        text = text.replace("{date-minor}", dt.toLocaleString(locale2));
      }
      if (text.includes("{user}")) {
        text = text.replace("{user}", this.user);
      }
      return text;
    },
    addImage(url, format, position, offset, width, height) {
      let x = offset.x;
      let y = offset.y;
      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;
      }
      let image = new Image();
      if (url) {
        image.src = url;
      } else {
        if (this.logoForPDF) {
          image.src = this.logoForPDF;
        } else {
          image.src = "/img/gemma-logo-for-pdf.png";
        }
      }
      if (format === "") {
        let tmp = image.src.split(".");
        format = tmp[tmp.length - 1].toUpperCase();
      }
      this.pdf.doc.addImage(image, format, x, y, width, height);
    },
    // add text at specific coordinates with a background box
    addBox(position, offset, width, height, rounding, color, brcolor) {
      // x/y defaults to offset for topleft corner (normal x/y coordinates)
      let x = offset.x;
      let y = offset.y;

      // 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 - height;
      }
      this.addRoundedBox(x, y, width, height, color, rounding, brcolor);
    },
    getTextHeight(numberOfLines) {
      // Return estimated height in mm.

      // FontSize is given in desktop publishing points defined as 1/72 inch.
      // aka 25.4 / 72 mm
      let fontSize = this.pdf.doc.getFontSize();
      let lineHeightFactor = 1.15; // default from jspdf-yworks 2.0.2
      if (typeof this.pdf.doc.getLineHeightFactor !== "undefined") {
        lineHeightFactor = this.pdf.doc.getLineHeightFactor();
      }
      return numberOfLines * fontSize * (25.4 / 72) * lineHeightFactor;
    },
    // title for diagram
    addDiagramTitle(position, offset, size, color, text) {
      let x = offset.x,
        y = offset.y;
      this.pdf.doc.setFontSize(size);
      this.pdf.doc.setFontStyle("bold");
      this.pdf.doc.setTextColor(color);
      let width =
        (this.pdf.doc.getStringUnitWidth(text) * 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.text(text, x, y, { baseline: "hanging" });
    },
    addRoundedBox(x, y, w, h, color, rounding, brcolor) {
      this.pdf.doc.setDrawColor(brcolor);
      this.pdf.doc.setFillColor(color);
      this.pdf.doc.roundedRect(x, y, w, h, rounding, rounding, "FD");
    },
    addTextBox(
      position,
      offset,
      width,
      height,
      rounding,
      padding,
      fontSize,
      color,
      background,
      text,
      brcolor
    ) {
      this.pdf.doc.setFontSize(fontSize);
      text = this.replacePlaceholders(text);

      if (!width) {
        width = this.pdf.doc.getTextWidth(text) + 2 * padding;
      }
      let textWidth = width - 2 * padding;
      if (!height) {
        let textLines = this.pdf.doc.splitTextToSize(text, textWidth);
        height = this.getTextHeight(textLines.length) + 2 * padding;
      }
      this.addBox(
        position,
        offset,
        width,
        height,
        rounding,
        background,
        brcolor
      );
      this.addText(
        position,
        { x: offset.x + padding, y: offset.y + padding },
        textWidth,
        fontSize,
        color,
        text
      );
    }
  }
};