javascriptjqueryleafletprintthis

Map container already initialized in LeafletJS when using printThis


I'm using printThis to print a bunch of elements from a page in an application.

I'm encountering the following error:

leaflet.js:5 Uncaught Error: Map container is already initialized.
at e._initContainer (leaflet.js:5:31752)
at e.initialize (leaflet.js:5:20608)
at new e (leaflet.js:5:2745)
at o.map (leaflet.js:6:8323)
at initLeafletMap (JsCombinerV22023702496814.ashx?jsLocal=true:57688:22)
at StatisticMapControl.LoadLeafletMap (JsCombinerV22023702496814.ashx?jsLocal=true:57375:24)
at eval (eval at <anonymous> (jquery.min.js:2:14136), <anonymous>:2:36)
at eval (<anonymous>)
at jquery.min.js:2:14136
at Function.globalEval (jquery.min.js:2:14147)

But this only happens the first time I click "print" when loading the application page. If, once loaded, I navigate through different menus and try to print in those menus, I don't have any errors. If I come back to the default page, I don't get any errors as well.

The error happens in the leaflet file (from the library)

_initContainer: function(t) {
            var e = this._container = o.DomUtil.get(t);
            if (!e)
                throw new Error("Map container not found.");
            if (e._leaflet_id)
                throw new Error("Map container is already initialized.");
            o.DomEvent.addListener(e, "scroll", this._onScroll, this),
            this._containerId = o.Util.stamp(e)
        },

when I invoke it:

function initLeafletMap(mapContainerId) {
return L.map(mapContainerId, { zoomControl: false, tap: false, zoomSnap: 0 });
};

After invoking it, part of the code that runs inside leaflet is this:

o.Class.extend = function(t) {
var e = function() {
this.initialize && this.initialize.apply(this, arguments),
this.callInitHooks()
}

It seems that initialize is called twice, which in turn calls initContainer, where the exception occurs that the map container has already been initialized.

Should I modify something in that function so that initialize is only called once? I wouldn't want to modify an external library.

I've researched, and in many places, they suggest setting the map to null before invoking the function. In my case, this is already done just before invoking the map:

this.map = null;
this.map = initLeafletMap(mapContainerId);

Before using printThis, something else was used (I'm not sure what) to grab the desired elements from the page and form a document for printing. Leaflet.js was also used and did not cause any problems.

If anyone knows what the problem might be or what I can try, I would appreciate it.

UPDATE

As requested from Jason, this is how I invoke printThis:

namespace('WebPageExportationService').getInstance = function () {
function webPageExportationService() {
    this.callback = null;

    this.exportPage = function (exportRequest, callback) {
        this.callback = callback;
        var cssContent = exportRequest.customProperties.cssContent;
        var elementsToPrint = exportRequest.customProperties.elementsToPrint;
        var header = exportRequest.customProperties.customHeader;

        var elementsJoined = elementsToPrint.join(',');

        $(elementsJoined).printThis({
            debug: true,
            printDelay: 2000,
            importStyle: true,
            loadCSS: cssContent,
            header: header,
            afterPrint: function() {
                if (typeof callback === 'function') {
                    callback();
                }
            }
        });
    };
}
return new webPageExportationService();
}

This is placed within a file in the front-end, which I call this way:

this.ExportRedirect = function () {

var dashboardTitle = $('#PaintMetaDataControl1 ul li.metadataItem').last().text();
var cssFileUrl = window.location.origin + '/CSS/printThisStyle.css';
var header = "<img src='" + window.location.origin + "/Img/header.png' />";

var request = {
    downloadedFileName: dashboardTitle,
    customProperties: null
};  

var elements = [];  
elements = ["#CongestionDetail", ".wrap-controller", "#Comp1", "#Comp2", "#CompTasa3", "#statistic-table", "#Type .StatisticTableControl", "#tipoRes", "#group5anios", "#Recurr1", "#Recurr2", ".prefooter"];

var printProperties = {
    cssContent: cssFileUrl,
    elementsToPrint: elements,
    customHeader: header
}
request.customProperties = Object.assign({}, request.customProperties, printProperties);

//window.waiting.Show();
jQuery(document).off().on('iFramePrintLoaded', function () {
    window.waiting.Hide();
});

namespace('WebPageExportationService').getInstance().exportPage(request, function () {
    window.waiting.Hide();
});
LoadingSpinnerChangingDashboards();


};

I inspected the iframe created with the setting debug: true. All the elements I need are within the iframe. It also includes and utilizes the Leaflet library, the same as the page from which I am retrieving elements to be printed. This is because I'm printing the interactive map using the library

<link type="text/css" rel="stylesheet" href="https://unpkg.com/leaflet@1.0.1/dist/leaflet.css" media="all">

I'm not sure of what to do with the beforePrintEvent option. Should I remove the invocation of LeafLet within the iframe? I think this won't allow me to select the map as it is from the web page.


Solution

  • I managed to solve the issue by using html2canvas to screenshot the Map that's using Leaflet library.

    After that, I put the image into the html with an id and display: none so it's not visible and then, I can finally select the image together with the rest of elements I want to print.

    I'll leave the code below:

    var map = document.getElementById('FirstMap_CongestionDetail');
        
    html2canvas(map, { scale: 0.5 }).then(canvas => {
      var imageData = canvas.toDataURL();
      var image = "<img id='interactiveMap' src='" + imageData + "' style='display: none;'/>";
      mapPlacedIn.innerHTML += image;
      //More code below...
    
        });
    }