Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

snapshot canvas and dom elements like markers #7345

Closed
PBrockmann opened this issue Sep 27, 2018 · 12 comments
Closed

snapshot canvas and dom elements like markers #7345

PBrockmann opened this issue Sep 27, 2018 · 12 comments

Comments

@PBrockmann
Copy link

PBrockmann commented Sep 27, 2018

I have tested the get map.getCanvas().toDataURL() as in https://bl.ocks.org/stephanbogner/98ab52a868f1c162644611e7e06f7418 but it captures only the canvas and not markers as they can appear in https://www.mapbox.com/mapbox-gl-js/example/custom-marker-icons/

I do understand that it is because markers are dom elements.
But is there a solution to this today ?

Perhaps, transform markers as symbols with an icon image ? But notice that in my real user case, I have 400 markers, each one with a different image (div rounded with a background-image).

@mourner
Copy link
Member

mourner commented Sep 28, 2018

To be able to capture the image from canvas with the markers, you'll have to convert them into a symbol layer manually — I'm afraid there's no other way, and we can't do the conversion automatically.

@mourner mourner closed this as completed Sep 28, 2018
@PBrockmann
Copy link
Author

PBrockmann commented Sep 28, 2018

Too bad because I will not be able to customize a symbol as I can do for a div with css specifications.
image
Here is an example. Each div has a border line + a box-shadow + a photo.

But all those dom elements are not captured by map.getCanvas(). 😢

@PBrockmann
Copy link
Author

And what about using html2canvas to capture dom elements and map.getCanvas to capture the canvas then combine the 2 canvas ?
Would it be possible ?

@JEVietti
Copy link

@PBrockmann You shouldn't need to do any merging instead just capture the root dom element with html2canvas that contains the map canvas and your DOM elements.

@PBrockmann
Copy link
Author

Ah... Cool.
I have tested this with https://www.mapbox.com/mapbox-gl-js/example/custom-marker-icons/ without success but will try again. Thanks.

@JEVietti
Copy link

@PBrockmann Make sure to try it on your own map with the preserveDrawingBuffer:true otherwise no map/icons will be captured, which is probably why its not working on the link you provided.

@PBrockmann
Copy link
Author

PBrockmann commented Sep 28, 2018

Ok, I think I am not far: image is well generated but not as a downloadable file.
Beware to use last html2canvas release (https://html2canvas.hertzen.com/dist/html2canvas.js)
My test is available from https://jsfiddle.net/PBrockmann/szf9n46q/

Finally it is not correct since by decoding directly base64 image, cats do not appear...

@JEVietti
Copy link

So there are a couple of issues at play here, and let me know how this turns out but for downloading from the html2canvas on click see https://stackoverflow.com/questions/31656689/how-to-save-img-to-users-local-computer-using-html2canvas . This is due to href not being resolved by promise until after click download event has occurred, so create a hidden a tag and click that once the promise is resolved.

The issue of the cats seems to be from html2canvas if you use the default markers instead it works as expected. So the issue seems to be html2canvas not capturing the divs' background image, and from a quick search this seems to be a common issue so I'll leave the rest to you. Please update though with what you find.

@PBrockmann
Copy link
Author

PBrockmann commented Sep 29, 2018

Ok I follow the roadtrip.
Issue about the download event is solved. I had this in mind but more focussed on problem with background images from html2canvas.

And indeed this one is not solved yet. https://jsfiddle.net/PBrockmann/szf9n46q/ has been updated.
The issue is to be still open niklasvh/html2canvas#265
Note that my test uses 1.0.0-alpha.12 release of html2canvas.

For now only border outline of markers are captured. Not the box-shadow borders neither the background images. Lost in what to change or experiment.
https://stackoverflow.com/questions/22569210/html2canvas-missing-background
solution is indicated for 0.4.1 but now release at 1.0.0-alpha.12

@PBrockmann
Copy link
Author

PBrockmann commented Sep 29, 2018

There is an issue on box-shadow niklasvh/html2canvas#221
Still open

Background images are well captured if encoded as base64 but not with a local file like url("cat1.jpg").
html2canvas throws then DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.
Search to understand why.

@tsuz
Copy link
Contributor

tsuz commented Dec 14, 2021

There are two ways to achieve this:

  1. Convert the popups and load that as a symbol layer. Two caveats with this approach; a) the lat/lng will point to the middle of the image so you'd need to figure out the offsets, and it's must harder if the content is dynamic. b) the attribution/logo will not be included, which can violate the Terms of Service. More about attribution here.
  2. Alternatively, you can convert the map into an image, and convert other overlaying HTML elements into an image and merge them onto a Canvas2D context. A working example looks like this: https://jsfiddle.net/tsuzk/fx8qsr5m/75/
    One minor caveat is the rasterized attribution text in the bottom right of the image doesn't look as good as we'd like. Someone with more insight into Canvas2D can improve this.

Screen Shot 2021-12-14 at 17 53 06

@cuellarirobert
Copy link

Hello @tsuz

was playing around a bit, and this will likely impact the performance/speed of generating the image, but it does help quite a bit with the clarity.

https://developer.mozilla.org/en-US/docs/Web/CSS/image-rendering

//add this
elements.forEach(element => {
element.width = element.offsetWidth * 1;
element.height = element.offsetHeight * 1;
element.style.width = element.width + "px";
element.style.height = element.height + "px";
element.style.imageRendering = "high-quality";
});
const container = getCanvas()
const containerRect = container.getBoundingClientRect()
const c = document.createElement("canvas");

//adjust these two lines
// c.width = mapRect.width
// c.height = mapRect.height
//with these 2
c.width = element.offsetWidth * 10;
c.height = element.offsetHeight * 10;

Screenshot 2023-02-07 at 11 36 31 PM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants