[Next.js] Chart.js
본문 바로가기
더 알아보기/기능

[Next.js] Chart.js

by 은돌1113 2022. 4. 6.

 

Chart.js | Open source HTML5 Charts for your website

New in 2.0 New chart axis types Plot complex, sparse datasets on date time, logarithmic or even entirely custom scales with ease.

www.chartjs.org

 

더 알아보기

 

Chartjs tutorial with React — Nextjs with examples

Creating amazing charts with in React with Chartjs

itnext.io

 

Chart.js 시작하기

안녕하세요, 똑똑한개발자에서 프론트엔드 개발을 하고 있는 Anne입니다. 이번에 프로젝트를 하면서 차트를 그리기 위한 용도로 Chart.js를 사용하게 되었습니다. 워낙에 기능도 많고 괜히 복잡해

tech.toktokhan.dev


이전 게시물에서 말했듯이 Chart.js 라이브러리를 사용하여 도넛 차트를 구현했다.

 

 

1. Chart.js 라이브러리를 설치한다.

npm install --save react-chartjs-2 chart.js
or
yarn add react-chartjs-2 chart.js

 

2. Chart.js 파일을 생성하고, 구현하고자 하는 차트의 기존 코드를 복붙한다.

코드

더보기
import { Doughnut } from "react-chartjs-2";

const expData = {
  labels: ["A", "B", "C", "D", "F"],
  datasets: [
    {
      labels: ["A", "B", "C", "D", "F"],
      data: [20, 20, 20, 20, 20],
      borderWidth: 0, // 차트별 border CSS
      hoverBorderWidth: 0,
      backgroundColor: ["#E1E1E1", "#038CFF", "#90F9A0", "#21F2A5", "#00DCEC"],
      fill: false,
    },
  ],
};

const Chart = () => {
  return (
    <div style={{ width: "300px" }}>
      <Doughnut
        options={{
          interaction: {
            intersect: false,
            mode: "index",
          },
          legend: {
            position: "right",
          },
        }}
        data={expData}
        height={120}
      />
    </div>
  );
};

 

3. 이때 "Error: "arc" is not a registered element." 오류가 발생하는 데, 상단에 아래 import를 추가 해주면 된다.

import "chart.js/auto";
 

react-chartjs-2 with chartJs 3: Error "arc" is not a registered element

I am working on a React app where i want to display charts. I tried to use react-chartjs-2 but i can't find a way to make it work. when i try to use Pie component, I get the error: Error: "arc...

stackoverflow.com

 

4. tooltip이나 chart를 커스텀 할 때는 Chart.js 공식문서 > Samples의 예제들을 많이 참고했다.

 

 

Chart.js | Chart.js

Chart.js (opens new window) Installation You can get the latest version of Chart.js from npm (opens new window), the GitHub releases (opens new window), or use a Chart.js CDN (opens new window). Detailed installation instructions can be found on the instal

www.chartjs.org

 

전체 코드

더보기
// 공식문서 https://www.chartjs.org/docs/latest/samples/legend/html.html

import "chart.js/auto";
// 출처 https://stackoverflow.com/questions/70098392/react-chartjs-2-with-chartjs-3-error-arc-is-not-a-registered-element
import { Doughnut } from "react-chartjs-2";
// 출처 https://dipsiiiiiiiiii.com/2019/11/03/1%EC%B0%A8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-react%EC%97%90%EC%84%9C-chart-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0/

// Chart 데이터
const expData = {
  labels: ["A", "B", "C", "D", "F"],
  datasets: [
    {
      labels: ["A", "B", "C", "D", "F"],
      data: [5290500, 14103000, 4282000, 3288000, 3036500],
      borderWidth: 0, // 차트별 border CSS
      hoverBorderWidth: 0,
      backgroundColor: ["#E1E1E1", "#038CFF", "#90F9A0", "#21F2A5", "#00DCEC"],
      fill: false,
    },
  ],
};

