D3의 React 프로젝트에서 사용하는 방법 ~ 그 1 ~

이 기사는 D3.js의 Advent Calendar 2016년 2일째 기사입니다.

어제는 D3는 React 프로젝트에서 다루기가 어렵다는 이야기를 했습니다만,
오늘은 여전히 ​​React 프로젝트에서 D3을 사용하고 싶은 경우에 어떻게 할 것인지를 코드 함께 써갑니다.

React의 프로젝트에서 D3를 이용하기 위해서는 다음의 3가지 방법이 있다(그 밖에도 있을지도)입니다만,
그 중 첫 번째 방법으로 시도하는 방법을 작성합니다.
  • React의 ComponentDidMount시에 DOM을 직접 내보내기
  • DOM 내보내기는 D3을 사용하지 않고 스스로 쓰고, Scale, Color, Max, Min 등의 계산이나 데이터 조작으로 이용한다.
  • jsdom을 이용한다 ※미 검증

  • React 프로젝트 만들기



    이전에 React를 프로젝트에 도입하는 경우,
    Webpack이나 Babel등을 설정할 필요가 있기 때문에, 도입 자체가 어려웠습니다만,
    이제 create-react-app 에서 쉽게 소개할 수 있습니다.



    "나중에 조금 Hello World를 할 수 있어요"라는 트윗이 흘러 왔을 때는 꽤 우케했습니다 w

    그럼 실제로 프로젝트를 만들겠습니다.
    $ npm install -g create-react-app
    $ create-react-app d3-react-example
    $ cd d3-react-example
    $ npm start
    

    http://localhost:3000 에서 브라우저에 "Welcome to React"라고 표시되면 준비 완료입니다.



    BubbleChart를 그려보세요





    여기 Bubble 차트가 v4로 작성되어 있으므로 React 프로젝트에서 그려 가고 싶습니다.

    d3.js Advent Calendar2016 「실은 React로 D3는 취급하기 어렵다」

    d3.js 설치


    $ npm install --save d3
    

    flare.csv 다운로드



    Gist에서 다운로드합니다.
    $ wget -P public/ https://gist.githubusercontent.com/mbostock/4063269/raw/acafd4305293814cdc87a403354a3583075b5b09/flare.csv

    App.js 수정



    d3을 가져오고 Render에 svg 태그를 넣습니다.
    d3은 v4에서 모듈화되어 있으므로 별도로 호출할 수도 있습니다.
    $ vim src/App.js
    
    import React, { Component } from 'react';
    import * as d3 from 'd3';
    import './App.css';
    
    class App extends Component {
    
      render() {
        return (
          <div className="App">
            <svg width="960" height="880"></svg>
          </div>
        );
      }
    }
    
    export default App;
    

    drawBubbleChart 메소드를 작성해, 기존의 소스를 그대로 복사합니다.
    그런 다음 ComponentDidMount 메서드에서 호출합니다.
    $ vim src/App.js
    
    import React, { Component } from 'react';
    import * as d3 from 'd3';
    import './App.css';
    
    class App extends Component {
    
      componentDidMount() {
        drawBubbleChart();
      }
    
      render() {
        return (
          <div className="App">
            <svg width="960" height="880"></svg>
          </div>
        );
      }
    }
    
    function drawBubbleChart() {
      var svg = d3.select("svg"),
        width = +svg.attr("width");
    
      var format = d3.format(",d");
    
      var color = d3.scaleOrdinal(d3.schemeCategory20c);
    
      var pack = d3.pack()
          .size([width, width])
          .padding(1.5);
    
      d3.csv("flare.csv", function(d) {
        d.value = +d.value;
        if (d.value) return d;
      }, function(error, classes) {
        if (error) throw error;
    
        var root = d3.hierarchy({children: classes})
            .sum(function(d) { return d.value; })
            .each(function(d) {
              if (id = d.data.id) {
                var id, i = id.lastIndexOf(".");
                d.id = id;
                d.package = id.slice(0, i);
                d.class = id.slice(i + 1);
              }
            });
    
        var node = svg.selectAll(".node")
          .data(pack(root).leaves())
          .enter().append("g")
            .attr("class", "node")
            .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
    
        node.append("circle")
            .attr("id", function(d) { return d.id; })
            .attr("r", function(d) { return d.r; })
            .style("fill", function(d) { return color(d.package); });
    
        node.append("clipPath")
            .attr("id", function(d) { return "clip-" + d.id; })
          .append("use")
            .attr("xlink:href", function(d) { return "#" + d.id; });
    
        node.append("text")
            .attr("clip-path", function(d) { return "url(#clip-" + d.id + ")"; })
          .selectAll("tspan")
          .data(function(d) { return d.class.split(/(?=[A-Z][^A-Z])/g); })
          .enter().append("tspan")
            .attr("x", 0)
            .attr("y", function(d, i, nodes) { return 13 + (i - nodes.length / 2 - 0.5) * 10; })
            .text(function(d) { return d; });
    
        node.append("title")
            .text(function(d) { return d.id + "\n" + format(d.value); });
      });
    }
    
    export default App;
    

    마지막으로 CSS를 수정합니다.
    $ vim src/App.css
    
    .App {
      text-align: center;
    }
    
    text {
      font: 10px sans-serif;
      text-anchor: middle;
    }
    

    수고하셨습니다.
    브라우저에서 http://localhost:3000을 다시 표시하면 거품형 차트가 표시됩니다.



    요약



    이 방법을 사용하면 기존 코드를 활용할 수 있으므로,
    도입이 간단합니다만, D3의 메소드로 DOM을 직접 수정하게 됩니다.
    또, 다른 DOM도 수정할 수 있어 버리기 때문에, 별로 추천할 수 없습니다.

    그 때문에, 다음의 기사에서는 방법 2의 「DOM의 내보내기는 D3를 사용하지 않고, 스스로 써, Scale이나 Color, Max, Min등의 계산이나 데이터 조작으로 이용한다」에 대해서 써 가고 싶습니다.

    계속.

    좋은 웹페이지 즐겨찾기