Summary
As a business owner, ensuring your data displays captivatingly is crucial. Regarding web development, the two libraries that have taken up the mantle to enable you to achieve this include ReactJS and D3. These libraries have been of significant efficacy for individuals building lively, data-packed web apps. This blog post will show how D3js and React Integration can help level up your web application with incredible features and next-gen performance.
Now that we know all the aspects of D3.js let us jump to the steps to integrate D3 JS in React.
D3.js and React are both UI libraries for manipulating DOM and managing UI elements, but they work differently. However, before we integrate D3.js with React, you must ensure that you have installed Node JS version 18 or higher. If not, you can install it using nvm or PNPM.
Since the release of React 18, significant improvements have been made to the core of React JS, and `create react app` is now an old way of creating new projects.
Many advanced frameworks built on React offer routing, data fetching, code bundling, and more out of the box. Ideally, we usually require these advanced features when we work on larger datasets.
Note: Depending on your needs and product requirements, the React team recommends using frameworks like Next.js, Remix, Gatsby, and Vite.
Here, we are going with ViteJS.
Moving ahead, go to your terminal and run the following command:
Then, give a project name, select React as the framework, and choose the JavaScript variant.
Then go to the project folder and open it in your preferred code editor to start the codebase.
Let us now install D3.js.
By default, App.jsx is the main entry point rendered on the browser. If you see any existing content in App.jsx, remove it. Let’s look at a few examples.
For React JS D3 charts, we will first define variables such as margin, inner width, height, and a React ref.
const margin = { top: 20, right: 20, bottom: 20, left: 20 }; const innerWidth = width - margin.left - margin.right; const innerHeight = height - margin.top - margin.bottom; const ref = useRef();
The ref is a React reference that will be utilized to select the SVG element within the DOM.
The useEffect hook is used to run side effects within a component. In this case, it is utilized to create a bar chart when the component mounts for the first time and to update it when value changes occur to the data, width, or height props.
const xScale = d3 .scaleBand() .domain(data.map((d) => d.name)) .range([0, innerWidth]) .padding(0.1); const yScale = d3 .scaleLinear() .domain([0, d3.max(data, (d) => d.value)]) .range([innerHeight, 0]);
Within the useEffect hook, the SVG element is initially targeted using the ref. The x-scale, specifically, is configured as a band scale for discrete name values within the data.
The x-scale is frequently utilized in bar charts, where each bar corresponds to a distinct value, such as a category or name.
The y-scale allows a linear scale to represent continuous values within the data.
The domain() function establishes the input domain applied to the x-scale; it iterates through the data array and returns an array comprising the name properties.
The x-scale will have a discrete value corresponding to each unique name in the data, and the y-scale will contain the value properties from the data. Hence, the y-scale will have discrete values equivalent to the unique values present in the data.
The range() function establishes the output range for the scale.
The x-scale sets the range from 0 to innerWidth, representing the width of the chart area. The y-scale sets the range from innerHeight to 0.
This is a usual practice in D3.js for flipping the y-axis, ensuring higher values are positioned on the screen, which contrasts with the standard behavior of pixel values in web browsers.
Next, let’s create bars using Rectangle.
svg .selectAll("rect") .data(data) .enter() .append("rect") .attr("x", (d) => xScale(d.name)) .attr("y", (d) => yScale(d.value)) .attr("width", xScale.bandwidth()) .attr("height", (d) => innerHeight - yScale(d.value)) .attr("fill", "blue");
Here, the selectAll(“rect”) method identifies and selects all rectangle elements within the SVG container, and the data(data) function links the provided data to these elements.
Following this, It’s required to add the enter() method to generate a selection of elements that should be added to match the new data points.
You must use the append(“rect”) function to add a rectangle element to each new data point. The attr() function is also utilized to assign various attributes to these rectangles.
The “x” and “y” attributes, denoting the position of the rectangles, are determined using the x and y scales along with the given data.
However, the width attribute, which determines the width of the rectangles, is set based on the bandwidth of the x scale. Meanwhile, the height attribute, which defines the height of the rectangles, is determined by the inner height of the chart, the y scale, and the data. Additionally, the fill attribute, responsible for the rectangles’ color, is set to blue.
svg .append("g") .attr("transform", `translate(0,${innerHeight})`) .call(d3.axisBottom(xScale)); svg .append("g") .attr("transform", `translate(${margin.left}, 0)`) .call(d3.axisLeft(yScale));
Hire ReactJS Developers from us and leverage the true potential of D3.js and React Integration for captivating Data Visualization Features.
Next, a group element is added to the SVG container to represent the x-axis, using the attr(“transform”) function to utilize the group element’s position at the bottom of the chart. Inside this group element, the call(d3.axisBottom(xScale)) function generates the x-axis using the specified x-scale.
You can create a y-axis using a similar process but without transforming since it’s already positioned on the left side of the chart.
Meanwhile, the critical point is to add the width and height attributes of the SVG container and assign the values of the width and height props, defining the overall size of the chart.
Now that we are almost done creating a bar chart. Before we run our code, we must add a cleanup function that removes all the elements from the SVG container. This is a must because we have added a side effect.
The cleanup function is returned from a useEffect hook, meaning it executes when the component is unmounted from the DOM and before re-running the effect due to changes in dependencies.
In our scenario, it removes all elements from the SVG container before the component is unmounted or before the effect is re-run for new elements representing updated data.
Thus, the final code for the BarChart component appears as follows.
import { useRef, useEffect } from "react"; import * as d3 from "d3"; const BarChart = ({ data, width, height }) => { const margin = { top: 20, right: 20, bottom: 20, left: 20 }; const innerWidth = width - margin.left - margin.right; const innerHeight = height - margin.top - margin.bottom; const ref = useRef(); useEffect(() => { const svg = d3.select(ref.current); const xScale = d3 .scaleBand() .domain(data.map((d) => d.name)) .range([0, innerWidth]) .padding(0.1); const yScale = d3 .scaleLinear() .domain([0, d3.max(data, (d) => d.value)]) .range([innerHeight, 0]); svg .selectAll("rect") .data(data) .enter() .append("rect") .attr("x", (d) => xScale(d.name)) .attr("y", (d) => yScale(d.value)) .attr("width", xScale.bandwidth()) .attr("height", (d) => innerHeight - yScale(d.value)) .attr("fill", "blue"); svg .append("g") .attr("transform", `translate(0,${innerHeight})`) .call(d3.axisBottom(xScale)); svg .append("g") .attr("transform", `translate(${margin.left}, 0)`) .call(d3.axisLeft(yScale)); svg.attr("width", width).attr("height", height); return () => { svg.selectAll("*").remove(); }; }, [data, width, height]); return ; }; export default BarChart;
We need to use the BarChart React component in the App component. We’ll begin by importing BarChart from the components folder. Additionally, we must define an array of data to display, along with width and height as props.
import "./App.css"; import BarChart from "./components/BarChart"; function App() { return ( <> D3 Charts in React
> ); } export default App;
Now, we will generate a pie chart using the same data with D3 JS in React. This will enhance our understanding of how to utilize D3.js in an alternative manner.
Using React with D3 first, we’ll establish the variables for margins, the inner width and height of the chart, and a React reference similar to the one used for the Barchart. Additionally, we’ll define a tooltip variable to display the value of each pie element when hovered over. We’ll create a < div > element with the id=”tooltip” within the App component to do this.
Within the useEffect hook in PieChart.jsx
const arc = d3 .arc() .innerRadius(0) .outerRadius(Math.min(innerWidth, innerHeight) / 2 - 1); const pie = d3 .pie() .sort(null) .value((d) => d.value); const arcs = pie(data);
The arc constant represents a D3 arc generator. It’s set up to create arcs with an inner radius of 0, effectively creating a pie chart rather than a donut chart. The outer radius is also determined to be half the smaller dimension between innerWidth and innerHeight, ensuring that the pie fits neatly within the SVG container.
Similarly, the pie constant denotes a D3 pie layout generator. It’s configured not to sort the data (sort(null)) and to use the value property of each data object to determine the size of each slice (value((d) => d.value)).
Finally, the arcs constant is an array of arc descriptors created by passing the data array to the pie layout generator.
const g = svg .selectAll(".arc") .data(arcs) .enter() .append("g") .attr("class", "arc") .attr("transform", `translate(${innerWidth / 2},${innerHeight / 2})`);
The g constant represents a D3 selection comprising new group elements, each corresponding to an arc. Every g element is translated to the center of the SVG.
g.append("path") .attr("fill", (d, i) => d3.schemeCategory10[i]) .attr("d", arc) .on("mouseover", (event, d) => { tooltip .style("opacity", 1) .style("left", `${event.pageX}px`) .style("top", `${event.pageY}px`) .text(`Value: ${d.value}`); }) .on("mouseout", () => { tooltip.style("opacity", 0); }); g.append("text") .attr("transform", (d) => `translate(${arc.centroid(d)})`) .attr("text-anchor", "middle") .attr("dy", "0.35em") // vertically center text .text((d) => d.data.name); svg.attr("width", width).attr("height", height);
The ‘g’ elements have the path elements appended to them. These paths are filled with colors from the d3.schemeCategory10 array, and their d attribute, which describes the arc path, is set using the arc generator. We also must add event listeners for mouseover and mouseout to display and hide a tooltip.
In addition, for D3 JS in React, text elements are added to each group element. They are translated to the centroid of their corresponding arc, and their text content is set to the name property of the associated data object.
Thus, the final code for the PieChart component appears as follows.
import { useEffect, useRef } from "react"; import * as d3 from "d3"; const PieChart = ({ data, width, height }) => { const margin = { top: 20, right: 20, bottom: 20, left: 20 }; const innerWidth = width - margin.left - margin.right; const innerHeight = height - margin.top - margin.bottom; const ref = useRef(); const tooltip = d3.select("#tooltip"); useEffect(() => { const svg = d3.select(ref.current); const arc = d3 .arc() .innerRadius(0) .outerRadius(Math.min(innerWidth, innerHeight) / 2 - 1); const pie = d3 .pie() .sort(null) .value((d) => d.value); const arcs = pie(data); const g = svg .selectAll(".arc") .data(arcs) .enter() .append("g") .attr("class", "arc") .attr("transform", `translate(${innerWidth / 2},${innerHeight / 2})`); g.append("path") .attr("fill", (d, i) => d3.schemeCategory10[i]) .attr("d", arc) .on("mouseover", (event, d) => { tooltip .style("opacity", 1) .style("left", `${event.pageX}px`) .style("top", `${event.pageY}px`) .text(`Value: ${d.value}`); }) .on("mouseout", () => { tooltip.style("opacity", 0); }); g.append("text") .attr("transform", (d) => `translate(${arc.centroid(d)})`) .attr("text-anchor", "middle") .attr("dy", "0.35em") // vertically center text .text((d) => d.data.name); svg.attr("width", width).attr("height", height); return () => { svg.selectAll("*").remove(); }; }, [data, width, height]); return ; }; export default PieChart;
This blog post deeply explored the ReactJS and D3 integrations and how D3.js works with React.js applications. Mastering D3.js requires familiarizing yourself with its distinct syntax and lots of practice. However, as a business owner, if you want to understand if this can benefit your ReactJS business application, you can contact a leading React JS Development Company and get started today!
To create interactive and meaningful visualizations that are both effective and engaging, we need to manage the state and its data flow. It guarantees that updating data will prompt the correct re-renders while also allowing D3.js to respond to changes in state.
D3 JS does not have many disadvantages, but learning to visualize data takes time and effective use of D3 JS requires prior knowledge of HTML, CSS, SVG, and DOM manipulation.
Since React controls the virtual DOM, direct DOM manipulation by D3.js can lead to conflicts and unexpected behavior. You must carefully handle updates and ensure operations do not interfere with React’s rendering process. Tip: Use cleanup functions.
Performance optimization is essential when integrating D3 JS in React, especially for applications dealing with large datasets or complex visualizations. Techniques like debouncing or throttling can help mitigate performance issues by limiting the frequency of updates and calculations to some extent.
Your Success Is Guaranteed !
We accelerate the release of digital product and guaranteed their success
We Use Slack, Jira & GitHub for Accurate Deployment and Effective Communication.