// Chart > ToolTip 커스텀
const getOrCreateTooltip = (chart) => {
  let tooltipEl = chart.canvas.parentNode.querySelector("div");

  if (!tooltipEl) {
    tooltipEl = document.createElement("div");
    tooltipEl.style.background = "#FFFFFF 0% 0% no-repeat padding-box";
    tooltipEl.style.borderRadius = "10px";
    tooltipEl.style.color = "#000000";
    tooltipEl.style.opacity = 1;
    tooltipEl.style.pointerEvents = "none";
    tooltipEl.style.position = "absolute";
    tooltipEl.style.transform = "translate(-50%, 0)";
    tooltipEl.style.transition = "all .1s ease";

    const table = document.createElement("table");
    table.style.margin = "0px";

    tooltipEl.appendChild(table);
    chart.canvas.parentNode.appendChild(tooltipEl);
  }

  return tooltipEl;
};

const externalTooltipHandler = (context) => {
  // Tooltip Element
  const { chart, tooltip } = context;
  const tooltipEl = getOrCreateTooltip(chart);

  // Hide if no tooltip
  if (tooltip.opacity === 0) {
    tooltipEl.style.opacity = 0;
    return;
  }

  // Set Text
  if (tooltip.body) {
    const titleLines = tooltip.title || [];
    const bodyLines = tooltip.body.map((b) => b.lines);

    const tableHead = document.createElement("thead");

    titleLines.forEach((title) => {
      const tr = document.createElement("tr");
      tr.style.borderWidth = 0;

      const th = document.createElement("th");
      th.style.borderWidth = 0;
      const text = document.createTextNode(title);

      th.appendChild(text);
      tr.appendChild(th);
      tableHead.appendChild(tr);
    });

    const tableBody = document.createElement("tbody");
    bodyLines.forEach((body, i) => {
      const colors = tooltip.labelColors[i];

      const span = document.createElement("span");
      span.style.background = colors.backgroundColor;
      span.style.borderColor = colors.borderColor;
      span.style.borderWidth = "2px";
      span.style.marginRight = "10px";
      span.style.height = "10px";
      span.style.width = "10px";
      span.style.display = "inline-block";

      const tr = document.createElement("tr");
      tr.style.backgroundColor = "inherit";
      tr.style.borderWidth = 0;

      const td = document.createElement("td");
      td.style.display = "block";
      td.style.width = "100px";
      td.style.textAlign = "center";

      // tooltip text 커스텀
      const text = document.createTextNode(`${body[0].split(":")[0]}`);
      const text2 = document.createTextNode(`${body[0].split(":")[1]}원`);

      td.appendChild(span);
      td.appendChild(text);
      td.appendChild(text2);
      tr.appendChild(td);
      tableBody.appendChild(tr);
    });

    const tableRoot = tooltipEl.querySelector("table");

    // Remove old children
    while (tableRoot.firstChild) {
      tableRoot.firstChild.remove();
    }

    // Add new children
    tableRoot.appendChild(tableHead);
    tableRoot.appendChild(tableBody);
  }

  const { offsetLeft: positionX, offsetTop: positionY } = chart.canvas;

  // Display, position, and set styles for font
  tooltipEl.style.background = "#FFFFFF 0% 0% no-repeat padding-box";
  tooltipEl.style.boxShadow = "0px 0px 10px #ADADAD40";
  tooltipEl.style.borderRadius = "10px";
  tooltipEl.style.font = "normal normal normal 14px/16px Pretendard";
  tooltipEl.style.letterSpacing = "-0.35px";
  tooltipEl.style.color = "#000000";
  tooltipEl.style.opacity = 1;
  tooltipEl.style.left = positionX + tooltip.caretX + "px";
  tooltipEl.style.top = positionY + tooltip.caretY + "px";
  tooltipEl.style.font = tooltip.options.bodyFont.string;
  tooltipEl.style.padding =
    tooltip.options.padding + "px " + tooltip.options.padding + "px";
};

const Chart = () => {
  return (
    <div style={{ width: "300px" }}>
      <Doughnut
        options={{
          interaction: {
            intersect: false,
            mode: "index",
          },
          legend: {
            position: "right",
          },
          plugins: {
            // 카테고리 커스텀
            legend: {
              display: false,
            },
            // 제목 커스텀
            title: {
              display: false,
              text: "Chart.js Line Chart - External Tooltips",
            },
            // 툴팁 커스텀
            tooltip: {
              enabled: false,
              position: "nearest",
              external: externalTooltipHandler,
            },
          },
        }}
        data={expData}
        height={120}
      />
    </div>
  );
};

export default Chart;

댓글