2

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);
2

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.

  • Thanks TomazicM for helping me but pdf is not being downloaded. Only Mapview is changed. – sanju verma Mar 5 at 8:18
  • Do you get any error in console? – TomazicM Mar 5 at 20:03
  • yes TomazicM, it is showing in console "Active resource loading counts reached a per-frame limit while the tab was in background. Network requests will be delayed until a previous loading finishes, or the tab is brought to the foreground." – sanju verma Mar 6 at 5:49
  • i think it never come within this function map.once('rendercomplete', function(event) { }); that's why map is not exported to pdf. – sanju verma Mar 6 at 6:16
  • 1
    ol3 does not have rendercomplete map event. It has similar postrender event. Documentation says it's experimental (openlayers.org/en/v3.20.1/apidoc/ol.Map.html), but you can try it. – TomazicM Mar 7 at 8:35
2

Here is solution for ol3. Base code is taken from ol3 export to PDF example https://openlayers.org/en/v3.20.1/examples/export-pdf.html.

ol3 does not have getZoomForResolution view method, so I took simplifed formula just for this example from getZoom method:

desiredZoom = Math.log(mapView.getMaxResolution() / reqiredResolution) / Math.log(2);

The code for export to PDF at desired scale then looks like this:

var printScale = 4000;

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();  // edit1
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;

var source = raster.getSource();

var tileLoadStart = function() {
  ++loading;
};

var tileLoadEnd = function() {
  ++loaded;
  if (loading === loaded) {
    var canvas = this;
    window.setTimeout(function() {
      loading = 0;
      loaded = 0;
      var data = canvas.toDataURL('image/png');
      var pdf = new jsPDF('landscape', undefined, format);
      pdf.addImage(data, 'JPEG', 0, 0, dim[0], dim[1]);
      pdf.save('map.pdf');
      source.un('tileloadstart', tileLoadStart);
      source.un('tileloadend', tileLoadEnd, canvas);
      source.un('tileloaderror', tileLoadEnd, canvas);
      map.setSize(size);
      // map.getView().fit(extent, size);  edit1: not needed
      mapView.setZoom(currZoom);  // edit1: return to original zoom
      map.renderSync();
      exportButton.disabled = false;
      document.body.style.cursor = 'auto';
    }, 100);
  }
};

map.once('postcompose', function(event) {
  source.on('tileloadstart', tileLoadStart);
  source.on('tileloadend', tileLoadEnd, event.context.canvas);
  source.on('tileloaderror', tileLoadEnd, event.context.canvas);
});

var mapView = map.getView();
var printPointResolution = (printScale * 25.4) / (resolution * 1000)
var printResolutionAtEquator = mapResolutionFactor * printPointResolution;
var printZoom = Math.log(mapView.getMaxResolution() / printResolutionAtEquator) / Math.log(2);

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

map.renderSync();

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

  • Thanks a lot TomazicM. If i want to print district name in map canvas then what i have to do? – sanju verma Mar 11 at 8:31
  • Describe your wish in more detail an put it as a new question. And mark answer as accepted if it answered your question. – TomazicM Mar 11 at 10:12
  • In this line showing error raster is not defined "var source = raster.getSource();" – sanju verma Mar 11 at 10:28
  • what is raster layer here because i already set a wms layer as baselayer which is required. – sanju verma Mar 11 at 10:36
  • Look at the complete code of example where I took my code from: openlayers.org/en/v3.20.1/examples/export-pdf.html. – TomazicM Mar 11 at 12:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.