DEV Community

Rajeesh C V
Rajeesh C V

Posted on • Originally published at rajeeshcv.com on

Creating Responsive D3 Chart using ReactJS

This post shows how to create a responsive chart using D3 and React.

Here is demo URL https://i5u7r.csb.app/ to play with and it looks like this

Building D3 chart requires width and height values upfront, this helps D3 to map data points to an x, y coordinate on the SVG canvas. In this post, we’re creating a simple line chart with x-axis and y-axis and it resizes when the browser window is resized and axes ticks are updated based on the available width and height.

First, we need a way to get width and height values and it should update when the browser window is resized. For this, I’m creating a custom resize hook called useResize, which returns the size of HTML element passed to it.

function useResize(ref) {
const [state, setState] = useState();
  useEffect(() => {
const getSize = debounce(() => {
if (!ref || !ref.current) {
return;
      }
const width = ref.current.offsetWidth;
const height = ref.current.offsetHeight;
      setState({
        width,
        height,
      });
    }, 1000);

window.addEventListener("resize", getSize);
    getSize();
return () => window.removeEventListener("resize", getSize);
  }, [ref]);

return state;
}

useResize hook subscribes to resize event and uses offsetWidth, offsetHeight properties on the HTML node to get width and height respectively.

Make sure getSize method is not called frequently to reduce the number of updates. Here, I’m using debounce helper function from lodash.

In my chart component, ref of my root element is passed to useResize hook to get its size.

const LineChart = props => {
  ....
const rootRef = useRef(null);
const size = useResize(rootRef);
  .....
return (
    <div className="chart-area" ref={rootRef}>
      .....
    </div>
  );
};

Once we have this in place, implementing a line chart is straight forward. However to make the axes responsive, i.e. change its tick based on the available size. Pass a ratio based on width or height to the ticks method of both axes.

const { width, height } = size;

const xAxis = d3
  .axisBottom()
  .scale(xScale)
  .ticks(width / 100); // I've hard coded 100 here, you can change it based on the no:of ticks required
const yAxis = d3
  .axisLeft()
  .scale(yScale)
  .ticks(height / 50); // I've hard coded 50 here, you can change it based on the no:of ticks required

Here is the full working demo running in CodeSandbox

Hope you enjoyed this, happy coding.

Top comments (0)