막대 구현하기

ex) 가로바 차트

import * as d3 from 'd3';

// 차트를 그리는 함수
const drawGraph = () => {
    
    // 캔버스   
    const svg = d3.select('body')
                   .append('svg') // 가상의 캔버스를 그린다
                   .attr('width', 400) // 캔버스의 넓이
                   .attr('height', 400); // 캔버스의 높이
    const data = [40, 50, 90, 100, 30, 90]; // 표현해야 할 input data

    svg
      .selectAll('rect') // 사각형 모양, 바 차트를 의미
      .data(data) // 데이터를 집어 넣고
      .enter() // 데이터를 순회한다.
      .append('rect')
      .attr('x', 10) // 도형을 그릴 x좌표의 값
      .attr('y', (data, idx) => idx * (20 + 1)) // 도형을 그릴 y좌표의 값
      .attr('width', (data) => data) // 각각의 데이터를 바 차트의 가로 길이로
      .attr('height', 20) // 바 차트의 높이는 20
      .attr('fill', 'tomato') // 도형에 색깔을 부여, default는 black
      .attr('class', 'bar-chart') // 직접 class를 부여하여 css로 처리도 가능
  }
  
  useEffect(()=>{
    drawGraph();
  },[])

ex)세로 바 차트(but 거꾸로 되어있다.)

import * as d3 from 'd3';

// 차트를 그리는 함수
const drawGraph = ()=>{
    
    // 캔버스   
    const svg = d3.select('body')
                   .append('svg') // 가상의 캔버스를 그린다
                   .attr('width', 400) // 캔버스의 넓이
                   .attr('height', 400); // 캔버스의 높이
    const data = [40, 50, 90, 50, 30, 90]; // 그래프로 나오게 될 data

    svg
      .selectAll('rect') // 사각형 모양, 바 차트를 의미
      .data(data) // 데이터를 집어 넣고
      .enter() // 데이터를 순회한다.
      .append('rect')
      .attr('x', (d, idx) => idx * (20 + 1)) // x 좌표의 위치는 인덱스번호 * (넓이 + 여백)
      .attr('width', 20) // 가로 넓이는 20 고정, 세로 바 차트
      .attr('height', (data) => data) // 높이는 각 데이터 수치만큼
      .attr('class', 'bar-chart')
      .attr('fill', 'tomato');
  }
  
  useEffect(()=>{
    drawGraph();
  },[])

y좌표의 0지점이 맨 위이고 x좌표의 0지점은 맨 왼쪽이다. 따라서 (0,0) 좌표는 맨 왼쪽 위다.

ex)세로 바 차트

import * as d3 from 'd3';

// 차트를 그리는 함수
const drawGraph = ()=>{
    
    // 캔버스   
    const svg = d3.select('body')
                   .append('svg') // 가상의 캔버스를 그린다
                   .attr('width', 400) // 캔버스의 넓이
                   .attr('height', 400); // 캔버스의 높이
    const data = [40, 50, 90, 50, 30, 90]; // 그래프로 나오게 될 data

    svg
      .selectAll('rect') // 사각형 모양, 바 차트를 의미
      .data(data) // 데이터를 집어 넣고
      .enter() // 데이터를 순회
      .append('rect')
      .attr('x', (d, idx) => idx * (20 + 1)) // x 좌표의 위치는 인덱스번호 * (넓이 + 여백)
      .attr('width', 40) // 막대의 넓이(숫자가 클수록 막대가 뚱뚱해짐)
      .attr('height', (data) => data) // 높이는 각 데이터 수치만큼
      .attr('class', 'bar-chart') // bar-chart라는 class를 부여
      .attr('fill', 'tomato'); // tomato 색깔
      .attr('y', (data) => 400 - data); 
// 400은 캔버스의 높이 이고 캔버스 높이에서 각 데이터를 뺀 값을 y좌표 시작점으로 하면 거꾸로된 막대그래프를 정상적으로 위치시킬 수 있다.
  }
  
  useEffect(()=>{
    drawGraph();
  },[])

척도 설정하기 (x축,y축)

x축 y축의 척도를 설정하고, 막대그래프를 그린다.

막대그래프 최종

import * as d3 from 'd3';

