본문으로 바로가기

React + D3.js (4) Bar Chart

category 📈 js 그래픽/react + d3.js 2021. 1. 18. 03:00

scaleBand

 

scaleLinear는 선형적으로 매핑합니다.

scaleBand는 명시적인 값의 범위(Band)에 값을 매핑합니다.

 

github.com/d3/d3-scale/blob/v3.2.2/README.md#band-scales

Band scales are like ordinal scales except the output range is continuous and numeric. Discrete output values are automatically computed by the scale by dividing the continuous range into uniform bands. Band scales are typically used for bar charts with an ordinal or categorical dimension. The unknown value of a band scale is effectively undefined: they do not allow implicit domain construction.

// line graph를 그리기 위한 scaleLinear
import { scaleLinear } from "d3";
const xScale = scaleLinear().domain([0, data.length - 1]).range([0, 300]);

// bar graph를 그리기 위해서 x축을 명시적으로 5ticks 할당
import { scaleBand } from "d3";
const xScale = scaleBand().domain([0, 1, 2, 3, 4]).range([0, 300]);

* 원래 0부터 시작하는데 xAxis에 ticksFormat에서 + 1씩해줘서 그렇게 보이는 것일 뿐입니다.

좌측 scaleLinear, 우측 scaleBand

보통은 index 만큼 주기위해 map을 돌립니다.

const xScale = scaleBand().domain(data.map((value, index) => index)).range([0, 300]);

 

그패르르 그릴 때는 아래와 같이 rect element를 이용하여 그려주면 됩니다.

svg
  .selectAll(".bar")
  .data(data)
  .join("rect")
  .attr("class", "bar")
  .attr("x", (value, index) => xScale(index)) // index xScale 통해 스케일링한 값을 x좌표로
  .attr("y", yScale)
  .attr("width", xScale.bandwidth()) // xScale의 bandwidth만큼 width 설정
  .attr("height", (value, index) => 150 - yScale(value)); // svg 아래에 붙이기 위해서 svg viewBox 고려해 변경

 

코드 전문을 가지고 와봤습니다.

import React, { useRef, useEffect, useState } from "react";
import { select, axisBottom, axisRight, scaleLinear, scaleBand } from "d3";

function App() {
  const [data, setData] = useState([25, 30, 45, 60, 20, 65, 75]);
  const svgRef = useRef();

  useEffect(() => {
    const svg = select(svgRef.current);

    // scale
    const xScale = scaleBand()
      .domain(data.map((value, index) => index))
      .range([0, 300])
      .padding(0.5);

    const yScale = scaleLinear().domain([0, 150]).range([150, 0]);

    // axis
    const xAxis = axisBottom(xScale).ticks(data.length);
    svg.select(".x-axis").style("transform", "translateY(150px)").call(xAxis);

    const yAxis = axisRight(yScale);
    svg.select(".y-axis").style("transform", "translateX(300px)").call(yAxis);

    svg
      .selectAll(".bar")
      .data(data)
      .join("rect")
      .attr("class", "bar")
      .attr("x", (value, index) => xScale(index)) // index xScale 통해 스케일링한 값을 x좌표로
      .attr("y", yScale)
      .attr("width", xScale.bandwidth()) // xScale의 bandwidth만큼 width 설정
      .attr("height", (value, index) => 150 - yScale(value)); // svg 아래에 붙이기 위해서 svg viewBox 고려해 변경
  }, [data]);

  return (
    <div style={{ padding: "50px" }}>
      <svg ref={svgRef}>
        <g className="x-axis" />
        <g className="y-axis" />
      </svg>
    </div>
  );
}

export default App;

 

네. 이렇게 나옵니다. 

 

 

 

 


darren, dev blog
블로그 이미지 DarrenKwonDev 님의 블로그
VISITOR 오늘 / 전체