0

I want to export my OpenLayers Map to PDF with custom scale and PDF formats (A0,A1..), so I implemented the answer in this post. On a separate basic page it worked but when I tried to implement it in my project, it didn't (wrong scale in printed map). I tried to print all the values used to calculate print zoom, I noticed that there is a bigg difference in view.getMaxResolution().

In basic page :

exportButton.addEventListener('click', function() {
    var scale = 20000;
    var format = document.getElementById('format').value;
    //a4
    var resolution = document.getElementById('resolution').value;
    //150
    var dim = dims[format];
    var width = Math.round(dim[0] * resolution / 25.4);
    console.log(width);
    //1754
    var height = Math.round(dim[1] * resolution / 25.4);
    console.log(height);
    //1240
    var size = map.getSize();
    console.log(size);
    //[1536, 614]
    var extent = map.getView().calculateExtent(size);
    console.log(extent);
    //[805947.5195034844, 451740.0253744397, 835266.4804965156, 463459.9746255603]

    var mapView = map.getView();
    var currZoom = mapView.getZoom();  // edit1
    console.log(currZoom);
    //13
    var mapProjection = mapView.getProjection();
    console.log(mapProjection);
    //wb {wb: "EPSG:26191", a: "m", i: null, oe: null, b: "enu", …}
    var mapResolutionAtEquator = mapView.getResolution();
    console.log(mapResolutionAtEquator);
    //19.087865229838002
    var viewCenter = mapView.getCenter();
    console.log(viewCenter);
    //[820607, 457600]
    var mapPointResolution = ol.proj.getPointResolution(mapProjection, mapResolutionAtEquator, viewCenter);
    console.log(mapPointResolution);
    //19.0908015439191
    var mapResolutionFactor = mapResolutionAtEquator / mapPointResolution;
    console.log(mapResolutionFactor);
    //0.9998461922054795

    var source = raster.getSource();
    var loading=0;
    var loaded=0;
    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 = (scale * 25.4) / (resolution * 1000);
    console.log(printPointResolution);
    //3.3866666666666667
    var printResolutionAtEquator = mapResolutionFactor * printPointResolution;
    console.log(printResolutionAtEquator);
    //3.3861457709358906
    var printZoom = Math.log(mapView.getMaxResolution() / printResolutionAtEquator) / Math.log(2);
    console.log(mapView.getMaxResolution());
    //156367.7919628329
    console.log(printZoom);
    //15.494939775431552

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

In my project :

$(".export_btn").click(function(){
    proj4.defs("EPSG:26191", "+proj=lcc +lat_1=33.3 +lat_0=33.3 +lon_0=-5.4 +k_0=0.999625769 +x_0=500000 +y_0=300000 +a=6378249.2 +b=6356515 +towgs84=31,146,47,0,0,0,0 +units=m +no_defs");

    var dims = {
        a0: [1189, 841],
        a1: [841, 594],
        a2: [594, 420],
        a3: [420, 297],
        a4: [297, 210],
        a5: [210, 148]
    };
    var scale = $('#scale').val();
    var format = 'a4';//$('#format').val();
    var resolution = 150;//$('#resolution').val();

    var loading = 0;
    var loaded = 0;

    var scale = 20000;
    var dim = dims[format];
    var width = Math.round(dim[0] * resolution / 25.4);
    console.log(width);
    //1754
    var height = Math.round(dim[1] * resolution / 25.4);
    console.log(height);
    //1240
    var size = Geoportail.map.getSize();
    console.log(size);
    //[1536, 614]
    var extent = Geoportail.map.getView().calculateExtent(size);
    console.log(extent);
    //[805445.7382534844, 454071.7967316347, 834764.6992465156, 465791.74598275527]
    var mapView = Geoportail.map.getView();
    var currZoom = mapView.getZoom();  // edit1
    console.log(currZoom);
    //13
    var mapProjection = mapView.getProjection();
    console.log(mapProjection);
    //wb {wb: "EPSG:26191", a: "m", i: null, oe: null, b: "enu", …}
    var mapResolutionAtEquator = mapView.getResolution();
    console.log(mapResolutionAtEquator);
    //19.087865229838002
    var viewCenter = mapView.getCenter();
    console.log(viewCenter);
    //[820105.21875, 459931.771357195]
    var mapPointResolution = ol.proj.getPointResolution(mapProjection, mapResolutionAtEquator, viewCenter);
    console.log(mapPointResolution);
    //19.090586736530412
    var mapResolutionFactor = mapResolutionAtEquator / mapPointResolution;
    console.log(mapResolutionFactor);
    //0.999857442480424

    var source = Geoportail.mapOptions.basemaps[Geoportail.getVisibleBaseMap()].layer.getSource();
    var loading=0;
    var loaded=0;
    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);
          Geoportail.map.setSize(size);
          // map.getView().fit(extent, size);  edit1: not needed
          mapView.setZoom(currZoom);  // edit1: return to original zoom
          Geoportail.map.renderSync();
          exportButton.disabled = false;
          document.body.style.cursor = 'auto';
        }, 100);
      }
    };

    Geoportail.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 = Geoportail.map.getView();
    var printPointResolution = (scale * 25.4) / (resolution * 1000);
    console.log(printPointResolution);
    //3.3866666666666667
    var printResolutionAtEquator = mapResolutionFactor * printPointResolution;
    console.log(printResolutionAtEquator);
    //3.386183871867036
    var printZoom = Math.log(mapView.getMaxResolution() / printResolutionAtEquator) / Math.log(2);
    console.log(mapView.getMaxResolution());
    //4886.4934988385285
    console.log(printZoom);
    //10.494923542310213
    Geoportail.map.setSize([width, height]);
    mapView.setZoom(printZoom);
});

I'm using Openlayer 4.6.5

8
  • Take a look at the source for mikenunn.16mb.com/demo/ol5-osm-map-print.htm (it uses OpenLayers 5 where the rendercomplete event avoids having to count loaded tiles but otherwise is similar to OpenLayers 4)
    – Mike
    Commented Sep 24, 2019 at 9:40
  • Thanks but I can not migrate to ol5 version Commented Sep 24, 2019 at 10:23
  • 1
    If method works with separate single page but not in project page (whatever the environment is), there is something in project environment that causes problems. Without having the same environment it's impossile to help.
    – TomazicM
    Commented Sep 24, 2019 at 10:33
  • You don't need to migrate to OL5, just replace the rendercomplete with the OL4 tileload checks. It is the setting of scale that is important.
    – Mike
    Commented Sep 24, 2019 at 10:35
  • 1
    Maybe setSize() isn't working if the map div is a fixed size? In later versions the viewport would expand but be partly hidden, but I'm not sure if that is true in OL4.
    – Mike
    Commented Sep 24, 2019 at 10:57

1 Answer 1

1

After analyzing the map initializer, I noticed that I was setting the minZoom attribute in my map view. After removing it, I now get the same value of mapView.getMaxResolution ().

Conclusion: The minZoom and maxZoom attributes influence the formula

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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