@riacarmin

Using

in React applications

D3.js

Agenda

0.

1.

2.

3.

Intro

D3.js 101

with React

[demo]

1

D3.js 101

What is it tho?

🤷‍♀️

[
  { item: 'apples', quantity: 20 },
  { item: 'oranges', quantity: 12 },
  { item: 'kiwis', quantity: 6 },
  { item: 'bananas', quantity: 4 },
]

[demo]

this.svg = d3
  .select(this.element)
  .append('svg')
  .attr(
  	'height',
    this.height + this.margin.top + this.margin.bottom
  )
  .attr(
  	'width',
    this.width + this.margin.left + this.margin.right
   )
  .style('font', '10px sans-serif');

this.canvas = this.svg
  .append('g')
  .attr(
    'transform',
    `translate(${this.margin.left}, ${this.margin.top})`
  );

// Set scales
// ==========================================================
const xScale = d3
  .scaleBand()
  .domain(this.data.map((d) => d.item))
  .range([0, this.width])
  .padding(0.25);

const yScale = d3
  .scaleLinear()
  .domain([0, d3.max(this.data, (d) => d.quantity)])
  .range([this.height, 0]);

const colorScale = d3
  .scaleLinear()
  .domain([0, d3.max(this.data, (d) => d.quantity)])
  .range(['#E2F5E1', '#017E54']);

// General Update Pattern
// ==========================================================

const enter = (enter) =>
    enter
        .append('rect')
        .attr('x', (d) => xScale(d.item))
        .attr('width', xScale.bandwidth)
        .attr('y', (d) => yScale(d.quantity))
        .attr('height', (d) => this.height - yScale(d.quantity))
        .attr('fill', (d) => colorScale(d.quantity));

const update = (update) => {}

const exit = (exit) => {}

this.canvas
    .selectAll('rect')
    .data(this.data)
    .join(enter, update, exit);

to VS Code…

2

…with React

React

  1. Data fetching
  2. State
  3. User interaction

D3

  1. Data mapping
  2. SVG rendering

 

<Component />

 

Architecture

 

<Chart />

 

 

chart.d3.js

 

import React, { useState, useCallback } from 'react';
import randomNumber from '../../utils/helpers/randomNumber';

import Chart from '../Chart';
import ScatterChart from './d3/scatter';

const DATA = Array.from(Array(6)).map(() => ({
  time: randomNumber(1, 20),
  points: randomNumber(0, 20),
}));

const Competition = () => {
  const [data, setData] = useState(DATA);

  return <Chart data={data} d3={ScatterChart} />
};

export default Competition;
<Component />
import React, { useEffect, useRef } from 'react';

const Chart = ({ className, data, d3: D3 }) => {

    if (!D3 || !validate(D3)) {
        return <div />;
    }
    
    const chartRef = useRef(null);
    const chartClass = useRef(null);

    // Render =================================================
    return <div className={className} ref={chartRef}></div>;
};
<Chart />

// Initialize chart svg container =================================
    
useEffect(() => {
  if (!chartRef.current) {
    return false;
  }
  chartClass.current = new D3(chartRef.current);

  return () => {
    chartClass.current.destroy();
  };
}, []);
<Chart />
export default class Chart {
  
  constructor(element) {
    this.element = element;
    this.data = null;
    this.margin = { top: 40, right: 60, bottom: 40, left: 60 };
    this.size = element ? element.getBoundingClientRect() : {};
    this.init();
  }

  get height() { … }
  get width() { … }
  init = () => { … };
  setData = (data) => { … };
  resize = (element) => { … };
  render = () => { … };
  destroy = () => { … };
}
chart.d3.js
const debouncedData = useDebounce(data, 150);

// Update chart on changes in data =========================================
useEffect(() => {
  debouncedData &&
    chartClass.current &&
    chartClass.current.setData(debouncedData);

  chartClass.current && chartClass.current.render();
}, [debouncedData]);
<Chart />

// Resize chart on window.resize ========================

const isClient = typeof window === 'object';
useEffect(() => {
  if (!isClient) {
    return false;
  }
  const handleResize = () =>
    chartClass.current.resize &&
    chartClass.current.resize(chartRef.current);

  window.addEventListener('resize', handleResize);

  return () => window.removeEventListener('resize', handleResize);
}, []);
<Chart />

to VS Code…

the end.

@riacarmin

Using d3.js

in React applications

Using D3.js with React

By Ria Carmin

Using D3.js with React

Introduction to integrating D3.js data visualization in React apps using functional components and hooks.

  • 628