Skip to content

A repository that demonstrates techniques while using React TypeScript and D3.js

Notifications You must be signed in to change notification settings

goatstone/react-d3

Repository files navigation

React D3

The purpose of this repository is to establish strategies that can be used while working with D3.js in the context of React.

The live website can be found here:

https://goatstone.com/react-d3/

The React website:

React (https://react.dev)

The D3 website:

D3.js (https://d3js.org)

Issues addressed:

  • Working with React and D3s' conflicting DOM manipulation.

  • Animation in React, updating graphs with new data.

  • Defining the style of the D3 graph with CSS

  • Providing the user the ability to change the graph type

Working with React and D3s' conflicting DOM manipulation

In the D3 documentation, it lays out clearly how to use the useRef hook to store the code generated from D3.

The following code summarizes the strategy demonstrated in the D3 documentation. It creates a red square. The D3 select function is passed the instance of the variable created by the React useRef hook.

import React, { useRef, useEffect } from "react";
import { select } from "d3";

const App = () => {
  const svgRef = useRef(null);

  useEffect(() => {
    const svg = select(svgRef.current)
    svg.append('rect')
      .attr('width', '300')
      .attr('height', '300')
      .attr('fill', 'red')
  }, [])

  return (
    <svg ref={svgRef} width="300" height="300">
    </svg>
  )
}

export default App;

Another strategy is to use a React useRef in an SVG element. Get an SVG node from a function that builds the D3 SVG. Set the SVG React useRef variable with appendChild. The following code demonstrates this technique. The example displays a red square.

import React, { useEffect, useRef } from 'react';
import { create } from 'd3';

const redSquare = () => {
  const svg = create('svg')
  svg.append('g')
    .append('rect')
    .attr('width', "300")
    .attr('height', "300")
    .attr('fill', 'red')

  return svg.node();
}

const App = () => {
  const svgRef = useRef(null);
  useEffect(() => {
    if (svgRef.current) {
       svgRef.current.appendChild(redSquare());
    }
  }, [])

  return (
    <svg width="300" height="300">
      <g ref={svgRef}></g>
    </svg>
  );
};

export default App;

Animation in React, updating graphs with new data

Using setInterval is a standard way to create a timer that drives an animation. The timer can be started at the initiation of the page load but a problem arises if the animation needs to be toggled on and off. In a standard web page a variable can be returned from the setInterval call that can be used later with the function clearTimeout. In React, with each refresh of the page, variables like this are thrown out. The solution is to use a useRef hook to preserve the returned variable that can be later used in a clearTimeout function. Following is the code that demonstrates this.

  // Set up the useRef that will be preserved between refreshes
  const intervalID = useRef(null);
  // Use React state to control the animation on or off state
  const [animationOn, setAnimationOn] = useState<boolean>(false);
  // Set up a useEffect that takes the animationOn React state
  useEffect(() => {
    if (!animationOn) {
      clearTimeout(intervalID.current);
    } else {
      intervalID.current = setInterval(() => {
        const newData = data.map((d) => {
          return d + Math.floor(Math.random() * 3 - 3);
        });
        setData(newData);
      }, 3000);
    }

    return () => clearTimeout(intervalID.current);
  }, [animationOn]);

Defining the style of the D3 graph with CSS

D3 generates SVG with class names. These class names can be used in CSS definitions to define the styles of the generated SVG. The following CSS can be used to style a D3 axis.

svg .tick {
  color: #333;
}
svg .domain {
  color: blue;
}

Custom SVG shapes, generated by D3 can be given custom class names. These class names can be used with the CSS key work customcolor to define the styles of these SVG shapes. Following is an example of using CSS to apply a color to a shape in D3.

The CSS definition

svg .background {
  color: #eee;
}

The D3 code

const svg = d3.create("svg")
  .append("rect")
  .attr("width", graphDimensions.width)
  .attr("height", graphDimensions.height)
  .attr("fill", "currentcolor")
  .attr("class", "background");

Providing the user the ability to change the graph type

Seeing the same data with different graph types can give insight into the given data. Following is a strategy for swapping graph types in the same area. It uses the previously mentioned appendChild method to put the D3 node into the document. In the user interface, the type of graph can be selected. When chartType is changed it triggers the useEffect and an if else statement sets the new chart node with the correct function.

const svgRef = useRef<any>(null);
const [data, setData] = useState(initData);
const [chartType, setChartType] = useState("histogram");

useEffect(() => {
  svgRef.current.innerHTML = "";
  let chartNode;
  if (chartType === "line") {
    chartNode = lineChart(data);
  } else {
    chartNode = histogram(data);
  }
  svgRef.current.appendChild(chartNode);
}, [data, chartType]);

About

A repository that demonstrates techniques while using React TypeScript and D3.js

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published