niklasvh / html2canvas

Screenshots with JavaScript
https://html2canvas.hertzen.com/
MIT License
30.53k stars 4.8k forks source link

Problem to generate the image of map (Google Maps) #345

Open DanielSBelo opened 10 years ago

DanielSBelo commented 10 years ago

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

bkralik commented 10 years ago

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

DanielSBelo commented 10 years ago

how do I do?

brcontainer commented 10 years ago

Google Maps images (images in external server)?

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

bkralik commented 10 years ago

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

brcontainer commented 10 years ago

@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.

DanielSBelo commented 10 years ago

how do i use this proxy?

brcontainer commented 10 years ago

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

brcontainer commented 10 years ago

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

bkralik commented 10 years ago

@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...

DanielSBelo commented 10 years ago

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

bkralik commented 10 years ago

@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...

DanielSBelo commented 10 years ago

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

brcontainer commented 10 years ago

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"?

DanielSBelo commented 10 years ago

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

brcontainer commented 10 years ago

@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

TGOlson commented 10 years ago

@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.

bkralik commented 10 years ago

@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 :-)

alanramires commented 9 years ago

subscribing

PhaedrusTheGreek commented 9 years ago

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

TGOlson commented 9 years ago

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.

PhaedrusTheGreek commented 9 years ago

I don't think that approach works with overlays

mfirdaus commented 9 years ago

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.

alanramires commented 9 years ago

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?

JordonGreene commented 8 years ago

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.

cht8687 commented 8 years ago

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

gariem commented 8 years ago

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.

mattweberinactive commented 8 years ago

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.

GCorbel commented 7 years ago

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 ?

GCorbel commented 7 years ago

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.

tankhuu commented 7 years ago

Thanks @GCorbel It works very well with your solution.

cpamp commented 7 years ago

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

niklasvh commented 6 years ago

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

no-response[bot] commented 6 years ago

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.

Ananda-Pryana commented 6 years ago

@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.

Juuuke commented 6 years ago

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

Thanks in advance.

Ananda-Pryana commented 6 years ago

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.

Juuuke commented 6 years ago

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

OneTrueBean commented 6 years ago

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.

rSensation commented 6 years ago

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.

FelipeMicali commented 6 years ago

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

OneTrueBean commented 6 years ago

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?

mylesboone commented 6 years ago

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.

sunghunOW commented 6 years ago

@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.

mylesboone commented 6 years ago

@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.

hseeda commented 6 years ago

Best solution I have found:

hseeda commented 6 years ago
    html2canvas($('.gm-style>div:eq(0)')[0],{
        useCORS: true,
        allowTaint: true,
        async:false,
    }).then(canvas => {document.body.appendChild(canvas)});
Jorricks commented 6 years ago
    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?

imlinus commented 5 years ago

@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

karlazz commented 5 years ago

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)
    });
});
shaji-Dev commented 5 years ago

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);
    });