Html2canvas: Problem to generate the image of map (Google Maps)

Created on 6 Mar 2014  ·  51Comments  ·  Source: niklasvh/html2canvas

hi, guys.
I need to generate a image of my dialog:

1

Using html2canvas, but the image create doesn't show the map:

2

My code:

            function imagem()
            {
                var html2obj = html2canvas($('#dialogPrint'));
                var queue  = html2obj.parse();
                var canvas = html2obj.render(queue);
                var img = canvas.toDataURL();
                window.open(img);
            };

i need help, please.
thanks

Needs More Information

Most helpful comment

Seems that in the new version of google maps transform is applied to the different div. Using @GCorbel's solution but with this selector (".gm-style>div:first>div:first>div:last>div") seems to work. Though I haven't yet tested it thoroughly.

All 51 comments

Problem is, that google maps uses CSS3 Transformation matrix, which are not fully implemented in html2canvas.

how do I do?

Google Maps images (images in external server)?

Use proxy: https://github.com/niklasvh/html2canvas#how-does-it-work

brcontainer: I think its illegal (accessing map tiles directly from another computer /proxy/). Only way is to use CORS.

@bkralik proxy is not only for you to access "blocked sites", proxy term means something else in case the proxy for html2canvas serve to make the javascript API open images from external servers as if it were on your local site.

The proxy makes a downloaded the external server and html2canvas loads the image only after the download completed.

Read this http://en.wikipedia.org/wiki/Same_origin_policy for you to understand the subject.

how do i use this proxy?

The link that you have spent all the links to the use of proxy (in php languages​​, C# (asp.net), python and VB (asp classic)).

Maybe you have not noticed the links to the proxies, then I will give you here:
https://github.com/niklasvh/html2canvas/wiki/Proxies

When using a new library is always good to read the entire README.

@brcontainer I know what this proxy do - when client want to screenshot page, then SERVER download all of pictures to local folder and then client loads them. But thats wrong - because google doesnt allow direct use of their tilesservers - and from their point of view, somebody is sudenly downloading loads of tiles to server without viewing webpage...

i'm using Java.
you have a example to use the proxy?

@brcontainer And as I mentioned, there is really problem with CSS3 transformations, because googlemaps running on Google Chrome use them, so map is not screenable with current implementation. Trust me, I had this problem in project I wrote...

@bkralik So, how can i do?
do you have any example?

I program in java too (I already created proxies in PHP, C # and VB), but I'm not in time to create a proxy in Java, maybe I can just do it on Sunday.

Its application is JSP or "Java Desktop"?

@brcontainer It's a webapplication, using JSF, Primefaces, Javascript and Java

@DanielSBelo JSF framework I never used, I program in pure Java, without frameworks, do not know if it will be easy to implement the current code with a code in java part. I wanted to help him, but it really is not timely.

[edited]
About css transforms support, read: https://github.com/niklasvh/html2canvas#contributing

@DanielSBelo did you find a good solution for this? I'm having the same problem.

Saving a map as a canvas works fine in Firefox, but fails to save the map in Chrome. I don't think it is directly related to the transformation, but more likely the way Chrome handles CORs. I'm totally stuck trying to find an answer, though.

@TGOlson It's really problem with CSS3 transformations, because current release of html2canvas is able to render only "one level" of transformation - it doesn't stack them.
You can verify that problem is in transformations simply by playing with google maps - usually, screenshot like this is given:
map_2014-08-10_10-44-02
(In css, whole map is positioned correctly but after disabling css3, this happens)
Only solution is to implement whole css3 transformations stack. I don't know, if it's in progress by Niklas, but someone should do it :-)

subscribing

I'm also having the same problem - only in Chrome. I'm using html2canvas-proxy-php. Other browsers work fine. Parts of the map are just missing.. seems to be related to resizing the map, adding/removing overlays, etc

FYI - if you need to get some map capture functionality up and running quickly, you can always use the google streetview or static maps API. Basically, reconstruct what the current user is looking at on the map (map.getPov, etc.) then get that static image from google.

I don't think that approach works with overlays

I've just stumbled across this issue. If I'm not mistaken, this stackoverflow question exhibits this problem and I've offered a workaround by reading the css3 transforms and applying them as normal CSS positions.

var transform=$(".gm-style>div:first>div").css("transform")
var comp=transform.split(",") //split up the transform matrix
var mapleft=parseFloat(comp[4]) //get left value
var maptop=parseFloat(comp[5])  //get top value
$(".gm-style>div:first>div").css({ //get the map container. not sure if stable
  "transform":"none",
  "left":mapleft,
  "top":maptop,
})

Perhaps, css3 transforms could be checked and automatically converted to normal CSS positioning while rendering then removing them after render.

i'm having an inconstant screen capture function.
Works after a full reload of the page (using CTLR+R on firefox)

here is my code, what basically it does is to generate a 64 base/png image of a captured printsreen of the window and the final result i put into an tag to see if it works.

An here is the function

function ebfPrintScreen(componentName)
{
html2cavnas
([document.body],
{
logging: true,
useCORS: true,
onrendered: function (canvas)
{
img = canvas.toDataURL("image/jpg");

                                                  console.log(img.length);
                                                  console.log(img);

                                                  var imgComp = $c(conponentName);
                                                  imgComp.img.src = img

                                          }
                      }
                );

}

The main objective is to capture the google map route after it is created, but as i say, sometime it works, sometime don't. Any clue on what is going on?

I am having the same problem. I go to take an image of the map after zooming and panning around and larger portions, to even all of the map, become shrouded in light brown all of a sudden. If anyone has a fix for this in Chrome please let me know.

tried @mfirdaus 's solution, and it works for noraml map view, however, in streetview, it is still broken...anyone have the same issue?

After applying @mfirdaus 's solution I was able to get the map view captured. But somehow this code below is making the map unusable (but the html2canvas usable):

$(".gm-style>div:first>div").css({ //get the map container. not sure if stable
      "transform":"none",
      "left":mapleft,
      "top":maptop,
    })

Is there a way to "restore" what that line is doing? For now I'm calling the initMap function again in order to have the map working after calling the html2canvas function witht the transformation code.

Does the above script work for Google Maps v3?

My requirement is to take a screenshot of a Google Map v3 with a route drawn on it.

It works nicely in Firefox, but in Chrome there is no marker or route. I am already using custom markers.

I have a difficult time debugging because there is no error in console and logging is so limited.

Has anyone solve the issue in Chrome? I have tried the proxy scripts in two languages, but neither seems to make a difference.

I have a similar issue, I copy/cut this code from the internet :

  if($.browser.safari) {// Fix for Chrome
    var transform=$(".gm-style>div:first>div").css("transform");
    var comp=transform.split(","); //split up the transform matrix
    var mapleft=parseFloat(comp[4]); //get left value
    var maptop=parseFloat(comp[5]);  //get top value
    $(".gm-style>div:first>div").css({ //get the map container. not sure if stable
      "transform":"none",
      "left":mapleft,
      "top":maptop,
    });
  }

  html2canvas([$("#map")[0]], {
    logging: false,
    useCORS: true,
    onrendered: function (canvas) {
      $('#screenshot').after(canvas);

      if($.browser.safari) {// Fix for Chrome
        $(".gm-style>div:first>div").css({
          left:0,
          top:0,
          "transform":transform
        });
      }
    }
  });

It works but if I move the map with the handler it doesn't work. I works with markers, polygons, etc. It also works in firefox ( I can move the map ) but not in chrome.

Any idea ?

Fixed !

The fix for chrome I stupidly copy/pasted was not triggered.

I did this :

  if(window.chrome) {// Fix for Chrome
    var transform=$(".gm-style>div:first>div").css("transform");
    var comp=transform.split(","); //split up the transform matrix
    var mapleft=parseFloat(comp[4]); //get left value
    var maptop=parseFloat(comp[5]);  //get top value
    $(".gm-style>div:first>div").css({ //get the map container. not sure if stable
      "transform":"none",
      "left":mapleft,
      "top":maptop,
    });
  }

  html2canvas([$("#map > div.g-map-canvas > div > div > div:nth-child(1)")[0]], {
    logging: false,
    useCORS: true,
    onrendered: function (canvas) {
      $('#screenshot').after(canvas);

      if(window.chrome) {// Fix for Chrome
        $(".gm-style>div:first>div").css({
          left:0,
          top:0,
          "transform":transform
        });
      }
    }
  });

The very long selector in html2canvas is for have map without buttons and options.

I works now, thanks.

Thanks @GCorbel It works very well with your solution.

The above workarounds work for rendering the map but the top controls are either missing or in the wrong position. Any ideas?

Is this still an issue with v1.0.0? If so, could you please share an example on jsfiddle.

This issue has been automatically closed because there has been no response to our request for more information from the original author. With only the information that is currently in the issue, we don't have enough information to take action. Please reach out if you have or find the answers we need so that we can investigate further.

@niklasvh I can confirm that it is still an issue with the latest version. Here is a fiddle I created while testing this issue: http://jsfiddle.net/9agom947/4/

The fiddle shows the problem as described in the linked stackoverflow question, not necessarily what's in the OP of this thread. If you don't pan the map, there is no problem in getting the map to be copied. Once you pan the map, in Chrome but not in FireFox, the copied map will be blank outside the region that was initially loaded.

image

The fix given in this thread does seem to solve the problem.

@Ananda-Pryana I've tried your jsFiddle however the fix does not seem to work anymore. Is there any other solution ?

Thanks in advance.

Looks like the latest version of google map (v3.32) released recently has a new experimental renderer.
https://developers.google.com/maps/documentation/javascript/releases

This has broken the fix. I only did a quick testing, but it seems like now things are broken equally in all browsers (not just for Chrome), so hopefully that will make it easier to fix in the next version of html2canvas?

But a quick work-around would be to use the older version of gmap, where the fix would still be working fine.

@Ananda-Pryana Yup I downgraded gmap, worked, thanks.

Thanks @Ananda-Pryana! I had this working last week then moved it to a new platform and I thought the move was what broke it. I was totally going down a rat hole assuming the new environment was the culprit. I downgraded to 3.30 and all is well.

Seems that in the new version of google maps transform is applied to the different div. Using @GCorbel's solution but with this selector (".gm-style>div:first>div:first>div:last>div") seems to work. Though I haven't yet tested it thoroughly.

@rSensation tip worked like a charm in newest version. Thank you!

Hmm seems this problem is back for me, I have to pan the map to see the issue and when I pan and use Html2Canvas to get the screen grab, some areas show as blank grey?

To any of you dealing with getting overlay layers cut off --
@GCorbel's selector only transforms the google map layer. If you have other overlays, you'll have to find which div they are in (for example, $('.gm-style>div:first>div:first>div:first>div:first>div') was one of my overlay divs and apply the same transform to the css.

@mylesboone how did you find which div the overlay layers are? I'm currently struggling through the same issue of overlay layers being cut off.

I'm using GmapMarker and GmapPolyline as overlay layers at the moment.

@sunghunOW
A solution can be found here https://github.com/niklasvh/html2canvas/issues/1568
You can use your browser's inspection tool to see which div's will need transformation.

Best solution I have found:

    html2canvas($('.gm-style>div:eq(0)')[0],{
        useCORS: true,
        allowTaint: true,
        async:false,
    }).then(canvas => {document.body.appendChild(canvas)});
    html2canvas($('.gm-style>div:eq(0)')[0],{
        useCORS: true,
        allowTaint: true,
        async:false,
    }).then(canvas => {document.body.appendChild(canvas)});

This give me canvas is not defined.. Should the selector of the items word out of the box?

@hseeda Thank you! Your selector was doing the trick for me!

Here's my slightly modified selector that does work (at least for me, haha)

const div = document.querySelector('#map > div:first-of-type')

html2canvas(div, {})

However, now it's cutting off the Google Logo which always has to show in order to comply with the terms and conditions :(

Well well, I'll just clone the node or something. I've been fighting this map for a while now :D

This works for me:

$('#snapshot').on('click',function () {
    html2canvas(document.querySelector('.gm-style'), 
           {useCORS:true, allowTaint: true,async:false} ).then(canvas => {
            document.body.appendChild(canvas)
    });
});

The issue with blank map or an error generating the canvas was tricky, but eventually what fixed it for me was adding this config:

ignoreElements: (node) => {
        return node.nodeName === 'IFRAME';
      }
html2canvas(mapWrapper, {
      useCORS: true,
      allowTaint: false,
      ignoreElements: (node) => {
        return node.nodeName === 'IFRAME';
      }
    }).then(canvas => {
      const url = canvas.toDataURL('image/png');
      saveAs(url, 'image3.png');
      window.URL.revokeObjectURL(url);
    });

Thanks to @imlinus and @hseeda ! This selector works perfectly for me! and it even keeps the google logo, thanks!

@hseeda Thank you! Your selector was doing the trick for me!

Here's my slightly modified selector that does work (at least for me, haha)

const div = document.querySelector('#map > div:first-of-type')

html2canvas(div, {})

However, now it's cutting off the Google Logo which always has to show in order to comply with the terms and conditions :(

Well well, I'll just clone the node or something. I've been fighting this map for a while now :D

Was this page helpful?
0 / 5 - 0 ratings

Related issues

arzyu picture arzyu  ·  3Comments

deepender87 picture deepender87  ·  4Comments

celik75 picture celik75  ·  4Comments

anthonymejia picture anthonymejia  ·  4Comments

Loki180 picture Loki180  ·  4Comments