8

I have implemented a scatterplot using react-plotly.js I would like the chart to re-size itself when the page layout changes. But currently, the layout of the chart doesn't change by itself. If I explicitly perform some function on the chart which forces the chart to redraw itself then only the chart width changes.

I applied useResizeHandler property and have set autosize to true. But that doesn't make any difference either.

<Plot
   useResizeHandler
   style={{ width: '100%' }}
   data={chartData}
   onClick={(data) => this.handlePlotClick(data)}
   type={'scatter'}
   layout={this.layout} />

 const layout = {
      autosize: true,
      dragmode: true,
      margin: {
        l: 5,
        r: 5,
        t: 10,
        b: 10,
        pad: 0,
        autoexpand: true
      },
      hovermode: 'closest',
      hoverlabel: {
        bgcolor: 'rgba(0,0,0,1)',
        bordercolor: 'rgba(200,200,200,1)'
      },
      height: '650',
      yaxis: {
        visible: false
      },
      xaxis: {
        autorange: false,
        showline: true,
        fixedrange: false, // true disables range selection on main graph
        rangeslider: {
          range: this.state.sliderRange,
          visible: true,
          borderwidth: 1,
          bordercolor: '#000'
        }
      }
    };
  }

enter image description here As you can see in the screenshot above, the div.svg-container has same width as the main-svg. But it still leaves white space on the right. I am unable to debug why it would behave that way. If I explicitly perform zoom on the chart that will redraw the plot then it will behave correctly. But I would like it to automatically resize when the page layout changes.

user2128
  • 590
  • 2
  • 13
  • 35

2 Answers2

9

I was stuck on this problem too. Try window.dispatchEvent(new Event('resize')) from http://codrate.com/questions/how-can-trigger-the-window-resize-event-manually-in-javascript

I was calling resizeHandler when my chart is resized by dragging.

resizeHandler = () => {
    this.child.resizeHandler();
    window.dispatchEvent(new Event('resize'));
}

The charts always autoscales when the chart is resized, so I basically trigger the window resize when my chart size is changed. So for you, when you detect the page layout changes you can trigger the window resize.

jonathon
  • 91
  • 1
  • 2
    I seems like it hasn't been mentioned yet but there is a plotly config option called 'responsive' that can be set to true to help handle a dynamic chart size. https://plot.ly/javascript/responsive-fluid-layout/ mentions that this is 'useful for phones!' so i suspect it was made with landscape/portrait mode switching in mind. So the window's resize event seems to trigger the re-calculation of the chart dimensions. – Harrison Telfer Feb 10 '20 at 16:27
  • This should be an answer. Works! – esantix Feb 04 '23 at 23:24
0

Here's a complete implementation with a resizable div so that a user can resize the plot to any size they want by resizing the parent div; it's using the ResizeObserver. This is slightly different than your question, but I felt like it would be useful for others searching for this question.

The plotly figure sits inside of a custom ResizableDiv component.

import _ from "lodash";
import PropTypes from "prop-types";
import React, {Component} from "react";
import ReactDOM from "react-dom";
import Plot from "react-plotly.js";

class ResizableDiv extends Component {
    constructor(props) {
        super(props);
        this.ref = React.createRef();
    }
    componentDidMount() {
        this.observer = new window.ResizeObserver(
            _.debounce(item => window.dispatchEvent(new Event("resize")), 1000)
        );
        this.observer.observe(this.ref.current);
    }
    componentWillUnmount() {
        this.observer.unobserve();
    }
    render() {
        return (
            <div style={{resize: "both", overflow: "hidden"}} ref={this.ref}>
                {this.props.children}
            </div>
        );
    }
}
ResizableDiv.propTypes = {
    children: PropTypes.element,
};

class PlotlyFigure extends Component {
    render() {
        const {data, layout} = this.props;
        return (
            <ResizableDiv>
                <Plot
                    data={data}
                    layout={layout}
                    useResizeHandler={true}
                    style={{width: "100%", height: "100%"}}
                />
            </ResizableDiv>
        );
    }
}
PlotlyFigure.propTypes = {
    data: PropTypes.array,
    layout: PropTypes.object,
};
shapiromatron
  • 569
  • 6
  • 11