Html2canvas: Not rendering shadow dom elements

Created on 25 Aug 2014  ·  16Comments  ·  Source: niklasvh/html2canvas

I am working on a new project using polymer webcomponents.

The problem is that html2canvas is not rendering the shadow dom

Can you please tell me where should i work on your library in order to have support for webcomponents?

Feature

Most helpful comment

Is there any update on this issue?
Or any workaround for the app having nested shadow dom?

All 16 comments

You'd probably need to look into the node parser (https://github.com/niklasvh/html2canvas/blob/master/src/nodeparser.js) and check whether a node has a shadow DOM before queueing to render it.

Here?

negativeZindex.concat(nonInlineNonPositionedDescendants).concat(nonPositionedFloats)
.concat(inFlow).concat(stackLevel0).concat(text).concat(positiveZindex).forEach(function(container) {
this.renderQueue.push(container);
if (isStackingContext(container)) {
this.parse(container);
this.renderQueue.push(new ClearTransform());
}
}, this);

Can you give me a hint about next step? :)

You'll need to to correctly order the nodes there for rendering (for more information see http://www.w3.org/TR/CSS21/visuren.html#z-index), but prior to that you'll need to fetch the shadow dom nodes for each context stack.

@fernandezpaco have you looked into this any further? I'm pretty interested in this feature as well.

@niklasvh Did somebody fix this issue? I'd be interested in using the library, but I'm using Polymer and ShadowDOM and it's not working for me.

var node = parentContainer.node; if(node.shadowRoot !== null){parentContainer.node = node.shadowRoot.querySelector('div');

The above lines in NodeParser.prototype.getChildren did render shadowDOM elements

@niklasvh can you confirm if this is right approach?

Unfortunately this also fails because of the way html2canvas tag the node to be rendered and then clone the entire document and inability to pierce shadow-dom using querySelector.

Even when tagging the node up to the document root the tagging seems to be lost after the first shadow dom during the cloning. Not sure what's happening there.

@niklasvh can you share a link (https://github.com/niklasvh/html2canvas/blob/master/src/nodeparser.js) again, it shows 404.

@niklasvh : We are facing the same issue (unable to render SHADOW-DOM), let us know if anyone had worked on it.

@srajabhoj Following version 1.0.0 rewrite, it's probably https://github.com/niklasvh/html2canvas/blob/master/src/NodeParser.js

hey anyone got solution for this, also I am facing to capture images div which have scroll, please suggest way, any lead will be helpful

My workaround is to clone the content and css that as you want to render a HTMLElement , then append it to document.body. Set style filter:opacity(0) because html2canvas does not support this but supported in modern browser. Remove it after render.

However, it is very hard to do if you included many shadow-dom element in the content you want to render. Still have no idea on that.

Here is my code in Angular

const newRef = this.renderRef.nativeElement.cloneNode(true);
this.renderer.setStyle(newRef, 'filter', 'opacity(0)');
this.renderer.appendChild(document.body, newRef);
html2canvas(newRef).then(canvas => {
     if (canvas.toBlob) {
          canvas.toBlob(
            blob => {
              fileSaver.saveAs(blob, 'image.jpg');
              this.renderer.removeChild(document.body, newRef);
              alert('Image has been downloaded to your device');
            },
            'image/jpg',
            0.8
          );
     }
});

@Jeffen this was very helpful, thank you! Also the file saver thing was of great help. Just in case anyone wonders how this works, I did it like this:

$ npm i file-saver

import * as saveAs from 'file-saver';

saveAs(blob, 'image.jpg');

Is there any update on this issue?
Or any workaround for the app having nested shadow dom?

The html2canvas lib would need to be updated so that it can traverse the "composed tree" instead of the "light tree".

The "composed tree" (or "flat tree" in other places) is described in the original ShadowDOM draft (click the "collapse" button in the red box to stay on that page instead of re-directing to the new page). Feel free to ask me if you're not familiar with any concept.

If all ShadowRoots have mode:'open', this should be fairly straight forward.

If we want to support ShadowRoots with mode: 'closed', then this will be more complicated and will require patching of attachShadow in order to track references to shadow roots so that we can traverse on them.

Once we know how to traverse the "composed tree" in general, then we'd need to update html2canvas's recursive DocumentCloner.cloneNode method to have it traverse the composed tree instead of the light tree.

Slotted content could be trickier to handle. You'd need to find the corresponding slots in order to render the content into the correct place.

<!--my-component-->
<div><slot name="some-region"></slot></div>
<slot></slot>
<!--my-app-->
<my-component>
  Default Slotted Content
  <button slot="some-region">Button</button>
</my-component>
Was this page helpful?
0 / 5 - 0 ratings