const drawGraph = () =>{
    
    // 캔버스의 틀을 잡는다.   
    const width = 400; // 넓이 400
    const height = 400; // 높이 400

    // svg 테두리 내부 여백 margin
    const margin = { top: 40, left: 40, bottom: 40, right: 40 };

    // 지정해둔 크기에 따라 캔버스를 그린다.
    const svg = d3.select('body').append('svg').attr('width', width).attr('height', height);
    
    // 그래프로 표현할 data
    const data = [
      { day: '5일전', value: 10 ,color : 'tomato'},
      { day: '4일전', value: 20 ,color : 'orange'},
      { day: '3일전', value: 30 ,color : 'blue'},
      { day: '2일전', value: 45 , color : 'yellow'},
      { day: '어제', value: 20 ,color : 'green'},
      { day: '오늘', value: 100 ,color : 'gray'},
    ];

    // 그래프의 index
    const x = d3
      .scaleBand() // 값이 문자열 : scaleBand, 숫자 : scaleLinear
      .domain(data.map((object) => object.day)) // 데이터의 day 값의 범위
      .range([margin.left, width - margin.right]); // 출력되는 범위, 캔버스내의 좌,우 여백을 제외한 값

    const y = d3
      .scaleLinear() // y축 value 값은 숫자, scaleLinear
      .domain([0, d3.max(data, (d) => d.value)]) // 데이터 범위 즉, 최소, 최대값 배열
      .range([height - margin.bottom, margin.top]); // range는 출력되는 범위, 캔버스 상, 하 여백을 제외한 값

    const xAxis = (g) => {
      return g // 각 축의 문서요소들, 이후 g container를 통해 설정한 값들이 적용.
         // transform 속성을 통해 원하는 만큼 x축을 이동, 
         // 즉, 가로 축을 설정한 바닥 여백 만큼 띄워 준다.
        .attr('transform', `translate(0, ${height - margin.bottom})`)
        // 바닥에 axisBottom 함수를 통해 x축을 생성, 
        // tickSizeOuter는 각 축에 튀어나오는 tick의 길이를 의미
        .call(d3.axisBottom(x).tickSizeOuter(0));
    };

    const yAxis = (g) =>
      g
        .attr('transform', `translate(${margin.left}, 0)`) 
        // 동일하게 원하는 만큼 여백을 이동
        // axisLeft를 통해 좌측에 y축 생성, tickValues 함수로 y축 간격을 정한다
        // tickSize를 width만큼 그려 그리드 생성.
        .call(d3.axisLeft(y).tickValues([0, 20, 40, 60, 80, 100]).tickSize(-width))
        .call((g) => g.select('.domain').remove()) // 축을 깔끔하게 지울수도 있다.
        .attr('class', 'grid'); // 이런식으로 직접 class를 부여해서 css로도 속성 부여 가능(색깔, 길이 등)
    svg.append('g').call(xAxis); // x축 index 추가
    svg.append('g').call(yAxis); // y축 index 추가

    // selectAll을 통해 존재하지 않았던 rect 사각형 도형(막대) 선택,
    // 이 후 append해서 속성, 데이터를 지정해서 최종적으로 그려준다.
    svg
      .selectAll('rect') // 막대(사각형 도형)
      .data(data) // 데이터 선택
      .enter() // 데이터를 순회
      .append('rect') 
      .attr('x', (data) => x(data.month) + x.bandwidth() / 2 - 20) 
      // 막대의 넓이의 반절(20)을 뺌으로서 막대의 중앙에 x축의 달이 나오도록 한다.
      // (막대의 중간에 1월,2월.. 등 x좌표의 index가 표기된다.)
      .attr('y', (data) => y(data.value)) // y좌표 척도 
      .attr('width', 40) // 막대(도형)의 넓이 (숫자가 커지면 막대가 뚱뚱해진다)
      .attr('height', (data) => y(0) - y(data.value)) 
      .attr('class', 'bar-chart') // 클래스를 부여하여 css, scss등으로 넓이나 색깔 등을 직접 부여 가능
      .attr('fill', (data) => data.color); // data에 미리 color를 넣어서 data마다 색깔 지정 가능
  }

useEffect(() => {
    drawGraph();
  },[])