555

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. <!-- https://falsy.me/d3-js-%eb%a5%bc-%ec%82%ac%ec%9a%a9%ed%95%98%ec%97%ac-%eb%8d%b0%ec%9d%b4%ed%84%b0-%ec%8b%9c%ea%b0%81%ed%99%94%ed%95%98%ea%b8%b0-2-bar-charts/ -->
  2. <!doctype html>
  3. <html lang="ko">
  4. <head>
  5. <title>D3 bar chart example</title>
  6. <script src="https://d3js.org/d3.v5.min.js"></script>
  7. </head>
  8. <body>
  9. <script>
  10. // line chart와 동일
  11. const width = 500;
  12. const height = 500;
  13. const margin = {top: 40, left: 40, bottom: 40, right: 40};
  14. const data = [
  15. {name: 'a', value: 10},
  16. {name: 'b', value: 29},
  17. {name: 'c', value: 32},
  18. {name: 'd', value: 25},
  19. {name: 'e', value: 23},
  20. {name: 'f', value: 15}
  21. ];
  22. const x = d3.scaleBand()
  23. // .scaleBand() 그래프의 막대의 반복되는 범위를 정해줍니다.
  24. .domain(data.map(d => d.name))
  25. // .domain() 각각의 막대에 순서대로 막대에 매핑합니다.
  26. .range([margin.left, width - margin.right])
  27. // 시작위치와 끝 위치로 눈금의 범위를 지정합니다.
  28. .padding(0.2);
  29. // 막대의 여백을 설정합니다.
  30. // line chart와 동일
  31. const y = d3.scaleLinear()
  32. .domain([0, d3.max(data, d => d.value)]).nice()
  33. .range([height - margin.bottom, margin.top]);
  34. // line chart와 동일
  35. const xAxis = g => g
  36. .attr('transform', `translate(0, ${height - margin.bottom})`)
  37. .call(d3.axisBottom(x)
  38. .tickSizeOuter(0));
  39. // line chart와 동일
  40. const yAxis = g => g
  41. .attr('transform', `translate(${margin.left}, 0)`)
  42. .call(d3.axisLeft(y))
  43. .call(g => g.select('.domain').remove());
  44. // line chart와 동일
  45. const svg = d3.select('body').append('svg').style('width', width).style('height', height);
  46. svg.append('g').call(xAxis);
  47. svg.append('g').call(yAxis);
  48. svg.append('g')
  49. .attr('fill', 'steelblue')
  50. .selectAll('rect').data(data).enter().append('rect')
  51. // .selectAll() | .select() 메서드는 해당 엘리먼트를 찾지만, 가상의 요소로 선택되기도 합니다.
  52. // .data() 앞에 선택된 select에 (data)배열에 Join하여 새 선택항목을 반환합니다.
  53. // DOM에 없는 선택된 엘리먼트에 각 데이터에 대한 자리의 노드를 반환합니다.
  54. // 여기까지의 코드를 간략하게 풀어보면
  55. // svg에 g 엘리먼트를 추가하고 그 안의 rect 엘리먼트를 찾습니다.
  56. // 새로 추가된 g 엘리먼트이기 때문에 그 안의 rect 엘리먼트는 없기 때문에 가상의 엘리먼트로 선택되었습니다.
  57. // .data(data)로 가상의 엘리먼트에 data 배열 데이터와 Join 되고
  58. // .enter() Join 된 데이터에 각 자리에 대한 노드를 반환하고
  59. // .append() 반환된 노드 데이터를 담고 react 엘리먼트를 추가합니다.
  60. // ex. data = [1, 2, 3, 4] 값을 가지고 있었다면 1, 2, 3, 4 데이터와 매핑된 rect 엘리먼트가 4개 추가됩니다.
  61. .attr('x', d => x(d.name))
  62. .attr('y', d => y(d.value))
  63. .attr('height', d => y(0) - y(d.value))
  64. .attr('width', x.bandwidth());
  65. // .bandwidth() 이름 그대로 막대기의 너비값을 응답합니다.
  66. // 인자값으로 명칭된 d가 svg 엘리먼트 속성 d를 의미하는 줄 알았는데, 그냥 data 값을 의미하는 듯 합니다.
  67. svg.node();
  68. </script>
  69. </body>
  70. </html>