Thursday, 6 August 2015

openlayers - how to fix scale 1:4000 to export map in PDF ol3


This is my code to export map in pdf but i want to fix this map in 1:4000 scale the n export or print it to pdf.


var dims = {
a0: [1189, 841],
a1: [841, 594],
a2: [594, 420],
a3: [420, 297],
a4: [297, 210],

a5: [210, 148]
};

var exportElement = document.getElementById("export-pdf");
exportElement.addEventListener('click', function(e) {
console.log("hi");
if (exportElement.className.indexOf('disabled') > -1) {
return;
}
exportElement.className += ' disabled';


var format = document.getElementById('format').value;
var resolution = document.getElementById('resolution').value;
var buttonLabelElement = document.getElementById('button-label');
var label = buttonLabelElement.innerText;
var dim = dims[format];
var width = Math.round(dim[0] * resolution / 25.4);
var height = Math.round(dim[1] * resolution / 25.4);
var size = /** @type {ol.Size} */ (map.getSize());
var extent = map.getView().calculateExtent(size);


map.once('postcompose', function(event) {
//var tileQueue = map.getTileQueue();

// To prevent potential unexpected division-by-zero
// behaviour, tileTotalCount must be larger than 0.

//var tileTotalCount = tileQueue.getCount() || 1;
var interval;
interval = setInterval(function() {

//var tileCount = tileQueue.getCount();
//var ratio = 1 - tileCount / tileTotalCount;
//buttonLabelElement.innerText = ' ' + (100 * ratio).toFixed(1) + '%';
//if (ratio == 1 && !tileQueue.getTilesLoading()) {
clearInterval(interval);
buttonLabelElement.innerText = label;
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');
map.setSize(size);
map.getView().fit(extent, size);
map.renderSync();
exportElement.className =
exportElement.className.replace(' disabled', '');
// }
}, 100);
});


map.setSize([width, height]);
map.getView().fit(extent, /** @type {ol.Size} */ (map.getSize()));
map.renderSync();

}, false);

any help would be highly appriciated.


I updated the code us per your suggestion still map is not exported to pdf.


//print map 
var dims = {

a0: [1189, 841],
a1: [841, 594],
a2: [594, 420],
a3: [420, 297],
a4: [297, 210],
a5: [210, 148]
};

var exportElement = document.getElementById("export-pdf");
exportElement.addEventListener('click', function(e) {

console.log("hi");
if (exportElement.className.indexOf('disabled') > -1) {
return;
}
exportElement.className += ' disabled';

var format = document.getElementById('format').value;
var resolution = document.getElementById('resolution').value;
var buttonLabelElement = document.getElementById('button-label');
var label = buttonLabelElement.innerText;

var scale = 4000;

var mapView = map.getView();
var mapProjection = mapView.getProjection();
var mapResolutionAtEquator = mapView.getResolution();
var viewCenter = mapView.getCenter();
var mapPointResolution = ol.proj.getPointResolution(mapProjection, mapResolutionAtEquator, viewCenter);

var dim = dims[format];
var width = Math.round(dim[0] * resolution / 25.4);

var height = Math.round(dim[1] * resolution / 25.4);
var size = map.getSize();
var extent = map.getView().calculateExtent(size);

var mapView = map.getView();
var mapProjection = mapView.getProjection();
var mapResolutionAtEquator = mapView.getResolution();
var viewCenter = mapView.getCenter();
var mapResolutionAtEquator = mapView.getResolution();
var mapPointResolution = ol.proj.getPointResolution(mapProjection, mapResolutionAtEquator, viewCenter);

var mapResolutionFactor = mapResolutionAtEquator / mapPointResolution;

map.once('rendercomplete', function(event) {
console.log('hiiii');
buttonLabelElement.innerText = label;
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');

map.setSize(size);
map.getView().fit(extent, size);
exportElement.className =
exportElement.className.replace(' disabled', '');
});


var printPointResolution = (scale * dim[0]) / (width * 1000);
var printResolutionAtEquator = mapResolutionFactor * printPointResolution
var printZoom = mapView.getZoomForResolution(printResolutionAtEquator);


map.setSize([width, height]);
mapView.fit(extent, (map.getSize()));
mapView.setZoom(printZoom);

}, false);

Answer



Since I'm not familiar with ol3, this will be for ol5.


To print in desired scale we neeed to calculate the zoom at which printed map will have that scale. First we need formula to calculate scale of printed map:


var scale =  (width * mapPointResolution * 1000) / dim[0];


where mapPointResolution is map resolution at the center of displayed map:


var mapView = map.getView();
var mapProjection = mapView.getProjection();
var mapResolutionAtEquator = mapView.getResolution();
var viewCenter = mapView.getCenter();
var mapPointResolution = ol.proj.getPointResolution(mapProjection, mapResolutionAtEquator, viewCenter);

We will also need mapResolutionFactor:


var mapResolutionFactor = mapResolutionAtEquator / mapPointResolution;


EDIT1: Original calculation of printPointResolution was wrong because it didn't take into account print DPI resolution. To get the correct value two different formulas for print width in pixels have to be combined:


width = (scale * printDim[0]) / (mapPointResolution * 1000);
width = printDim[0] * resolution / 25.4;

From this we get map point resolution for print at desired scale:


mapPointResolution = (scale * 25.4) / (resolution * 1000);

And finally from this we can get required zoom for print:


printResolutionAtEquator = mapResolutionFactor * printPointResolution;

printZoom = mapView.getZoomForResolution(printResolutionAtEquator);

To put all this togeter (just the print part):


var scale = 4000;

var mapView = map.getView();
var mapProjection = mapView.getProjection();
var mapResolutionAtEquator = mapView.getResolution();
var viewCenter = mapView.getCenter();
var mapPointResolution = ol.proj.getPointResolution(mapProjection, mapResolutionAtEquator, viewCenter);


var dim = dims[format];
var width = Math.round(dim[0] * resolution / 25.4);
var height = Math.round(dim[1] * resolution / 25.4);
var size = map.getSize();
var extent = map.getView().calculateExtent(size);

var mapView = map.getView();
var currZoom = mapView.getZoom(); //edit2
var mapProjection = mapView.getProjection();

var mapResolutionAtEquator = mapView.getResolution();
var viewCenter = mapView.getCenter();
var mapResolutionAtEquator = mapView.getResolution();
var mapPointResolution = ol.proj.getPointResolution(mapProjection, mapResolutionAtEquator, viewCenter);
var mapResolutionFactor = mapResolutionAtEquator / mapPointResolution;

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');
map.setSize(size);
// map.getView().fit(extent, size); //edit2: not needed
mapView.setZoom(currZoom); // edit2: set original zoom
});

var printPointResolution = (scale * 25.4) /(resolution * 1000); // edit1: corrected
var printResolutionAtEquator = mapResolutionFactor * printPointResolution;
var printZoom = mapView.getZoomForResolution(printResolutionAtEquator);


map.setSize([width, height]);
// mapView.fit(extent, (map.getSize())); - edit1: removed, not neccessary
mapView.setZoom(printZoom);

EDIT2: Corrected code to return to original zoom after print.


No comments:

Post a Comment

arcpy - Changing output name when exporting data driven pages to JPG?

Is there a way to save the output JPG, changing the output file name to the page name, instead of page number? I mean changing the script fo...