본문 바로가기

프론트엔드/리액트

리액트로 도넛모양차트 하이차트, +annotation 옵션 구현

import {  useEffect, useRef } from 'react';

import styled from '@emotion/styled';
import { DashboardData } from '~/interfaces/Dashboard';
import Highcharts from 'highcharts';
import HighchartsReact from 'highcharts-react-official';


interface Props {
  items: DashboardData[];
  title: string;
  total:number;
}

function PieChart({ items, title,total }: Props) {

  const randomColors = items
    .map((item) => {
      if (item.hex === null) {
        const num = Math.floor(Math.random() * 256);
        return `rgb(${num}, ${num}, ${num})`;
      } else {
        return item.hex;
      }
    })
    .filter((color): color is string => typeof color === 'string');

  const options: Highcharts.Options = {
    credits: {
      enabled: false,
    },
    tooltip: {
      enabled:false,
      // formatter(this: Highcharts.TooltipFormatterContextObject): string {
      //   return `<b>${this.point.name}</b>: ${this.point.y}%`;
      // },
    },
   
    chart: {
      height:  320,
      width:  300, // 차트 영역의 높이를 300으로 지정
      marginLeft: 0,
      plotBorderWidth: 0,
      plotShadow: false,
    },
    title: {
      text: 
      ` <span style="font-size: 22px;">${title}<br><br>(${total} 개)</span>` 
       verticalAlign: 'middle',
       y: +10
    },

    plotOptions: {
      pie: {
        borderWidth: 0,
        dataLabels: {
          enabled: true,
          connectorColor: 'black', // 연결선 색상 설정
          connectorWidth: 1, // 연결선 너비 설정
          // 기타 옵션
          color: '#333',
          style: {
            fontWeight: 'normal',
            fontSize: '13',
            textOutline: 'none',
          },

          distance: 15,
          formatter(this: Highcharts.PointLabelObject): string | undefined {
            if (this.y !== 0) {
              return `${this.y}%<br> ${this.point?.name ?? ''}`;
            }
          },
        },
        colors: randomColors, // 색상이 없는경우 무채색 랜덤 할당
      },
    },
    series: [
      {
        type: 'pie',
        innerSize: '50%',
        data: items.map((item) => ({
          name: item.name,
          y: item.percentage,
        })),
      },
    ],
  };

  return (
    <>
      <ChartContainer width={430} height={330} ref={chartRef}>
        <HighchartsReact highcharts={Highcharts} options={options} />
      </ChartContainer>
    </>
  );
}

export default PieChart;

const ChartContainer = styled.div<{ width: number; height: number }>`
  align-item: center;
  width: ${(props) => props.width}px;
  height: ${(props) => props.height}px;
  background-color: white;
`;

아이템 들어오는 배열 예시

  1. : {rank: 1, name: '퍼플', count: 89, percentage: 30.17, hex: '#AD00FF'}
  2. : {rank: 2, name: '핑크', count: 80, percentage: 27.12, hex: '#FFA7F6'}
  3. : {rank: 3, name: '실버', count: 73, percentage: 24.75, hex: '#D7D7D7'}
  4. : {rank: 4, name: '라벤더', count: 33, percentage: 11.19, hex: '#BEB0D1'}
  5. : {rank: 5, name: '그레이', count: 9, percentage: 3.05, hex: '#BBBBBB'}