티스토리 뷰

반응형

chart.js로 구현한 그래프


얼마전 Chart.js로 그래프 작업을 하면서 겪었던 황당한 버그였는데 혼자 몇 분간 삽질하다가 구글에 검색해보니 생각보다 간단하고 명확한 이유여서 빠르게 해결할 수 있었다.

한 캔버스에서 일간, 주간, 월간 버튼을 클릭할 때 마다 다르게 보여지게 구현해야해서 하나의 변수에 그래프 데이터를 저장해두고 사용자 이벤트가 발생할 때 마다 해당 변수의  datasets 프로퍼티에 그래프 데이터를 할당해주었는데 그래프의 특정 포인트에 마우스 오버 할 때 마다 이전 데이터가 화면에 나타나는 것이다.

(예를 들어, 월간 클릭된 상태인데 처음에 로드한 일간 데이터 바뀜)

게다가 마우스를 움직이면 또 새로운 그래프로 나왔다가 왔다갔다 함...
처음엔 너무 황당한 버그라서 어디서부터 손을 대야할지도 몰랐는데, 검색하니 바로 나오더라...

내가 참고한 스택오버플로우는 여기

이전 데이터가 나오는 이유는 그래프 객체를 파괴하지 않고 계속 재할당 해줘서인데,
만약 처음에 var chartObj = new Chart(); 이렇게 할당했었다면,
chartObj.destroy()를 통해 이전 데이터를 삭제해주고 다시 할당하면 된다.

그러나 단순히 데이터만 변경하는 것이라면 굳이 destroy() 하지 않고,
config 데이터 재설정 해준뒤 chartObj.update()를 해주면 더 적은 비용으로 이전 데이터 없이 깔끔하게 업데이트가 가능하다.

(사실 업데이트 때마다 새로운 인스턴스 생성해서 할당 해줬는데 왜 이전 데이터가 남아있는것인지는 잘 모르겠다... 아시는 분 있으면 물어보고싶다... 내 생각엔 Chart.js 라이브러리 내에서 같은 캔버스에 할당되는 데이터를 조작하는 중에 이전 것을 물고있는것이 아닌가 짐작해보지만,,, 확실히는 모르겠다.)

나의 경우에는 타입에 따라서 y축의 min/max 값을 변경해줘야 했는데, 이전 객체 파괴없이 update()만 하는 경우엔 min/max 값 재설정이 안되더라...

그래서 만약 기간만 변경했을 경우 update()로, 타입을 변경했을 때는 파괴 후, 재할당 하는 식으로 작업하였다.

밑에는 실제 작업 소스 일부를 첨부하였다.

storeCtrl.chartComponent: null,
drawChart: function(type, period, list) {

        var ctx = document.getElementById("chart-area").getContext("2d");

        var config = {
            type: 'line',
            data: {
                labels: [],
                datasets: [{
                    label: type,
                    data: [],
                    fill: false,
                    borderColor: '#F00'
                }]
            },
            options: {
                responsive: true,
                title: {
                    display: true,
                    //text:'Chart.js Line Chart'
                },
                tooltips: {
                    mode: 'label'
                },
                scales: {
                    xAxes: [{
                        display: true,
                        scaleLabel: {
                            show: true,
                            labelString: 'Month'
                        }
                    }],
                    yAxes: [{
                        display: true,
                        scaleLabel: {
                            show: true,
                            labelString: 'Value'
                        },
                        ticks: {
                            suggestedMin: type == 'TEMPERATURE' ? -20 : 0,
                            suggestedMax: type == 'TEMPERATURE' ? 30 : 100
                        }
                    }]
                }
            }
        };

        if (period == 'day') {
            //1 DAY

        } else if (period == 'week') {
            //1 WEEK
        } else {
            //1 MONTH
        }

        if (storeCtrl.chartComponent == null) {
            storeCtrl.chartComponent = new Chart(ctx, config);
        } else {
            storeCtrl.chartComponent.config = config;
            storeCtrl.chartComponent.update();
        }
},



1. 페이지 로드되면 storeCtrl.chartComponent 객체를 null로 초기화 한다.
2. 서버로부터 그래프 데이터 받아오면 config변수로 그래프 데이터 셋팅.
3-1. 기간 버튼(DAY, WEEK, MONTH) 눌러서 이벤트 발생시 각 상황에 맞게 데이터 처리해주고 storeCtrl.chartComponent.update()를 통해 데이터 업로드.
3-2. 타입 버튼(온도, 습도) 눌러서 이벤트 발생시 storeCtrl.chartComponent.destroy()로 객체 파괴 및 storeCtrl.chartComponent = null 할당 후 drawChart() 함수 호출하여 new Chart()로 새로운 객체 인스턴스 할당.
(객체 파괴 및 null 할당 부분은 위 소스에서 생략되어 있다.)

반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함