How to build a responsive chart with React and d3.js
Most of the viz components of this gallery accept a width
and a height
property. Yet, most of the time the dimensions of the viz we're building are unknown. We just want them to fit their container. Let's build a hook
that retrieves the parent container dimension and passes it to the viz.
This density chart is responsive! try to resize your window to see how the graph fits.
-A hook to get a div's dimension
The method I use on this website to make my chart responsive uses a hook. Hooks let you use y and other React features without writing a class as explained in the doc
This hook is basically a function that checks the offsetWidth
and offsetHeight
of a ref
that is provided as input.
An event listener to the resize
event is added to the window
, to make sure the dimension is updated when the window size changes.
That's how the hook looks like:
export const useDimensions = (targetRef: React.RefObject<HTMLDivElement>) => {
const getDimensions = () => {
return {
width: targetRef.current ? targetRef.current.offsetWidth : 0,
height: targetRef.current ? targetRef.current.offsetHeight : 0
};
};
const [dimensions, setDimensions] = useState(getDimensions);
const handleResize = () => {
setDimensions(getDimensions());
};
useEffect(() => {
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
useLayoutEffect(() => {
handleResize();
}, []);
return dimensions;
}
-Using the hook
Using the useDimensions
hook described above is pretty straight-forward. You first need to create a ref
using the react useRef()
function:
const chartRef = useRef(null);
Then, pass this newly created ref
to the hook:
const chartSize = useDimensions(chartRef);
Last but not least, do not forget to pass this ref to the container you want to track. You now have an object called chartSize
here that has 2 properties, height
and width
. You can use those properties for your chart component.
return(
<div ref={chartRef}>
<MyChartComponent
height={chartSize.height}
width={chartSize.width}
</div>
)
Here is an application with a ViolinPlot component that accepts a width and a height property, becoming responsive thanks to this hook:
-Caveat
Remember that the element we are tracking needs to have a height
and a width
. Otherwise the hook will basically return nothing.
→ Container is displayed as inline
An html elemente that is displayed as inline
(display: inline;
) cannot have a width and height. span
elements are inline by default.
→ By default, a div has no height
By default, the width of a div is 100%, and its height fits its content. Which means that with no content, there is no height.
→ Width 100% is ignored, flex example
By default, the width of a div is 100%, and its height fits its content. Which means that with no content, there is no height.
→ Mind the border
Josh Comeau post about border being part of the main box.
General Knowledge
Contact
👋 Hey, I'm Yan and I'm currently working on this project!
Feedback is welcome ❤️. You can fill an issue on Github, drop me a message on Twitter, or even send me an email pasting yan.holtz.data
with gmail.com
. You can also subscribe to the newsletter to know when I publish more content!
Contact
👋 Hey, I'm Yan and I'm currently working on this project!
Feedback is welcome ❤️. You can fill an issue on Github, drop me a message on Twitter, or even send me an email pasting yan.holtz.data
with gmail.com
. You can also subscribe to the newsletter to know when I publish more content!