Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Save Openlayers map as PDF (offline version)

I would like to save my openlayers map as PDF.

Unfortunately all the options I tried don't work.

The first option, I guess the easiest one was here:

https://jsfiddle.net/Ljnya5gp/1/

from which I developed something like this:

 function createPdf() {

 var doc = new jsPDF();

 source = $('#map')[0];

 specialElementHandlers = {
    '#map': function (element, renderer) {
        return true
    }
  };

 doc.fromHTML(
  source,
 15,
 15, 
 {
  'width': 170,
  'elementHandlers': specialElementHandlers
 }
   );
     doc.save('Area 5 map - alterations.pdf')

but the script downloads only blank document for me.

I want to have this section downloaded (from index.html)

      <div id="map">
        <div id="popup" class="ol-popup">
            <a href="#" id="popup-closer" class="ol-popup-closer"></a>
            <div id="popup-content"></div>
        </div>
      </div>

Why the output PDF document is blank? Is it caused by Map script, which is embedded into the HTML file?

My <div id="map"> refers to the script attached to the HTML file as the:

enter image description here

The jsfiddle can be found here:

https://jsfiddle.net/rjetdvyo/

Is it something which causes the problem too?

UPDATE:

Based on the answer below I formed something like this:

function createPdf() {

var mapElement = $("#map");

html2canvas(mapElement, {
    useCORS: true,
    onrendered: function (canvas) {
        var img = canvas.toDataURL("image/jpeg,1.0");
        var pdf = new jsPDF();
        pdf.addImage(img, 'JPEG', 15, 40, 180, 180);
        pdf.save('a4.pdf')
    }
});
  }

 var map = (document.getElementById('map'), createPdf);

The printpdf button only refreshes the page.

like image 836
MKR Avatar asked Nov 13 '20 15:11

MKR


1 Answers

I think everything is ok, it was showing blank because you didn't write any text into div. Have a look:

function createPdf() {

    var doc = new jsPDF();

    source = $('#map')[0];

    specialElementHandlers = {
        '#map': function (element, renderer) {
            return true
        }
    };

    doc.fromHTML(
        source,
        15,
        15,
        {
            'width': 170,
            'elementHandlers': specialElementHandlers
        }
    );
    doc.save('Area 5 map - alterations.pdf')

}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"
    integrity="sha512-bLT0Qm9VnAYZDflyKcBaQ2gg0hSYNQrJ8RilYldYQ1FxQYoCLtUjuuRuZo+fjqhx/qtq/1itJ0C2ejDxltZVFg=="
    crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.5.3/jspdf.min.js"></script>

<div id="map">
    <div id="popup" class="ol-popup">
        <a href="#" id="popup-closer" class="ol-popup-closer">Hello</a>
        <div id="popup-content"><h1>Hello, this is a H1 tag</h1></div>
    </div>
</div>

<button onclick="createPdf()">generate PDF</button>

Update:

By using jsPDF and html2canvas both, you can achieve your goal.

html2canvas creates a canvas object from the DOM element. From canvas, you can create an image and finally convert that image into pdf by jsPDF. Have a look at the code below:

function createPdf() {

    var mapElement = $("#map-canvas");

    html2canvas(mapElement, {
        useCORS: true,
        onrendered: function (canvas) {
            var img = canvas.toDataURL("image/jpeg,1.0");
            var pdf = new jsPDF();
            pdf.addImage(img, 'JPEG', 15, 40, 180, 180);
            pdf.save('a4.pdf')
        }
    });

}

// if HTML DOM Element that contains the map is found...
if (document.getElementById('map-canvas')) {

    // Coordinates to center the map
    var myLatlng = new google.maps.LatLng(52.525595, 13.393085);

    // Other options for the map, pretty much selfexplanatory
    var mapOptions = {
        zoom: 14,
        center: myLatlng,
        mapTypeId: google.maps.MapTypeId.ROADMAP
    };

    // Attach a map to the DOM Element, with the defined settings
    var map = new google.maps.Map(document.getElementById("map-canvas"), mapOptions);

}
#map-canvas {
    width: 500px;
    height: 400px;
}
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false" type="text/javascript"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"
    integrity="sha512-bLT0Qm9VnAYZDflyKcBaQ2gg0hSYNQrJ8RilYldYQ1FxQYoCLtUjuuRuZo+fjqhx/qtq/1itJ0C2ejDxltZVFg=="
    crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.5.3/jspdf.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.4.1/html2canvas.min.js"
    integrity="sha512-s/XK4vYVXTGeUSv4bRPOuxSDmDlTedEpMEcAQk0t/FMd9V6ft8iXdwSBxV0eD60c6w/tjotSlKu9J2AAW1ckTA=="
    crossorigin="anonymous"></script>

<button onclick="createPdf()">generate PDF</button>
<div id="map-canvas"></div>

Update 2: I don't know which ways you're following. Just follow these steps to get the job done:

  1. Follow these steps first.
  2. Replace your index.js code by this:
import 'ol/ol.css';
import { Map, View } from 'ol';
import TileLayer from 'ol/layer/Tile';
import OSM from 'ol/source/OSM';

const map = new Map({
    target: 'map',
    layers: [
        new TileLayer({
            source: new OSM()
        })
    ],
    view: new View({
        center: [0, 0],
        zoom: 0
    })
});

var exportButton = document.getElementById('export-pdf');

exportButton.addEventListener(
    'click',
    function () {
        exportButton.disabled = true;
        document.body.style.cursor = 'progress';

        // var format = [297, 210]; 
        var resolution = 72; // The term 72 dpi(dots per inch) is used to express the resolution of a screen
        var dim = [297, 210]; // a4 size's dimension
        var width = Math.round((dim[0] * resolution) / 25.4);
        var height = Math.round((dim[1] * resolution) / 25.4);
        var size = map.getSize();
        var viewResolution = map.getView().getResolution();

        map.once('rendercomplete', function () {
            var mapCanvas = document.createElement('canvas');
            mapCanvas.width = width;
            mapCanvas.height = height;
            var mapContext = mapCanvas.getContext('2d');
            Array.prototype.forEach.call(
                document.querySelectorAll('.ol-layer canvas'),
                function (canvas) {
                    if (canvas.width > 0) {
                        var opacity = canvas.parentNode.style.opacity;
                        mapContext.globalAlpha = opacity === '' ? 1 : Number(opacity);
                        var transform = canvas.style.transform;
                        // Get the transform parameters from the style's transform matrix
                        var matrix = transform
                            .match(/^matrix\(([^\(]*)\)$/)[1]
                            .split(',')
                            .map(Number);
                        // Apply the transform to the export map context
                        CanvasRenderingContext2D.prototype.setTransform.apply(
                            mapContext,
                            matrix
                        );
                        mapContext.drawImage(canvas, 0, 0);
                    }
                }
            );
            var pdf = new jsPDF('landscape');
            pdf.addImage(
                mapCanvas.toDataURL('image/jpeg'),
                '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);
    },
    false
);
  1. Replace your index.html by this:
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>Using Parcel with OpenLayers</title>
    <style>
        #map {
            width: 400px;
            height: 250px;
        }
    </style>
</head>

<body>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.5.3/jspdf.min.js"></script>

    <button id="export-pdf" >Export PDF</button>
    <div id="map"></div>
    <script src="./index.js"></script>

</body>

</html>
like image 61
Shahnawaz Hossan Avatar answered Nov 13 '22 09:11

Shahnawaz Hossan