changeset 1897:c78efb1ddb02 dev-pdf-generation

client: pdf-gen: improve scalebar to show nice values * Add an algorithm to shorten the scale bar to show nice value for the four parts. * Remove or disable some debugging console.log() output. * Disable print of "Scale 1:x" as this would still show fine grained numbers.
author Bernhard Reiter <bernhard@intevation.de>
date Fri, 18 Jan 2019 12:26:08 +0100
parents 3ed036adc80f
children 7247ac316cb7
files client/src/components/Pdftool.vue
diffstat 1 files changed, 75 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/client/src/components/Pdftool.vue	Thu Jan 17 21:48:11 2019 +0100
+++ b/client/src/components/Pdftool.vue	Fri Jan 18 12:26:08 2019 +0100
@@ -128,7 +128,6 @@
       }
 
       // FUTURE: consider margins
-      console.log(width, height);
 
       // dots per mm = dots per inch / (25.4 mm/inch)
       var pixelsPerMapMillimeter = this.form.resolution / 25.4;
@@ -173,7 +172,13 @@
         let metersPerPixel = // average meters (reality) per pixel (map)
           getPointResolution(proj, view.getResolution(), view.getCenter()) *
           proj.getMetersPerUnit();
-        console.log("metersPerPixel = ", metersPerPixel);
+        // DEBUG console.log("metersPerPixel = ", metersPerPixel);
+
+        let scaleNominator = Math.round(
+          // the x in 1:x map scale
+          1000 * pixelsPerMapMillimeter * metersPerPixel
+        );
+        console.log("scaleNominator = ", scaleNominator);
 
         var data = canvas.toDataURL("image/jpeg");
         pdf.addImage(data, "JPEG", 0, 0, width, height);
@@ -188,9 +193,10 @@
           pdf,
           width - scalebarSize * 5,
           height - scalebarSize / 2,
-          scalebarSize,
-          scalebarSize * pixelsPerMapMillimeter * metersPerPixel
+          scalebarSize * 4,
+          scaleNominator
         );
+        /*
         self.addText(
           pdf,
           width - scalebarSize * 5,
@@ -198,9 +204,9 @@
           10,
           "black",
           50,
-          "Scale 1:" +
-            Math.round(1000 * pixelsPerMapMillimeter * metersPerPixel)
+          "Scale 1:" + scaleNominator
         );
+        */
         //self.addText(pdf, 150, 20, 10, "black", 70, "some text");
         self.addNorthArrow(pdf, 15, 8, northarrowSize);
         pdf.save("map.pdf");
@@ -241,8 +247,64 @@
       doc.setFillColor(255, 255, 255);
       doc.roundedRect(x, y, w, h, 3, 3, "FD");
     },
-    addScalebar(doc, x, y, size, realLength) {
-      // realLength as number in meters (reality)
+    addScalebar(doc, x, y, maxWidth, scaleNominator) {
+      // maxWidth in mm
+      // scaleNominator is the x in 1:x of the map scale
+
+      // reduce width until we'll find a nice number for printing
+      // strategy:
+      //           1. check which unit prefix we shall use to get [10:10000[
+      //           2. using a mapping for the leading digit to get [1:10[
+      //           3. select a smaller number which is nicely dividable
+      //           4. scale up again to get length in paper mm and to be shown
+
+      // from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/log10#Polyfill
+      let log10 =
+        Math.log10 || // more precise, but unsupported by IE
+        function(x) {
+          return Math.log(x) * Math.LOG10E;
+        };
+
+      let maxLength = maxWidth * scaleNominator;
+
+      let unit = "mm";
+      let unitConversionFactor = 0;
+      if (maxLength > 10e7) {
+        // >10 km
+        unit = "km";
+        unitConversionFactor = 10e6;
+      } else if (maxLength > 10e4) {
+        // >10m
+        unit = "m";
+        unitConversionFactor = 10e3;
+      }
+
+      maxLength /= unitConversionFactor;
+
+      // DEBUG console.log(maxLength, unit);
+      let unroundedLength = maxLength;
+      let numberOfDigits = Math.floor(log10(unroundedLength));
+      let factor = Math.pow(10, numberOfDigits);
+      let mapped = unroundedLength / factor;
+      // DEBUG console.log(mapped);
+
+      var length = Math.floor(maxLength); // just to have an upper limit
+
+      // manually only use numbers that are very nice to devide by 4
+      // note that this is taken into account for rounding later
+      if (mapped > 8) {
+        length = 8 * factor;
+      } else if (mapped > 4) {
+        length = 4 * factor;
+      } else if (mapped > 2) {
+        length = 2 * factor;
+      } else {
+        length = factor;
+      }
+
+      let size = (length * unitConversionFactor) / scaleNominator / 4;
+      // DEBUG console.log(length, size);
+
       doc.setDrawColor(0, 0, 0);
       doc.setFillColor(0, 0, 0);
       doc.rect(x, y, size, 1, "FD");
@@ -254,13 +316,14 @@
       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, Math.round(realLength).toString());
-      doc.text(x + size * 2, y + 3, Math.round(realLength * 2).toString());
+      // /4 and could give 2.5. We still round, because of floating point arith
       doc.text(
-        x + size * 4,
+        x + size,
         y + 3,
-        Math.round(realLength * 4).toString() + " m"
+        (Math.round((length * 10) / 4) / 10).toString()
       );
+      doc.text(x + size * 2, y + 3, Math.round(length / 2).toString());
+      doc.text(x + size * 4, y + 3, Math.round(length).toString() + " " + unit);
     },
 
     addNorthArrow(doc, x1, y1, size) {