@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

Made with Slides.com