changeset 3989:ca448aff3a17 diagram-cleanup

merge with default
author Thomas Junk <thomas.junk@intevation.de>
date Wed, 17 Jul 2019 14:17:26 +0200
parents e0751da6272c (current diff) beaa75082c09 (diff)
children d76321bc22d8
files schema/updates/0000/99.set_version.sql schema/updates/0301/99.set_version.sql schema/updates/1000/99.set_version.sql
diffstat 7 files changed, 148 insertions(+), 218 deletions(-) [+]
line wrap: on
line diff
--- a/client/src/components/Pdftool.vue	Wed Jul 17 13:00:19 2019 +0200
+++ b/client/src/components/Pdftool.vue	Wed Jul 17 14:17:26 2019 +0200
@@ -169,7 +169,7 @@
       readyToGenerate: true, // if the user is allowed to press the button
       rendercompleteListener: null,
       mapSize: null,
-      mapExtent: null
+      resolution: null
     };
   },
   computed: {
@@ -209,12 +209,6 @@
     close() {
       this.$store.commit("application/showPdfTool", false);
     },
-    millimeter2pixels(length, dpi) {
-      return (dpi * length) / 25.4;
-    },
-    pixel2millimeter(pixels, dpi) {
-      return (pixels * 25.4) / dpi;
-    },
     // When a template is chosen from the dropdown, its propoerties are
     // applied to the rest of the form.
     applyTemplateToForm() {
@@ -250,7 +244,18 @@
       this.form.resolution = this.templateData.properties.resolution;
     },
     download() {
-      // disable button while working on it
+      /**
+       * In order to generate the image with the appropriate resolution
+       * we have to temporaily scale the visible part of the map.
+       * The newly rendered canvas is converted to Base64 DataURL.
+       * After that is done, the resolution is resetted to its previous state.
+       *
+       * calculateExtent() and fit() do not give the desired result
+       * when the view is rotated so we replace them completely by setting resolution
+       *
+       * Details: https://gis.stackexchange.com/questions/328933/openlayers-generating-clientside-pdfs
+       *
+       */
       this.readyToGenerate = false;
 
       console.log(
@@ -261,245 +266,170 @@
       );
 
       if (this.form.format !== "portrait") {
-        // landscape, default
         this.pdf.width = paperSizes[this.form.paperSize][0];
         this.pdf.height = paperSizes[this.form.paperSize][1];
       } else {
-        // switch width and height
         this.pdf.width = paperSizes[this.form.paperSize][1];
         this.pdf.height = paperSizes[this.form.paperSize][0];
       }
 
       // FUTURE: consider margins
 
-      // dots per mm = dots per inch / (25.4 mm/inch)
       var pixelsPerMapMillimeter = this.form.resolution / 25.4;
       var mapSizeForPrint = [
-        // in pixel
         Math.round(this.pdf.width * pixelsPerMapMillimeter),
         Math.round(this.pdf.height * pixelsPerMapMillimeter)
       ];
-
-      // generate PDF and open it
-      // our units are milimeters; width 0 x height 0 is left upper corner
-
-      // Step 1 prepare and save current map extend
-      // Then add callback "rendercomplete" for Step 3
-      //    which will generate the pdf and resets the map view
-      // Step 2 which starts rendering a map with the necessary image size
-
       var map = this.openLayersMap();
-      this.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.
-      this.mapExtent = map.getView().calculateExtent(this.mapSize);
+      this.mapSize = map.getSize();
+      this.resolution = map.getView().getResolution();
 
       this.pdf.doc = new jsPDF(this.form.format, "mm", this.form.paperSize);
-      // set a callback for after the next complete rendering of the map
       this.rendercompleteListener = map.once("rendercomplete", event => {
         let canvas = event.context.canvas;
-
-        // because we are using Web Mercator, a pixel represents
-        // a differently sized spot depending on the place of the map.
-        // So we use a value calculated from the center of the current view.
         let view = map.getView();
         let proj = view.getProjection();
         let metersPerPixel = // average meters (reality) per pixel (map)
           getPointResolution(proj, view.getResolution(), view.getCenter()) *
           proj.getMetersPerUnit();
-        // DEBUG console.log("metersPerPixel = ", metersPerPixel);
-
         let scaleDenominator = Math.round(
-          // the x in 1:x map scale
           1000 * pixelsPerMapMillimeter * metersPerPixel
         );
         console.log("scaleDenominator = ", scaleDenominator);
-        const width80DPI = this.millimeter2pixels(this.pdf.width, 80);
-        const height80DPI = this.millimeter2pixels(this.pdf.height, 80);
-        const currentHeight = this.millimeter2pixels(
-          this.pdf.height,
-          this.form.resolution
-        );
-        const currentWidth = this.millimeter2pixels(
+        var snapshot = canvas.toDataURL("image/jpeg");
+        this.pdf.doc.addImage(
+          snapshot,
+          "JPEG",
+          0,
+          0,
           this.pdf.width,
-          this.form.resolution
+          this.pdf.height
         );
-        //const scaleFactor = this.form.resolution / 80;
-        var snapshot = canvas.toDataURL("image/jpeg");
-        const offscreen = document.createElement("canvas");
-        offscreen.width = currentWidth;
-        offscreen.height = currentHeight;
-        const image = new Image();
-        image.src = snapshot;
-        image.onload = () => {
-          offscreen
-            .getContext("2d")
-            .drawImage(
-              image,
-              (currentWidth - width80DPI) / 2,
-              (currentHeight - height80DPI) / 2,
-              width80DPI,
-              height80DPI,
-              0,
-              0,
-              currentWidth,
-              currentHeight
-            );
-          const data = offscreen.toDataURL("image/jpeg");
-          this.pdf.doc.addImage(
-            data,
-            "JPEG",
-            0,
-            0,
-            this.pdf.width,
-            this.pdf.height
-          );
 
-          if (this.templateData) {
-            this.pdf.doc.setFont("linbiolinum", "normal");
-            let defaultFontSize = 11,
-              defaultRounding = 2,
-              defaultTextColor = "black",
-              defaultBgColor = "white",
-              defaultPadding = 3,
-              defaultOffset = { x: 0, y: 0 },
-              defaultBorderColor = "white",
-              defaultWidth = 100;
-            this.templateData.elements.forEach(e => {
-              switch (e.type) {
-                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 || defaultOffset,
-                    e.width,
-                    e.height,
-                    // handling the case when the rectangle  not rounded (rounding = 0)
-                    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;
-                }
-                case "image": {
-                  this.addImage(
-                    e.url,
-                    e.format,
-                    e.position,
-                    e.offset || defaultOffset,
-                    e.width,
-                    e.height
-                  );
-                  break;
-                }
-                case "bottleneck": {
-                  this.addBottleneckInfo(
-                    e.position,
-                    e.offset || defaultOffset,
-                    e.rounding === 0 || e.rounding
-                      ? e.rounding
-                      : defaultRounding,
-                    e.color || defaultTextColor,
-                    e.brcolor || defaultBorderColor
-                  );
-                  break;
-                }
-                case "legend": {
-                  this.addLegend(
-                    e.position,
-                    e.offset || defaultOffset,
-                    e.rounding === 0 || e.rounding
-                      ? e.rounding
-                      : defaultRounding,
-                    e.brcolor || defaultBorderColor
-                  );
-                  break;
-                }
-                case "scalebar": {
-                  this.addScaleBar(
-                    scaleDenominator,
-                    e.position,
-                    e.offset || defaultOffset,
-                    e.rounding === 0 || e.rounding
-                      ? e.rounding
-                      : defaultRounding,
-                    e.brcolor || defaultBorderColor
-                  );
-                  break;
-                }
-                case "scale": {
-                  this.addScale(
-                    scaleDenominator,
-                    e.position,
-                    e.width,
-                    e.offset || defaultOffset,
-                    e.fontSize || defaultFontSize,
-                    e.color || defaultTextColor
-                  );
-                  break;
-                }
-                case "northarrow": {
-                  this.addNorthArrow(
-                    e.position,
-                    e.offset || defaultOffset,
-                    e.size
-                  );
-                  break;
-                }
+        if (this.templateData) {
+          this.pdf.doc.setFont("linbiolinum", "normal");
+          let defaultFontSize = 11,
+            defaultRounding = 2,
+            defaultTextColor = "black",
+            defaultBgColor = "white",
+            defaultPadding = 3,
+            defaultOffset = { x: 0, y: 0 },
+            defaultBorderColor = "white",
+            defaultWidth = 100;
+          this.templateData.elements.forEach(e => {
+            switch (e.type) {
+              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 || defaultOffset,
+                  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.filename);
-          }
-
-          // reset to original size
-          map.setSize(this.mapSize);
-          map.getView().fit(this.mapExtent, {
-            size: this.mapSize,
-            // necessary to get to the previous zoom level in all cases
-            // details see https://github.com/openlayers/openlayers/issues/9235
-            constrainResolution: false
+              case "image": {
+                this.addImage(
+                  e.url,
+                  e.format,
+                  e.position,
+                  e.offset || defaultOffset,
+                  e.width,
+                  e.height
+                );
+                break;
+              }
+              case "bottleneck": {
+                this.addBottleneckInfo(
+                  e.position,
+                  e.offset || defaultOffset,
+                  e.rounding === 0 || e.rounding ? e.rounding : defaultRounding,
+                  e.color || defaultTextColor,
+                  e.brcolor || defaultBorderColor
+                );
+                break;
+              }
+              case "legend": {
+                this.addLegend(
+                  e.position,
+                  e.offset || defaultOffset,
+                  e.rounding === 0 || e.rounding ? e.rounding : defaultRounding,
+                  e.brcolor || defaultBorderColor
+                );
+                break;
+              }
+              case "scalebar": {
+                this.addScaleBar(
+                  scaleDenominator,
+                  e.position,
+                  e.offset || defaultOffset,
+                  e.rounding === 0 || e.rounding ? e.rounding : defaultRounding,
+                  e.brcolor || defaultBorderColor
+                );
+                break;
+              }
+              case "scale": {
+                this.addScale(
+                  scaleDenominator,
+                  e.position,
+                  e.width,
+                  e.offset || defaultOffset,
+                  e.fontSize || defaultFontSize,
+                  e.color || defaultTextColor
+                );
+                break;
+              }
+              case "northarrow": {
+                this.addNorthArrow(
+                  e.position,
+                  e.offset || defaultOffset,
+                  e.size
+                );
+                break;
+              }
+            }
           });
 
-          // as we are done: re-enable button
-          this.readyToGenerate = true;
-        };
+          this.pdf.doc.save(this.filename);
+        }
+        map.setSize(this.mapSize);
+        map.getView().setResolution(this.resolution);
+        this.readyToGenerate = true;
       });
-
-      // trigger rendering
+      const size = map.getSize();
+      const [width, height] = mapSizeForPrint;
       map.setSize(mapSizeForPrint);
-      map.getView().fit(this.mapExtent, { size: mapSizeForPrint });
+      const scaling = Math.min(width / size[0], height / size[1]);
+      map.getView().setResolution(this.resolution / scaling);
     },
     cancel() {
       this.openLayersMap().un(
@@ -509,7 +439,7 @@
       this.openLayersMap().setSize(this.mapSize);
       this.openLayersMap()
         .getView()
-        .fit(this.mapExtent, { size: this.mapSize });
+        .fit(this.resolution, { size: this.mapSize });
       this.readyToGenerate = true;
     },
     // add the used map scale and papersize
--- a/schema/install-db.sh	Wed Jul 17 13:00:19 2019 +0200
+++ b/schema/install-db.sh	Wed Jul 17 14:17:26 2019 +0200
@@ -133,8 +133,8 @@
        -f "$BASEDIR/geoserver_views.sql" \
        -f "$BASEDIR/auth.sql" \
        -f "$BASEDIR/isrs_functions.sql" \
-       -f "$BASEDIR/default_sysconfig.sql"
-
+       -f "$BASEDIR/default_sysconfig.sql" \
+       -f "$BASEDIR/version.sql"
 
   # setup initial login roles with given passwords:
   psql -qt -P pager=off -p "$port" -d "$db" \
--- a/schema/update-db.sh	Wed Jul 17 13:00:19 2019 +0200
+++ b/schema/update-db.sh	Wed Jul 17 14:17:26 2019 +0200
@@ -88,7 +88,7 @@
   if ver=$( psql -qtA -p "$port" -d "$db" \
                  -c 'SELECT get_schema_version()' 2>/dev/null )
   then
-    echo $ver
+    echo ${ver:--1}
   else
     echo '-1'
   fi
@@ -104,6 +104,8 @@
     echo "Running updates for $new_ver ..."
 
     sql=$( cat `echo "$d/"* | sort -n` )
+    sql+="INSERT INTO gemma_schema_version(version) VALUES ($new_ver);"
+
     psql -1 -q -p "$port" -d "$db" -c "$sql"
   fi
 done
--- a/schema/updates/0000/99.set_version.sql	Wed Jul 17 13:00:19 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-INSERT INTO gemma_schema_version(version) VALUES (0);
--- a/schema/updates/0301/99.set_version.sql	Wed Jul 17 13:00:19 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-INSERT INTO gemma_schema_version(version) VALUES (301);
--- a/schema/updates/1000/99.set_version.sql	Wed Jul 17 13:00:19 2019 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-INSERT INTO gemma_schema_version(version) VALUES (1000);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/schema/version.sql	Wed Jul 17 14:17:26 2019 +0200
@@ -0,0 +1,1 @@
+INSERT INTO gemma_schema_version(version) VALUES (1000);