Print Map with InfoTemplate/Popup

631
4
Jump to solution
12-04-2019 08:21 PM
HenryKo2
New Contributor III

Hi, in ArcGIS API for JavaScript v3, is it possible to print a map that has Popup or InfoTemplate being displayed?

For example, in here, popups can show when clicked on the map:

ArcGIS API for JavaScript Sandbox 

But how can I print the map including the popup?

I tried the digit-print widget but no luck:

ArcGIS API for JavaScript Sandbox 

I know that a screen-capture will work, but it won't have the usual things such as legends, titles... etc.

0 Kudos
1 Solution

Accepted Solutions
HenryKo2
New Contributor III

In the end, I got it working as follows:

  1. All the "popup" / "InfoWindow" was implemented as good old plain HTML DIV elements.
  2. I print these DIV elements using the html2canvas JavaScript library. They are printed as HTML canvas.
  3. I print the map using the standard ArcGIS for Server print API. The map is printed as HTML canvas.
  4. Finally, I "merge" the two printed HTML canvases as one PNG image.

(I could print everything using the html2canvas library but there were some weird issues).

Hope it helps.

 

View solution in original post

0 Kudos
4 Replies
Noah-Sager
Esri Regular Contributor

Ryan Libed‌ wrote a great blog post on this subject using the 4x version of the ArcGIS API for JavaScript:

https://community.esri.com/people/RLibed-esristaff/blog/2018/12/20/screenshots-with-the-arcgis-api-f... 

HenryKo2
New Contributor III

In the end, I got it working as follows:

  1. All the "popup" / "InfoWindow" was implemented as good old plain HTML DIV elements.
  2. I print these DIV elements using the html2canvas JavaScript library. They are printed as HTML canvas.
  3. I print the map using the standard ArcGIS for Server print API. The map is printed as HTML canvas.
  4. Finally, I "merge" the two printed HTML canvases as one PNG image.

(I could print everything using the html2canvas library but there were some weird issues).

Hope it helps.

 

0 Kudos
GennadiiPrykhodko
New Contributor

@HenryKo2 - Could you share a code example of your work around? I am trying to do the exact same thing. I have been able print pop-up and the map separately, but I am struggling to merge them together.

0 Kudos
HenryKo2
New Contributor III

With the other canvas/node, I firstly set the background-color to rgba(254, 254, 254, 1.0) in CSS as a hack to flag that the pixels are meant to be transparent (so the map below it can show through).

When I merge the map and other canvas together, I manually loop through the pixels to find (254, 254, 254, 1.0) pixels and then set these to real transparent pixels (i.e. a value is zero).

 

 

mergeCanvases: function(mapCanvas, otherCanvas, mapNode, otherNode) {
    console.log("Merging my canvas on top of map canvas.");

    var srcRect = otherNode.getBoundingClientRect();
    var destRect = mapNode.getBoundingClientRect();

    this.maskContainerBackgroundPixels(otherCanvas, srcRect);

    var mapCanvasContext = mapCanvas.getContext("2d", {
        alpha: true
    });

    // Workaround for different screen resolutions.
    mapCanvasContext.drawImage(otherCanvas, 0, 0, srcRect.width * window.devicePixelRatio, srcRect.height * window.devicePixelRatio, 0, 0, destRect.width, destRect.height);
},

// Use flag of RGB of (254, 254, 254) to pretend it is "transparent" (so the map below it can show through). Using CSS transparency didn't work.
maskContainerBackgroundPixels: function(otherCanvas, rect) {
    console.log("Masking pixels.");

    var otherContext = otherCanvas.getContext("2d");

    // Manually set the container background background pixels to transparent.
    var canvasImageData = otherContext.getImageData(0, 0, rect.width * window.devicePixelRatio, rect.height * window.devicePixelRatio);
    for (var i = 0; i < canvasImageData.data.length; i += 4) {
        var r = canvasImageData.data[i];
        var g = canvasImageData.data[i + 1];
        var b = canvasImageData.data[i + 2];
        var a = canvasImageData.data[i + 3];

        // We know that rgb(254, 254, 254) need to be set to transparent.
        if (r == 254 && g == 254 && b == 254 && a == 255) {
            canvasImageData.data[i] = r;
            canvasImageData.data[i + 1] = g;
            canvasImageData.data[i + 2] = b;
            canvasImageData.data[i + 3] = 0;
        }
    }

    // The container background is now transparent so the map beneath can show through.
    otherContext.putImageData(canvasImageData, 0, 0);
},

/* In CSS set the other container background to rgba(254, 254, 254, 1.0) which flags it as 'transparent' pixel. */
.otherContainer {
	/* This is IMPORTANT for printing - these pixels will be masked to transparent when printing. */
	background-color: rgba(254, 254, 254, 1.0);
}

 

 

Hope that helps.

 

0 Kudos