1

Here is my code to export map in PDF and map is successfully exported to PDF Now i want to add legends in map canvas but i do not know how to do that.

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

            exportElement.disabled = true;
            document.body.style.cursor = 'progress';

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

    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;
    var pdf_name = dist + "_" + tahsil + "_"+village+ ".pdf";
    map.once('rendercomplete', function(event) {

         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(pdf_name);
          map.setSize(size);
          map.getView().fit(extent, size);
          map.renderSync();
          exportElement.disabled = false;
              document.body.style.cursor = 'auto';
    }); 


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

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

see outout pdf looks too blur at 150 dpi or 300 dpi and even label is not clear. enter image description here

  • If your legend is an image take a look at step 2 in this answer stackoverflow.com/questions/41805963/… – Mike Mar 12 at 10:33
  • my legends is not an image its just a color that shows boundary of district and village. – sanju verma Mar 12 at 11:09
  • So it's a layer? – TomazicM Mar 12 at 21:40
  • Question title mentions ol3. Code above uses getZoomForResolution method, so it's at least for ol4. – TomazicM Mar 12 at 21:43
  • Yes TomazicM i edited the question for ol5. – sanju verma Mar 14 at 5:13
1

The most reasonable selection for legend seems to be .svg graphics. It is vector image, so it is scalable wihout loosing quality and easy editable with many free editors. This legend was created with Inkscape in 5 minutes:

enter image description here

The code to paint legend to canvas has to be outside rendercomplete event so that image has time to load. Parameter placement controls placement of legend on the map. By default legend is aligned top left on the map. If parameter contains letter R, legend is aligned right, if it contains letter B, it is aligned to the bottom.

var legendImage = new Image();
legendImage.crossOrigin = 'Anonymous';
legendImage.src = 'legend.svg';

function drawLegend(ctx, placement) {
  var canvasHeight = ctx.canvas.height;
  var canvasWidth = ctx.canvas.width;

  var legendHeight = canvasHeight * 0.10;  // legend height is 10% of map height
  var legendWidth = legendHeight * (legendImage.width / legendImage.height);
  var offset = canvasHeight * 0.01;

  var legendX;
  var legendY;

  placement = (placement === undefined) ? '' : placement.toUpperCase();
  if (placement.indexOf('R') >= 0)
    legendX = canvasWidth - legendWidth - offset;
  else {
    legendX = offset;
  };
  if (placement.indexOf('B') >= 0)
    legendY = canvasHeight - legendHeight - offset;
  else {
    legendY = offset;
  };

  ctx.drawImage(base_image, legendX, legendY, legendWidth, legendHeight);
}

Call to draw the legend can be just before canvas.toDataURL('image/jpeg') statement. With the call below legend is aligned top left on the map:

...
drawLegend(event.context);
var data = canvas.toDataURL('image/jpeg');
...

Here is an example of semitransparent legend on 1:4000 map exported to PDF at 300 dpi:

enter image description here

There is one problem with this solution. I couldn't get this code to work in IE11. It has CORS problems because canvas source is coming from two different places. It works in Firefox and Chrome.

To make it work in IE11, bitmap image has to be used (.png, .tif, .jpg).

  • ok sir i will apply this then acknowledge you...thanks a lot. – sanju verma Mar 22 at 7:46
  • may you plase tell me if i have to write something in top left of the canvas then what i have to do. – sanju verma Mar 22 at 7:50
  • 1
    I modified the answer so that placement of legend on the map is controled with parameter. – TomazicM Mar 22 at 19:26
  • Great TomazicM sir. thanks for helping. you are such a genius. – sanju verma Mar 23 at 5:06
  • now only one problem is there..when i am choosing 150dpi or 300dpi the pdf map is more dark & blur. I add image for this please go through it. – sanju verma Mar 23 at 9:09

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.