I am currently working on a solution to generate clientside PDFs from OpenLayers content. The experience is okay so far, but I am having a bit of a hassle.
The abstract is as follows:
- Calculating the amount of pixels needed to fill a given space on paper
- Temporarily set the
map
to given resolution - read canvas
- do print stuff
- reset map to previous resolution
In code:
var mapSizeForPrint = [
// in pixel
Math.round(this.pdf.width * pixelsPerMapMillimeter),
Math.round(this.pdf.height * pixelsPerMapMillimeter)
];
...
var map = this.openLayersMap();
...
this.mapExtent = map.getView().calculateExtent(this.mapSize);
...
this.rendercompleteListener = map.once("rendercomplete", event => {
//Do printing magic
}
map.setSize(mapSizeForPrint);
map.getView().fit(this.mapExtent, { size: mapSizeForPrint });
If anyone is interested in the (dirty) details: full code is available as open source here
That works to a certain degree.
- scaling to 80 DPI, I get an expected subset of the map
- scaling to 120 DPI, I get a relatively expected subset of the map
- scaling to 200 DPI, getting an unexpected result
Currently I assume, that I get the "same" dataset for any given resolution - i.e. the visible center of the 80DPI
version is "the same" as the 200DPI
only that it doesn't fit on screen; but that seems not to be the case.
Does anybody give me a hint in which direction to look? Perhaps I have some false assumptions which I currently do not see or do not see, how to overcome.
Answer
It's because in OpenLayers 5 by default fit
constrains the resolution to an integer zoom level. That can be fixed by adding constrainResolution: false
to the options. Also note that calculateExtent()
and fit()
do not give the desired result when the view is rotated so you could replace them completely by setting resolution so in this example https://openlayers.org/en/latest/examples/export-pdf.html
var extent = map.getView().calculateExtent(size);
map.once('rendercomplete', function(event) {
var canvas = event.context.canvas;
var data = canvas.toDataURL('image/jpeg');
var pdf = new jsPDF('landscape', undefined, format);
pdf.addImage(data, 'JPEG', 0, 0, dim[0], dim[1]);
pdf.save('map.pdf');
// Reset original map size
map.setSize(size);
map.getView().fit(extent, {size: size});
exportButton.disabled = false;
document.body.style.cursor = 'auto';
});
// Set print size
var printSize = [width, height];
map.setSize(printSize);
map.getView().fit(extent, {size: printSize});
becomes
var viewResolution = map.getView().getResolution();
map.once('rendercomplete', function(event) {
var canvas = event.context.canvas;
var data = canvas.toDataURL('image/jpeg');
var pdf = new jsPDF('landscape', undefined, format);
pdf.addImage(data, 'JPEG', 0, 0, dim[0], dim[1]);
pdf.save('map.pdf');
// Reset original map size
map.setSize(size);
map.getView().setResolution(viewResolution);
exportButton.disabled = false;
document.body.style.cursor = 'auto';
});
// Set print size
var printSize = [width, height];
map.setSize(printSize);
var scaling = Math.min(width / size[0], height / size[1]);
map.getView().setResolution(viewResolution / scaling);
No comments:
Post a Comment