Vue에서 Chart.js 차트 데이터 업데이트

2021. 11. 18. 16:51Vue

차트 생성방법: https://crispypotato.tistory.com/146

 

Vue에서 Chart.js만 사용하는 방법

vue-chart.js와 같은 vue에서 chart.js를 쉽게 사용할수있는 라이브러리가 있지만 chart.js를 그대로 사용하는게 react와같은 프레임워크가 다른 곳에서도 사용하기 좋을꺼같아 chart.js만 사용하여 데이터

crispypotato.tistory.com

 

위에 링크대로 차트를 구현하고 안에 데이터값만 변경해주면 mounted 될 때 자동 적용/변경 이라고 생각을 했다.

하지만 이전 데이터가 출력이 되는 현상이 생겨 알아보니 데이터가 변경되는것을 감지해야한다.

 

순서

1. props 또는 vuex를 이용한 데이터 받아오기

 

2. let chart 변수 생성

 

3. createChart() 함수 수정

3-1. chart에 새로운 데이터 삽입 

3-2. chart.js의 destory()함수, update()함수 사용, 이유

 

4. watch 함수 사용하여 가져오는 데이터 변경 감지

5. mounted에 nextTick 설정

 

1. props 또는 vuex를 이용한 데이터 받아오기

 

*chart.js 에서는 데이터를 String으로 받기 때문에 형변환을 해주는것을 추천한다.

App.vue에서 변경되는 데이터를 firsrtData, secondData, height props로 넘겨 받아준다.

 

height는 크기 조절이기 때문에 무시해도 된다.

firsrtData : 첫 번째 데이터,

secondData : 두 번째 데이터 

 

App.vue에서 props를 보내는 코드

 

props를 이용한 데이터를 받은 BarChart.vue

 

2. let chart 변수 선언

new Chart()가 들어갈 chart 변수 선언

데이터 변경을 적용하기 위해 new Chart()로 만들어진 chart변수에 넣어주어야 한다.

let chart

import한 Chart밑에 만들어준다.

 

3. createChart() 함수 수정

new Chart()한 차트에 직접적으로 데이터를 넣어서 수정하는 함수가 만들어진다.

 

3-1. chart에 새로운 데이터 삽입 

 

let chart를 로그로 찍어 적용되는 데이터를 찾아보면

chart.data.datasets[0].data 에 적용되는데이터가 있다.

chart.data.datasets[0].data 이 부분에 props로 받은 데이터를 직접 변경해주는 코드를 작성해주면된다.

data값 변경

 

3-2. chart.js의 destory()함수, update()함수 사용, 이유

 

chart에 props 데이터를 변경해주고 update()함수를 실행해야 적용이된다.

마지막에 chart.update()를 넣어준다.

update()

update()를 해도 동일한 ID를 사용한다며 에러가 나올때가 있다.

그래서 chart가 있으면 삭제를 해주어야 하는데 맨 처음 chart에 데이터가 있는지 확인하고 그 후에 destroy()함수를 실행 시켜주어야 한다.

 

chart 확인 후 destory()

 

4. watch 함수 사용하여 가져오는 데이터 변경 감지

vue에 watch를 사용하여 props에서 설정한 데이터가 변경이 생기면 함수가 실행되도록 한다.

watch()함수

5. mounted에 nextTick 설정

mounted에 nextTick을 설정하여 컴포넌트가 전부 mounted된 후에 화면에 띄어 줄수있게 설정한다.

 

 

최종 코드

<template>
  <div>
    <canvas
      ref="barChart"
      :height="height"
    />
  </div>
</template>

<script>
import { Chart, registerables } from 'chart.js'
Chart.register(...registerables)
let chart 
export default {
  props:{
    height:{
      type:String,
      required:true
    },
    firstData:{
      type:String,
      required:true
    },
    secondData:{
      type:String,
      required:true
    }
  },
  data:() => ({
    chartData: {
      labels: [ 'firstData', 'secondData' ],
      datasets: [{
        data:[],
        backgroundColor: [
          'rgba(255, 99, 132, 0.2)',
          'rgba(54, 162, 235, 0.2)',
        ],
        borderColor: [
          'rgba(255, 99, 132, 1)',
          'rgba(54, 162, 235, 1)',
        ],
        borderWidth: 1
      }]
    },
    options: {
      scales: {
        y: {
          beginAtZero: true
        }
      }
    }
  }),
  watch:{
    firstData(){
      this.createChart()
    },
    secondData(){
      this.createChart()
    },
    deep: true
  },
  async mounted(){
    this.$nextTick(function () {
      this.createChart()
    })
  },
  methods:{
    createChart(){
      if (chart !== undefined){
        chart.destroy()
      }
      chart =  new Chart(this.$refs.barChart, {
        type:'bar',
        data:this.chartData,
        options:this.options
      })
      chart.data.datasets[0].data[0] = this.firstData
      chart.data.datasets[0].data[1] = this.secondData
      chart.update()
    },
  },
}
</script>
728x90
반응형