그 땐 IT활동했지/그 땐 영일영 근무했지

[010/JS Library] chart.js | 범례 커스텀하기(3.7.1 version)

루이란 2022. 3. 21. 20:57
728x90

문제 상황

2022.03.20 - [그 땐 IT활동했지/그 땐 영일영 근무했지] - [010/JavaScripts] chart.js | 범례 커스텀하기(2.4.0 version)

차트를 그리고 범례까지 커스텀하는 것에 성공했다!(이전 포스팅↑) 하지만 chart.js가 옛날 버전이라 자료를 찾거나 최신 기능을 이용하기 힘들었다..

때문에 버전을 올려야 할 필요성을 느꼈고 버전을 올리니 코드도 대폭 바꿔야 했다. 버전이 올라가며 코드 작성 방식이 바뀌었기 때문이다.ㅎㅎ

그럼 chart.js 최신 버전 범례 커스텀 시작!

 

최신버전 공식문서!

https://www.chartjs.org/docs/latest/

 

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

버전 올리기
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.0/chart.min.js"></script>

👉🏻버전을 바꾸는 것 자체는 어렵지 않다. CDN script를 위와 같이 최신 버전의 것으로 바꾸면 된다!

범례 새로 쓰기

🐰코드를 새로 쓰는게 어려웠다..ㅎㅎㅠㅠ 그럼 저번 포스팅 처럼 코드를 3부분으로 나누어 보겠다.

 

1️⃣차트 실행 & 차트 데이터

window.onload = function () {
    chartDraw();
    let legendDiv = document.getElementById('legend-div');
}

let chartData = {
    labels: [
        3/13, 3/14, 3/15, 3/16, 3/17, 3/18, 3/19
    ],
    datasets: [
        { //데이터
            label: '가격1',
            fill: false,
            data: [
                620000, 620000, 620000, 620000, 620000, 620000, 620000
            ],
            pointRadius: [
                3, 3, 3, 3, 3, 3, 3
            ],
            borderColor: 'pink',
            backgroundColor: 'pink',
            borderWidth: 2
        },
        {
            label: '가격2',
            fill: false,
            data: [
                548000, 548000, 548000, 548000, 548000, 548000, 548000
            ],
            pointRadius: [
                3, 3, 3, 3, 3, 3, 3
            ],
            backgroundColor: 'skyblue',
            borderColor: 'skyblue',
            borderWidth: 2
        }
    ]
}

👉🏻window가 준비완료 되면 차트 그리는 함수를 실행한다.

👉🏻차트에 넣을 데이터이다.

 

2️⃣차트 실행 함수

let chartDraw = function () {
    let context = document.getElementById('myChart').getContext('2d');
    let lastDataIndex = chartData.datasets[0].data.length - 1;

    Chart.register(ChartDataLabels);

    window.myChart = new Chart(context, {
        type: 'line', // 차트의 형태
        data: chartData,
        options: {
            layout: {},
            plugins: {
                datalabels: {
                    color: 'black',
                    anchor: 'end',
                    clamp: true,
                    clip: true,
                    align: '-135',
                    offset: 1,//거리
                    formatter: function (value, context){
                        let result = value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
                        return result + '원'
                    },
                    display: function(context) {
                        if ( context.dataIndex === lastDataIndex ) { return 1 }
                        else { return 0 }
                    }
                },
                legend: {
                    display: false,
                },
                htmlLegend: {
                    containerID: 'legend-div',
                },
            },
            interaction: {
              intersect: false,
            },
            scales: {
                y: {
                    type: 'linear',
                    position: 'right',
                    grace: '5%',
                    grid: {
                        display: false,
                    },
                    ticks: {}
                },
                x: {
                    grid: {
                        display: false,
                    },
                    ticks: {
                        alignment: 'end',
                        color: function (ctx) {
                            if ( ctx.index === lastDataIndex ) { return '#426AE6' }
                            else { return 'black' }
                        }
                    }
                },
            }
        },
        plugins: [htmlLegendPlugin],
    });
}

👉🏻버전이 업데이트되면서 options의 plugins에 legend 속성을 설정해야 한다. 우리가 커스텀할 legend를 넣을 것 이므로 일단 'display: false'로 설정한다. 그리고 커스텀할 legend를 넣을 html 위치(해당 div의 id)를 htmlLegend 속성에 적어준다.

👉🏻그리고 마지막 줄에 plugins에 [htmlLegendPlugin]을 넣어준다. 해당 plugin은 아래에서 작성할 것이다.

 

3️⃣범례 함수

const getOrCreateLegendList = (myChart, id) => {
  const legendContainer = document.getElementById(id);
  let listContainer = legendContainer.querySelector('ul');

  if (!listContainer) {
    listContainer = document.createElement('ul');
    legendContainer.appendChild(listContainer);
  }
  return listContainer;
};

const htmlLegendPlugin = {
  id: 'htmlLegend',
  afterUpdate(chart, args, options) {
    const ul = getOrCreateLegendList(chart, options.containerID);
    // Remove old legend items
    while (ul.firstChild) {
      ul.firstChild.remove();
    }
    // Reuse the built-in legendItems generator
    const items = chart.options.plugins.legend.labels.generateLabels(chart);
        items.forEach(item => {
            let classText = ''
            if ( item.text === '가격1' ) { classText = 'max'}
            else{ classText = 'normal'}

            const li = document.createElement('div');
            li.classList.add('wrap');
            // Color box
            const boxSpan = document.createElement('span')
            boxSpan.classList.add(`box-${classText}`);
            boxSpan.style.background = item.fillStyle;
            // Text
            const textContainer = document.createElement('p');
            textContainer.classList.add(`value-${classText}`);
            const text = document.createTextNode(item.text);
            textContainer.appendChild(text);

            const helpCircle = document.createElement('img');
            helpCircle.src = '{% static 'imgs/stockList/includes/phone_list_table/help-circle.svg' %}';
            helpCircle.onclick = modalOpenClose;
            helpCircle.classList.add(`modal-${classText}-price`);
            li.appendChild(boxSpan);
            li.appendChild(textContainer);
            li.appendChild(helpCircle);
            ul.appendChild(li);
        });
  }
};

👉🏻먼저 ul 태그를 추가해주는 getOnCreateLegendList 함수를 짜준다. 

👉🏻htmlLegendPlugin 코드를 짜보자!

  1. getOnCreateLegendList함수를 실행해주고 먼저 그 안에 있는 요소를 제거해준다. 새롭게 만든 요소를 넣어주기 위함이다.
  2. 아래에서 generateLabels를 호출해 본인이 원하는 요소를 만들고 style을 지정해서 li 태그에 넣어준다.
  3. 최종적으로 이 li 태그를 ul 태그에 넣어준다.

범례 커스텀 전과 후

🐰커스텀을 잘 해 내가 원하는대로 나왔다!

728x90