# HG changeset patch # User Thomas Junk # Date 1563365846 -7200 # Node ID ca448aff3a173d44e501ea11417257352f31b375 # Parent e0751da6272c1b8aab477d368691777426a161a7# Parent beaa75082c09f9c3f082c20587784a5f911002eb merge with default diff -r e0751da6272c -r ca448aff3a17 client/src/components/Pdftool.vue --- 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 diff -r e0751da6272c -r ca448aff3a17 schema/install-db.sh --- 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" \ diff -r e0751da6272c -r ca448aff3a17 schema/update-db.sh --- 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 diff -r e0751da6272c -r ca448aff3a17 schema/updates/0000/99.set_version.sql --- 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); diff -r e0751da6272c -r ca448aff3a17 schema/updates/0301/99.set_version.sql --- 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); diff -r e0751da6272c -r ca448aff3a17 schema/updates/1000/99.set_version.sql --- 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); diff -r e0751da6272c -r ca448aff3a17 schema/version.sql --- /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);