본문 바로가기
Vue.js

[Vue.js] 17. use chart.js event and label plugin listeners

by 청양호박이 2021. 4. 1.

이번 시간에는 vue-chartjs를 통해서 그린 chart에 대해서 마우스를 올렸을 때, tooltips로 자동제공하는 정보가 아닌...

마우스 click이나 기타 event(이벤트)를 발생시켜서 원하는 동작을 하게하는 방법에 대해서 알아보겠습니다. 

 

 

저같은 경우에는 위의 그림과 같이 그려진 chart의 dataset중 한개의 특정 data를 선택하여 click을 하게되면, 해당 data와 관련된 다른 정보를 보여주거나, 다른 기능을 추가로 제공하고자 했었습니다. 따라서 그것이 가능하기위한 기능을 추가해야 했는데... 그게 바로 아래의 2가지 방법입니다. 

 

그럼 각 방법에 대해서 알아보도록 하겠습니다. 

 

 

1. chart.js Events


chart.js의 docs를 살펴보면, General > Interactions > Events 에 chart내 특정 영역에 특정 동작을 할 때 event가 발생한다고 되어있습니다. 

 

  • onHover - 마우스를 해당 영역에 올렸을 때, 발생함
  • onClick - 마우스로 해당 영역을 클릭했을 때, 발생함

 

이렇게 2가지 event가 발생합니다. 그렇다면, 사용을 해 보도록 하겠습니다. chart.js의 onClick event는 options에 기재해 주어야 합니다.

      options: {
        onClick: function(point, event){
          console.log('event : ', event);
          console.log('point : ', point);
        },
      },

이렇게 onClick event로 함수를 작성해 주고, 그 parameter는 point와 event가 되겠습니다. 그럼 각각 무엇을 의미하는지 console.log로 확인을 해 보겠습니다. 

[chart의 첫번째 data 영역을 onClick했을 때]

event :  
  [ChartElement]
  0: ChartElement
  $datalabels: Array(1)
  hidden: false
  _chart: Chart
  _datasetIndex: 0
  _index: 0
  _model: Object
  _options: Object
  _start: null
  _view: Object


[chart의 두번째 data 영역을 onClick했을 때]

event :  
  [ChartElement]
  0: ChartElement
  $datalabels: Array(1)
  hidden: false
  _chart: Chart
  _datasetIndex: 0
  _index: 1
  _model: Object
  _options: Object
  _start: null
  _view: Object

우선 event 부분입니다. chart에서 첫번째 data영역과 두번째 data영역을 클릭했을대 결과입니다. event 내 대부분의 인자값을 동일한 반면에, _index가 서로 다르고 각 data영역의 순번대로 값이 표현되고 있습니다. 나중에 해당부분으로 선택한 부분을 확인하여 차별적인 무언가를 할 수 있어 보입니다.

 

사용방식은 아무래도 이런 형식이 되겠죠??

if(event[0]['_index'] == 0) { ..... }

 

다음으로는 point부분을 확인해 보겠습니다. 

point :  
  MouseEvent {isTrusted: true, screenX: 423, screenY: 289, clientX: 423, clientY: 218, …}

이건... 단순히 진짜 mouse의 event가 발생한 위치나 기타 정보를 제공하는 parameter입니다. 

 

 

2. chartjs-plugin-datalabels Events Listeners


기본적으로 chart의 data영역에 대해서 chart.js에서 event를 제공하지만, 기존에 설치를 추가로 했던 plugin에서도 해당 event listener를 제공합니다. 총 3가지의 event listener를 제공하며, 사용방법은 간단합니다.

listeners: {
  enter: function(context) {
  	console.log('enter', context);
  },
  leave: function(context) {
  	console.log('leave', context);
  },
  click: function(context) {
  	console.log('click', context);
  }
},

하지만 chart.js에서 제공하는 부분과 다른점이 있습니다. 

 

  • chart.js의 event - 해당 data에 해당하는 chart 도표 및 datalabel 중 어디에서 동작해도 event가 발생함
  • chart.js-plugin-datalabels의 event listeners - 해당 data의 datalabel 위에서 동작해야 event가 발생함
enter 
  {…}
  active: false
  chart: Chart
  dataIndex: 0
  dataset: Object
  datasetIndex: 0
  
leave 
  {…}
  active: false
  chart: Chart
  dataIndex: 0
  dataset: Object
  datasetIndex: 0

click 
  {…}
  active: false
  chart: Chart
  dataIndex: 0
  dataset: Object
  datasetIndex: 0

여기서는 dataIndex가 event가 발생한 data의 위치를 알려주는 parameter 입니다.

 

 

3. 사용 주의사항


해당 이벤트들을 사용할 때, 주의할 점이 있습니다. 현재 chart.js는 child component를 제작해서, parent component에서 prop로 chartData와 options를 포함해서 데이터를 전달해 주고 있습니다. 그렇다면, options에 포함된 event 관련 부분도 child component로 전달되서 해당 component에서 동작할 것이기 때문에 onClick등 이벤트로 발생한 point 및 event parameter에 대해서 parent component로 전달해야 하지 않을까 라고 생각할 수 있습니다. 

 

[this.$emit 을 통한 결과 전송]

<doughnut-test :chart-data="doughnutCollection" :options="doughnutOptions" @trans="checkIt(event)"></doughnut-test>


onClick: function(point, event){
  console.log('event : ', event);
  console.log('point : ', point);
  this.$emit('trans', event);
},


checkIt(event) {
  console.log(event);
},

우선 필요한 부분문 발췌해서 적었습니다. 우선 chart option에 onClick event에 parent component로 값을 전송하기 위해서 this.$emit을 작성합니다. 

 

그 다음에는 parent component에서 해당 emit의 이름으로 @이름 을 작성해 줍니다. 그리고, 그 결과를 checkIt( )함수도 전달해 줍니다. 이것이 보통의 부모 자식간 component의 data trans방식입니다. 하지만 아래와 같은 에러가 발생합니다.

 

[Error 발생]

ChartTestMain.vue?8863:72 Uncaught TypeError: this.$emit is not a function
    at Chart.onClick (VM111 ChartTestMain.vue:74)
    at Chart.handleEvent (Chart.js?8a4c:10230)
    at Chart.eventHandler (Chart.js?8a4c:10167)
    at listener (Chart.js?8a4c:10100)
    at HTMLCanvasElement.proxies.<computed> (Chart.js?8a4c:7830)

뚜렷한 원인을 모르겠지만...;; 이 방법으로는 전달이 불가능하다는 것을 알았습니다. 그래서 제가 사용한 방식은... 어차피 options코드도 parent component에 있으니 onClink event를 parent의 method와 매핑해 보기로 했습니다.

 

해당 구현방식은 chart.js의 onClick event와 char.js-plugin-datalabels의 event listeners와 동일합니다.

 

[매핑코드 : 성공]

doughnutOptions: {
  onClick: this.handleClickEvent,
},


methods: {
  handleClickEvent(point, event) {
    console.log('event : ', event);
    console.log('point : ', point);
  },
},

그럼 이렇게 chart의 반응형 web application에 한층 더 가까워 졌습니다.

 

- Ayotera Lab -

댓글