I'm trying to wrap the Plotly.js React component inside Web Components. After mounting the plotly.js React component, the 2D plot is divided into two separatedmain-svg
s, one for data and one for layout.
Moreover, the events are activated on main-svg
containing layout
However, for a 3D plot, I didn't face this issue. The 2D plot and 3D plot are almost the same. The 3D plot just has one extra line to get z data
. Also, the type
is set to 'scatter3d'
.
The following code is the 2d plotly react component:
export class Sct2dClassComp extends React.Component{
constructor(props){
super(props);
this.state = {
data : props.data,
layout : {
xaxis:{
title:'x-axis',
},
yaxis:{
title:'y-axis',
},
hovermode:'closest',
margin:{l:0, r:0, t:0, b:0},
},
config : {
displaylogo: false,
modeBarButtonsToRemove: [
'autoScale2d',
'hoverClosestCartesian',
'hoverCompareCartesian',
'toggleSpikelines',
'pan2d',
'zoomIn2d',
'zoomOut2d',
'zoom2d',
'lasso2d'
],
}
};
}
handleOnSelectedEvent = (event) => {
window.alert("onSelected events fired onSelected event")
}
handleOnClickEvent = (events)=>{
window.alert("onClick events fired onClick event")
}
componentDidMount(){
axios.get('http://localhost:3003/sct')
.then(resp => {
const res_data = resp.data;
if (res_data && res_data.length > 0) {
const sct_data=[{
x: res_data.map((item) => item.x),
y: res_data.map((item) => item.y),
// z: res_data.map((item) => item.z),
mode: 'markers',
type: 'scatter',
marker:{
size: 7,
color: res_data.map((item) => item.color),
opacity: 0.8
},
hovertemplate:res_data.map((item) => item.name)
}]
this.setState({
data : sct_data
});
}
})}
render() {
return (
<div>
<Plot
data = {this.state.data}
layout={this.state.layout}
config={this.state.config}
onClick={this.handleOnClickEvent}
onSelected={this.handleOnSelectedEvent}
/>
</div>
);
}
}
And this is the corresponding custom element:
class Sct2dElement extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
this.mountPoint = document.createElement('span');
const shadowRoot = this.attachShadow({ mode: 'open' });
shadowRoot.appendChild(this.mountPoint);
ReactDOM.render(<Sct2dClassComp />, this.mountPoint);
retargetEvents(this.shadowRoot);
}
disconnectedCallback(){
ReactDOM.unmountComponentAtNode(this.mountPoint);
}
}
customElements.define('sct2d-element', Sct2dElement);
I was wondering if someone has any ideas about the reason behind this issue, and how I can fix it.
Thanks in advance.
The issue is because const shadowRoot = this.attachShadow({ mode: 'open' });
is adding Shadow DOM which provides encapsulated CSS. In this specific case this isn't ideal because the Plotly.js library depends on global CSS styles, so the styles are not applied within the component's shadowRoot
.
Until Plotly fixes issues with Shadow DOM, a workaround is to not create any Shadow DOM, e.g:
class ExampleEl extends HTMLElement {
constructor() {
super();
const mountPoint = document.createElement('div');
this.appendChild(mountPoint);
Plotly.newPlot(mountPoint, [{
x: [1,2,3,4,5],
y: [1,2,4,8,16],
margin: {t:0},
}]);
}
}
customElements.define('example-el', ExampleEl)
<script src="https://cdn.plot.ly/plotly-2.16.1.min.js"></script>
<example-el></example-el>