Skip to main content

D3 Responsive Chart Scaffold

Table of Contents

Intro

Here is a scaffold for a responsive D3 chart inside a React functional component. Includes scaffold for Redux. This structure should be chart agnostic, but detects and saves container dimensions in state and reloads chart when dimensions change.

Based on knowledge we put together in these posts:

Ncoughlin: D3 React

Ncoughlin: D3 React Responsive Chart

CSS

Vital classes to fill available space and also make tooltips work if you are implementing them.

.chart-container {
width: 100%;
}

.chart-svg-container {
width: 100%;
height: 800px;

/* required for tooltip positioning */
position: relative;
}

Component

This component detects the size of the container and feeds that into the chart dynamically as width and height. It automatically re-renders the chart if the dimensions change (window is resized) and clears all previous elements before re-drawing. See post above for more details on this method.

import React, { useRef, useEffect, useState } from "react";
// libraries
import * as d3 from "d3";
// redux
import { connect } from "react-redux";

const SomeChart = (props) => {
// Element References
const svgRef = useRef(null);
const svgContainer = useRef(null); // The PARENT of the SVG

// State to track width and height of SVG Container
const [width, setWidth] = useState();
const [height, setHeight] = useState();

// calculate width and height of container
const getSvgContainerSize = () => {
const newWidth = svgContainer.current.clientWidth;
setWidth(newWidth);

const newHeight = svgContainer.current.clientHeight;
setHeight(newHeight);
};

// resizer
useEffect(() => {
// get 'width' and 'height' on render
getSvgContainerSize();
// listen for resize changes
window.addEventListener("resize", getSvgContainerSize);
// cleanup event listener
return () => window.removeEventListener("resize", getSvgContainerSize);
}, []);

// draw chart
useEffect(() => {
// D3 Code

// Dimensions
let dimensions = {
width: width,
height: height,
margins: 50,
};

dimensions.containerWidth = dimensions.width - dimensions.margins * 2;
dimensions.containerHeight = dimensions.height - dimensions.margins * 2;

// selections
const svg = d3
.select(svgRef.current)
.attr("width", dimensions.width)
.attr("height", dimensions.height);

// clear all previous content on refresh
const everything = svg.selectAll("*");
everything.remove();

const container = svg
.append("g")
.attr(
"transform",
`translate(${dimensions.margins}, ${dimensions.margins})`
);

// rest of d3 code ...

// const someElement = container.append('g')
// ...

}, [width, height]); // redraw chart if data or dimensions change

const renderContent = () => {
return (
<div className="chart-container">
<div ref={svgContainer} className="chart-svg-container">
<svg ref={svgRef} />
</div>
</div>
);
};

return <>{renderContent()}</>;
};

// map state to props
function mapState(state) {
return {};
}

// map actions to props
const mapDispatch = {};

// connect store
export default connect(mapState, mapDispatch)(SomeChart);

Recent Work

Free desktop AI Chat client, designed for developers and businesses. Unlocks advanced model settings only available in the API. Includes quality of life features like custom syntax highlighting.

Learn More
slide-6
slide-5
slide-2
slide-1
slide-3
slide-4
Technologies Used
TypeScript
Electron
React

BidBear

bidbear.io

Bidbear is a report automation tool. It downloads Amazon Seller and Advertising reports, daily, to a private database. It then merges and formats the data into beautiful, on demand, exportable performance reports.

Learn More
slide-1
slide-2
slide-5
slide-3
slide-4

Technologies Used

Front End
JavaScript
Docker
React
Redux
Vite
Next
Docusaurus
Stripe
Sentry
D3
React-Flow
TipTap
Back End
JavaScript
Python
AWS CognitoCognito
AWS API GatewayAPI Gateway
AWS LambdaLambda
AWS AthenaAthena
AWS GlueGlue
AWS Step FunctionsStep Functions
AWS SQSSQS
AWS DynamoDBDynamo DB
AWS S3S3
AWS CloudwatchCloudWatch
AWS CloudFrontCloudFront
AWS Route 53Route 53
AWS EventBridgeEventBridge