d3-react-component

2.0.1 • Public • Published

D3-React-Component logo

Coverage Status License: MIT build status dependency count: 0 minzipped size Gitlab npm package

D3-React-Component provides a React component wrapper for any d3 visualization. The component is called "D3Chart" and the entire package is only 1.9kb gzipped!(Seriously, this README is bigger than the entire build at ~8kb)

Design Philosophies

  • [x] Should provide a single class component which can be extended to work with any existing d3 code
  • [x] Should have a dead-simple API that contains only 3 methods: Create, Update, Destroy
  • [x] Should work with d3 loaded in a script tag, just like if you weren't using react. It must not require any other d3-related react libraries to work
  • [x] Zero dependency

Installation

NPM

npm install d3-react-component

Manual

  1. Copy D3Chart.js from the /src folder of this repository into the /src folder of your react app.
  2. profit

Usage

  1. Load d3 in a script tag. (add <script src="https://d3js.org/d3.v6.min.js"></script> to your index.html file)
  2. Create a class for your chart which extends the included D3Chart class component
  3. Write your chart initialization d3 code in your charts "create" method
  4. Write your chart update d3 code in your charts "update" method
  5. If you want to run custom d3 code before the component is unmounted from the dom, write this code in your charts "destroy" method.
  6. If you do not want to run custom d3 code before the component is unmounted from the dom, do not create a "destroy" method in your chart subclass. The parent class (D3Chart) will automagically take care of properly destroying the root svg element before the component is unmounted.

Notes:

- Class must have a create method
	- Use this method to store chart-specific functions, variables, etc
 - Class must have an update method
   	 - Use this method to render the chart, update scale domains, perform enter/exit/update etc
 - Class may have an optional destroy method
 	 - Use this method to run custom d3 code before the component is unmounted from the DOM
	 - If no destroy method is present in your subclass, the parent class will take care of destroying the root svg element for you

Reasons to extend the provided Chart class (It is highly recommended that you do so)

 - Margin math is done for you and is accessible from your subclass with `this.margin`
 - Default margins are setup for you (20px default)
 - A reference to the window.d3 object is mapped to `this.d3` for your subclass

Examples

Step1: Create a subclass for your chart (extend the provided D3Chart class):

The first step is to create a class for your chart/visualization. The class that you create is required to have 2 methods, with an optional third method. Each of these methods directly maps to a phase in Reacts DOM lifecycle.

  • Create: This method is called after the canvas node has been mounted to the DOM
    • Use it to create the SVG element on the page, create your scales, and init any other d3 functions
  • Update: This method is called any time a new data prop is passed to your charts subclass
    • Use it to render your chart, perform enter/update/exit transitions, update your scale domains, etc
  • Destroy (optional method): This method is called before React unmounts the canvas node from the DOM
    • Use it if you need to clean up after yourself.

Here is a very basic example of what it looks like when you extend the provided D3Chart class. We'll call our chart "MyAwesomeChart" and we'll save it in its own file

"MyAwesomeChart.js"

import {D3Chart} from "d3-react-component" // If you used NPM
//import D3Chart from "./D3Chart.js" // If you performed a manual install

export default class MyAwesomeChart extends D3Chart {
	/**
	 * Create and store the necessary functions for your vis
	 * @param canvasNode - The DOM node that will contain your vis. Append your svg element to this!
	 * @param data - The data that was initially passed to the vis
	 * @param props - any properties that you passed to your subclass. (Except margins, we'll discuss that later...)
	 */
	create( canvasNode, data, props ){
		// Create the SVG element
		this.svg = this.d3.select( canvasNode ) // Access the d3 object with this.d3
		  .append( "svg" )
			.attr( "width", this.totalWidth ) // this.totalWidth provided by D3Chart parent class
			.attr( "height", this.totalHeight ) // this.totalHeight provided by D3Chart parent class
		  .append( "g" )
			.attr(
				"transform",
				`translate( ${this.margin.left},${this.margin.top} )` // This.margin object provided by Chart.js
			);
		// This is where you create and store your scales, axis formats, path generators, etc
	}

	/**
	 * Anytime your subclass component is updated with new data, this
	 * function is called. use it to update/transition your vis
	 * @param data - The new data
	 */
	update( data ){
		// Code to update the chart
		// This is where you update your scale domains, perform enter/exit/update etc
	}
}
  • Notice that we don't need any margin logic. Our parent class takes care of that for us by following the conventions laid out here
  • Notice that you automagically get a reference to the d3 object. Use this.d3. ( again, the parent class takes care of this for us )
  • If you chose not to extend the provided Chart class, you will have to get a reference to the d3 object yourself (typically just window.d3). You will also have to perform any margin mathematics yourself. see here

Step 2: Render your chart component

Next, you need to simply render your chart as you would any other react component

"App.js"

	import MyAwesomeChart from "./MyAwesomeChart.js"

	const data = // Retrive your data however you want. Whether that be a static svg, database query, etc
	function App(){
		return(
			<MyAwesomeChart
				id={"some_unique_id"}
				data={data}
				width={1000}
				height={500}
				leftMargin={50}
				rightMargin={20}
				topMargin={35}
				bottomMargin={20}
			/>
		);
	}
  • Note: All margins default to 0px, but we have overridden them here. These override will take effect even though your subclass does not implement any margin logic. This is take care of automatically by the D3Chart parent class
  • Note: Both width and height default to 500px. Again, the D3Chart parent class allows this to happen without you having to write any logic for it in your subclass.

Custom properties

any custom properties that you pass to your subclass component will be passed to the create method as the third parameter ( props )

App.js

	import MyAwesomeChart from "./MyAwesomeChart.js"
	function App(){
		return(
			<MyAwesomeChart
				id={"some_unique_id"}
				...
				myCustomProperty={{
					foo: "bar"
				}}
			/>
		 );
	}

MyAwesomeChart.js

import {Chart} from "d3-react-component"
export default class MyAwesomeChart extends Chart {

	create( canvasNode, data, props ){
		console.log( props )
		// Outputs { myCustomProperty : { foo: "bar" } }
		...
	}

	update( data ){...}
}

Accessing Margins, Width, and Height

Margins

You can access the margins in your chart class with this.margin. For instance, if you want to get the left margin, just use this.margin.left.

Width and Height ( minus margins )

You can access the computed width and height with this.wdith and this.height respectively. ( these values are minus margins )

Total Width and Total Height ( width and height including margins )

If you would like to access the total width or total height you can use this.totalWidth and this.totalHeight respectively. ( these values include the margins )

Refactoring An existing chart

If you have existing D3 charts, they can be quite easily refactored into a subclass of D3Chart. I have adapted this chart to a Chart class so that you can compare them. (You will find it along with its data file in the "examples" folder of the repository)

To run the example:

  1. Start by placing data.csv into the /public folder
  2. Next, Place D3Chart.js and LineChart.js in the /src folder
  3. Edit App.js as to look as follows
import React from 'react';
import './App.css';
import {D3Chart} from "d3-react-component"
import LineChart from "./LineChart.js"
function App() {
	return (
		<LineChart
			id={"LineChart"}
			data={"data.csv"}
			leftMargin={50}
			width={1000}
			height={500}
		  />
	);
}

export default App;

Package Sidebar

Install

npm i d3-react-component

Weekly Downloads

1

Version

2.0.1

License

MIT

Unpacked Size

17.9 kB

Total Files

4

Last publish

Collaborators

  • native-coder