Mercurial > gemma
view client/src/components/Pdftool.vue @ 1876:e53924abb4a2 dev-pdf-generation
client: export some elements to pdf
* render north arrow, scale bar and text on pdf
author | Fadi Abbud <fadi.abbud@intevation.de> |
---|---|
date | Wed, 09 Jan 2019 15:59:33 +0100 |
parents | bad32adafef2 |
children | f030182f82f1 |
line wrap: on
line source
<template> <div :class="[ 'box ui-element rounded bg-white text-nowrap', { expanded: showPdfTool } ]" > <div style="width: 20rem"> <h6 class="mb-0 py-2 px-3 border-bottom d-flex align-items-center"> <font-awesome-icon icon="file-pdf" class="mr-2"></font-awesome-icon> <translate>Generate PDF</translate> <font-awesome-icon icon="times" class="ml-auto text-muted" @click="$store.commit('application/showPdfTool', false)" ></font-awesome-icon> </h6> <div class="p-3"> <b> <translate>Chose format:</translate> </b> <select v-model="form.format" class="form-control d-block w-100"> <option value="landscape"> <translate>landscape</translate> </option> <option value="portrait"> <translate>portrait</translate> </option> </select> <select v-model="form.paperSize" class="form-control d-block w-100"> <option value="a3"> <translate>ISO A3</translate> </option> <option value="a4"> <translate>ISO A4</translate> </option> </select> <small class="d-block my-2"> <input type="radio" id="pdfexport-downloadtype-download" value="download" v-model="form.downloadType" selected > <label for="pdfexport-downloadtype-download" class="ml-1 mr-2"> <translate>Download</translate> </label> <input type="radio" id="pdfexport-downloadtype-open" value="open" v-model="form.downloadType" > <label for="pdfexport-downloadtype-open" class="ml-1"> <translate>Open in new window</translate> </label> </small> <button @click="download" type="button" class="btn btn-sm btn-info d-block w-100"> <translate>Generate PDF</translate> </button> </div> </div> </div> </template> <script> /* 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 by via donau * – Österreichische Wasserstraßen-Gesellschaft mbH * Software engineering by Intevation GmbH * * Author(s): * * Markus Kottländer <markus.kottlaender@intevation.de> * * Bernhard E. Reiter <bernhard@intevation.de> */ import { mapState } from "vuex"; import jsPDF from "jspdf"; var paperSizes = { // in millimeter, landscape [width, height] a3: [420, 297], a4: [297, 210] }; export default { name: "pdftool", data() { return { form: { format: "landscape", paperSize: "a4", downloadType: "download" } }; }, computed: { ...mapState("map", ["openLayersMap"]), ...mapState("application", ["showPdfTool"]), ...mapState("bottlenecks", ["selectedSurvey"]) }, methods: { download() { // FUTURE: disable button while working on it console.log( "will generate pdf with", this.form.paperSize, this.form.format ); var width, height; // generate PDF and open it if (this.form.format !== "portrait") { // landscape, default width = paperSizes[this.form.paperSize][0]; height = paperSizes[this.form.paperSize][1]; } else { // switch width and height width = paperSizes[this.form.paperSize][1]; height = paperSizes[this.form.paperSize][0]; } let resolution = 120; // Dots per inch. An inch is 25.4 mm. // FUTURE: consider margins console.log(width, height); var map = this.openLayersMap; var mapSize = map.getSize(); // size in pixels of the map in the DOM // Calculate the extent for the current view state and the passed size. // The size is the pixel dimensions of the box into which the calculated // extent should fit. var mapExtent = map.getView().calculateExtent(mapSize); var pdf = new jsPDF(this.form.format, "mm", this.form.paperSize); var self = this; var scalebarSize = self.form.format === "portrait" && self.form.paperSize === "a4" ? 10 : 15; var northarrowSize = 3; // set a callback for after the next complete rendering of the map map.once("rendercomplete", function(event) { let canvas = event.context.canvas; console.log("rendered", canvas); var data = canvas.toDataURL("image/png"); pdf.addImage(data, "PNG", 0, 0, width, height); self.addScalebar( pdf, width - scalebarSize * 5, height - scalebarSize / 2, scalebarSize ); //self.addText(pdf, 150, 20, 10, "black", 70, "some text"); self.addNorthArrow(pdf, 15, 8, northarrowSize); pdf.save("map.pdf"); // reset to original size map.setSize(mapSize); map.getView().fit(mapExtent, { size: mapSize }); // FUTURE: re-enable button when done }); // trigger rendering var mapSizeForPrint = [ Math.round((width * resolution) / 25.4), Math.round((height * resolution) / 25.4) ]; map.setSize(mapSizeForPrint); map.getView().fit(mapExtent, { size: mapSizeForPrint }); // TODO: replace this src with an API reponse after actually generating PDFs /* let src = this.form.format === "landscape" ? "/img/PrintTemplate-Var2-Landscape.pdf" : "/img/PrintTemplate-Var2-Portrait.pdf"; let a = document.createElement("a"); a.href = src; if (this.form.downloadType === "download") a.download = src.substr(src.lastIndexOf("/") + 1); else a.target = "_blank"; document.body.appendChild(a); a.click(); document.body.removeChild(a); */ }, addScalebar(doc, x, y, size) { doc.setDrawColor(255, 255, 255); doc.setFillColor(255, 255, 255); doc.roundedRect(x - size / 2, y - size / 2, size * 5, size, 3, 3, "FD"); doc.setDrawColor(0, 0, 0); doc.setFillColor(0, 0, 0); doc.rect(x, y, size, 1, "FD"); doc.setFillColor(255, 255, 255); doc.setDrawColor(0, 0, 0); doc.rect(x + size, y, size, 1, "FD"); doc.setFillColor(0, 0, 0); doc.setDrawColor(0, 0, 0); doc.rect(x + size * 2, y, size * 2, 1, "FD"); doc.setFontSize(5); doc.text(x, y + 3, "0"); doc.text(x + size, y + 3, "50"); doc.text(x + size * 2, y + 3, "100"); doc.text(x + size * 4, y + 3, "200 m"); }, addNorthArrow(doc, x1, y1, size) { var y2 = y1 + size * 3; var x3 = x1 - size * 2; var y3 = y1 + size * 5; var x4 = x1 + size * 2; //white triangle doc.setFillColor(255, 255, 255); doc.setDrawColor(255, 255, 255); doc.triangle(x3 - 0.8, y3 + 1.2, x1, y1 - 1.2, x1, y2 + 0.6, "F"); doc.triangle(x1, y1 - 1.2, x1, y2 + 0.6, x4 + 0.8, y3 + 1.2, "F"); //north arrow doc.setDrawColor(0, 0, 0); doc.setFillColor(255, 255, 255); doc.triangle(x3, y3, x1, y1, x1, y2, "FD"); doc.setFillColor(0, 0, 0); doc.triangle(x1, y1, x1, y2, x4, y3, "FD"); doc.setFontSize(size * 3.1); doc.setTextColor(255, 255, 255); doc.setFontStyle("bold"); doc.text(size < 3 ? x1 - 0.5 : x1 - 1.3, y3 + 1, "N"); doc.setFontSize(size * 3); doc.setTextColor(0, 0, 0); doc.setFontStyle("normal"); doc.text(size < 3 ? x1 - 0.5 : x1 - 1.3, y3 + 1, "N"); }, //export an image to PDF addImage(doc, img, type, x, y, width, hight) { doc.addImage(img, type, x, y, width, hight); }, // add some text at specific coordinates and determine how many wrolds in single line addText(doc, postitionX, positionY, size, color, lineWidth, text) { // split the incoming string to an array, each element is a string of words in a single line var textLines = doc.splitTextToSize(text, lineWidth); // get the longest line to fit the white backround to it var longestString = ""; textLines.forEach(function(element) { if (element.length > longestString.length) longestString = element; }); var indexOfMaxString = textLines.indexOf(longestString); // white background (rectangular) around the text doc.setFillColor(255, 255, 255); doc.setDrawColor(255, 255, 255); doc.rect( postitionX - doc.getStringUnitWidth(textLines[indexOfMaxString]) / size, size > 10 ? positionY - size / 1.8 : positionY - size / 2.4, doc.getStringUnitWidth(textLines[indexOfMaxString]) * (size / 2.6), textLines.length * (size / 2), "FD" ); //rounded rectangular /* doc.roundedRect( postitionX - doc.getStringUnitWidth(textLines[indexOfMaxString]) / size, size > 10 ? positionY - size / 1.8 : positionY - size / 2.6, doc.getStringUnitWidth(textLines[indexOfMaxString]) * (size / 2.6), textLines.length * (size / 2), 3, 3, "FD" ); */ doc.setTextColor(color); doc.setFontSize(size); doc.text(postitionX, positionY, textLines); } } }; </script>