Search code examples
reactjshighchartsreact-highcharts

Chart not resizing when container width changes - Highcharts React


I am wrapping HighCharts inside a Grid. When the grid is resized, the chart doesnt seem to resize accordingly. Please advice.

This is the code.

import "./styles.css";
import { Grid, Card, CardContent, IconButton } from "@mui/material";
import React from "react";
import { KeyboardArrowLeft, KeyboardArrowRight } from "@mui/icons-material";
import HighchartsReact from "highcharts-react-official";
import Highcharts from "highcharts";

const options = {
  title: {
    text: "U.S Solar Employment Growth by Job Category, 2010-2020",
    align: "left"
  },

  subtitle: {
    text:
      'Source: <a href="https://irecusa.org/programs/solar-jobs-census/" target="_blank">IREC</a>',
    align: "left"
  },

  yAxis: {
    title: {
      text: "Number of Employees"
    }
  },

  xAxis: {
    accessibility: {
      rangeDescription: "Range: 2010 to 2020"
    }
  },

  legend: {
    enabled: false
  },

  plotOptions: {
    series: {
      label: {
        connectorAllowed: false
      },
      pointStart: 2010
    }
  },

  series: [
    {
      name: "Installation & Developers",
      data: [
        43934,
        48656,
        65165,
        81827,
        112143,
        142383,
        171533,
        165174,
        155157,
        161454,
        154610
      ]
    },
    {
      name: "Manufacturing",
      data: [
        24916,
        37941,
        29742,
        29851,
        32490,
        30282,
        38121,
        36885,
        33726,
        34243,
        31050
      ]
    },
    {
      name: "Sales & Distribution",
      data: [
        11744,
        30000,
        16005,
        19771,
        20185,
        24377,
        32147,
        30912,
        29243,
        29213,
        25663
      ]
    },
    {
      name: "Operations & Maintenance",
      data: [
        null,
        null,
        null,
        null,
        null,
        null,
        null,
        null,
        11164,
        11218,
        10077
      ]
    },
    {
      name: "Other",
      data: [
        21908,
        5548,
        8105,
        11248,
        8989,
        11816,
        18274,
        17300,
        13053,
        11906,
        10073
      ]
    }
  ],

  responsive: {
    rules: [
      {
        condition: {
          maxWidth: 500
        },
        chartOptions: {
          legend: {
            layout: "horizontal",
            align: "center",
            verticalAlign: "bottom"
          }
        }
      }
    ]
  }
};

export default function App() {
  const [expanded, setExpanded] = React.useState(true);
  const chartRef = React.useRef(null);

  React.useEffect(() => {
    chartRef && chartRef.current.chart.reflow();
  }, [expanded, chartRef]);

  return (
    <Grid container sx={{ height: "100%" }}>
      <Grid
        item
        xs={expanded === true ? 4 : 2}
        sx={{
          transition: (theme) =>
            theme.transitions.create("all", {
              easing: theme.transitions.easing.sharp,
              duration: theme.transitions.duration.leavingScreen
            })
        }}
      >
        <Card>
          <CardContent>
            <Grid container justifyContent="space-between" alignItems="center">
              {expanded && <Grid item>Sidebar</Grid>}
              <Grid item>
                <IconButton onClick={() => setExpanded(!expanded)}>
                  {expanded ? <KeyboardArrowLeft /> : <KeyboardArrowRight />}
                </IconButton>
              </Grid>
            </Grid>
          </CardContent>
        </Card>
      </Grid>
      <Grid
        item
        xs={expanded === true ? 8 : 10}
        sx={{
          transition: (theme) =>
            theme.transitions.create("all", {
              easing: theme.transitions.easing.sharp,
              duration: theme.transitions.duration.leavingScreen
            })
        }}
      >
        <Card>
          <CardContent>
            {" "}
            <HighchartsReact
              highcharts={Highcharts}
              ref={chartRef}
              options={options}
            />
          </CardContent>
        </Card>
      </Grid>
    </Grid>
  );
}

When you click on the arrow to collapse the container, I expect the container to resize along with the chart.

Appreciate the help.

This is the CodeSandbox: Link


Solution

  • You are right that chart.reflow needs to be called, but because of animation, there are no correct chart's container dimensions in useEffect hook. As a solution, you can reflow the chart after the animation:

      <Grid
        item
        xs={expanded === true ? 8 : 10}
        sx={{
          transition: (theme) => {
            setTimeout(() => {
              chartRef.current && chartRef.current.chart.reflow();
            }, theme.transitions.duration.leavingScreen);
    
            return theme.transitions.create("all", {
              easing: theme.transitions.easing.sharp,
              duration: theme.transitions.duration.leavingScreen
            });
          }
        }}
      >
        <Card>
          <CardContent>
            {" "}
            <HighchartsReact
              highcharts={Highcharts}
              ref={chartRef}
              options={options}
            />
          </CardContent>
        </Card>
      </Grid>
    </Grid>
    

    Live demo: https://codesandbox.io/s/kind-pond-6b3v-6b3vlo?file=/src/App.js

    API Reference: https://api.highcharts.com/class-reference/Highcharts.Chart#reflow