-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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
Plotly.js is incompatible with Chrome's native shadow DOM implementation #1433
Comments
Closing due to lack of activity. |
@etpinard whoops—didn't see your responses. Yes, I did mean the modebar, and yes, the behavior is just like #702. I'm fine with this being closed relative to that issue, if resolving #702 also fixes this bug. (Although, tbh, this particular case might be more of a Shadow DOM/Polymer issue than a plotly issue, since turning on Shadow DOM ought to have no effect.) Also, thank you! 😊 Cheers! |
I have the same problem with the legend. In Polymer 1.0 you can turn off native shadow DOM and everything works fine but If you plan to use Plotly with native shadow DOM v1 toolbar and legend are not working as expected. I think this can have a huge impact for who wants to use Plotly + web components since Shadow DOM v1 has became W3C spec. |
I am also experiencing this issue - it seems like it makes it impossible to use plotly with polymer and perhaps even native webcomponents. I attempted to use the child-window branch in #702 but it did not fix the problem. |
I believe the problem is in the way that plotly adds style to the document. When the plotly.js script is loaded it initializes itself by running the following function for a number of css styles: lib.addStyleRule = function(selector, styleString) {
if(!lib.styleSheet) {
var style = document.createElement('style');
// WebKit hack :(
style.appendChild(document.createTextNode(''));
document.head.appendChild(style);
lib.styleSheet = style.sheet;
}
var styleSheet = lib.styleSheet;
if(styleSheet.insertRule) {
styleSheet.insertRule(selector + '{' + styleString + '}', 0);
}
else if(styleSheet.addRule) {
styleSheet.addRule(selector, styleString, 0);
}
else lib.warn('addStyleRule failed');
}; This appends a new style tag to the head of the document. Chrome doesn't seem to totally understand this because if you try to inspect the element it just appears empty. This is not a problem if you are not using a shadowRoot as the styles are still correctly applied. However, in a shadowRoot the style encapsulation screws things up and the styles are not found. You can get around this by adding the required styles to your template style section. This is kind of a mess but it does work. I have created an example project that shows the initial problem and the hack working at: plotly-polymer-fix There is a script at happybase that claims to be a cross-browser way to create css styles dynamically. I replaced the original implementation of addStyleRule with this one and it also does not work. |
I've also found that the following css restores proper behavior in my polymer component: /* plotly require those class to render correctly */
.js-plotly-plot .plotly .main-svg {
position: absolute;
top: 0;
left: 0;
pointer-events: none;
} EDIT: actually never mind, it's just slightly better, and jdfergason's styles are much more complete. However, there are still some issues with getting the position of the mouse for the zoom / hover actions. |
This is because css must be defined inside the component's shadow dom.
Then do what you want with css, if you are using lit-element your can expose the css this way:
Then you are free to import this piece of css in your individual components. |
I discovered a hacky approach to getting full Plotly support inside of shadow dom that people might find useful until better shadow dom support is available. Basically, if you put a slot inside of the shadow dom and then slot in the plot div into the custom element containing that shadow dom, the plot will behave as if it's in the light dom but will be visually located inside the shadow dom. I've made a demo project demonstrating this trick using the polymer3 starter project: I myself was having issues getting plotly_click and plotly_hover events to fire and solved it this way, but this solution is meant to answer the broader topic of Plotly being incompatible with shadow dom. The downside is that you have to slot things in from the top level of the dom structure, but it does work. Also, this approach should work for any framework, as long as slots are an option. |
For anyone using Lit and running into the same problem: Overriding Example (in scala.js): final class Chart() extends LitElement {
override protected def createRenderRoot(): EventTarget = this
override protected def render(): TemplateResult =
html"""
<div></div>
"""
override protected def firstUpdated(changedProperties: js.Map[String, js.Object]): Unit = {
super.firstUpdated(changedProperties)
val data = ...
val div = querySelector("div").asInstanceOf[HTMLElement]
Plotly.plot(div, data)
}
} Edit: Grammar |
This is still an issue with Web Components as I've just found out. Seems unlikely that Plotly will ever be very useful as browsers and w3c standards progress, plotly's assumptions about its environment are increasingly unsustainable. Rather sad since some effort has been made to support browser ECMA module use. |
@darkengines solution does work. Is there a way we can get the global css required via the distribution package: https://www.npmjs.com/package/plotly.js-dist |
+1, the best workaround would be providing compiled CSS in the dist package. I'm also running into this issue with web components in SolidJS currently. |
Context
I develop and maintain ginkgobioworks/plotly-plot, a Polymer element that encapsulates plotly.js. Polymer is a web-component framework written by Google, which uses browser functionality known as the "shadow DOM" to isolate the internals of web components from the rest of the page.
Polymer 1.x has two kinds of shadow DOM implementations: native shadow DOM (v0), and a
shim called "shady DOM." Native shadow DOM is newer and yields improved
performance, but it has poor support in browsers outside of Chrome
and can cause problems with existing code. For this reason, shady DOM is
still the default implementation in Polymer 1.x.
Issue
Unfortunately, native shadow DOM is currently incompatible with plotly.js. The
icon toolbar layout code in the plotly.js library fails for all plotly plots
rendered inside a shadow DOM.
Example
Since it's a pain to create your own elements without the tools in a code pen, the easiest example to observe is on the plotly-plot demo page.
You can render the page either with shady DOM (the default) or with shadow DOM by passing in the
?dom=shadow
GET parameter, which forces Polymer to use native shadow DOM v0 in browsers that support it.Expected/Observed
Under shady DOM (no GET parameter), the elements behave as expected. Under shadow DOM (with the GET parameter), however, the toolbars fail to render entirely.
Impact
I don't know why this is the case. It might have to do with SVG support for the buttons, or CSS effects.
The work-around on my side is that anyone who consumes my element must not turn on native shadow DOM rendering on any page that renders a
plotly-plot
widget. This is fine for small, simple pages, but can be a real drag when front-end performance is at stake.I'm wondering if there might be a relatively easy fix that would prevent this from happening—if there is, it'd be nice to do it. If not, it's probably not worth doing any serious rewriting for this use case.
In any case, thought you'd be interested to know.
The text was updated successfully, but these errors were encountered: