차트는 모던 웹사이트와 어플리케이션의 중요한 부분입니다. 차트는 텍스트로 쉽게 표현할 수 없는 정보를 쉽게 전달 할 수 있도록 도와주며 일반적으로 텍스트 형태일 때는 이해하기 어려운 데이터를 이해하고 읽기 쉽게 만들어줍니다.
이 글에서는 Chart.js와 Vue.js의 도움을 받아 다양한 타입의 차트 형태로 데이터를 표현해볼 것 입니다.
Chart.js는 개발자와 디자이너들에게 HTML5 canvas 엘리먼트를 이용하여 다양한 종류의 차트를 그릴 수 있도록 해주는 간단하지만 유연한 자바스크립트 차트 라이브러리입니다.
Vue.js는 우리가 차트 예제를 시연하기 위해 Chart.js와 함께 사용할 progressive 자바스크립트 프레임워크입니다. 또한 우리는 우리가 만들 데모 프로젝트를 위한 발판으로 vue-cli를 사용할 것입니다. vue-cli는 간단한 CLI(command-line-interface)로 앱이 만들어질 수 있는 다양한 템플릿을 지원하지만 우리 앱을 만들기 위해서 우리는 이 중 webpack 템플릿을 이용할 것입니다.
다양한 차트들
Vue.js에 구축 된 다양한 JavaScript 차트 라이브러리와 차트 wrapper가 있지만, 이 글은 Chart.js에 중점을 둘 것이기 때문에 Chart.js에 대한 Vue wrapper 중 vue-charts, vue-chartjs, vue-chartkick 이 세가지를 알아보도록 하겠습니다.
vue-cli로 프로젝트 준비
vue init webpack my-project
npm install chart.js chartkick hchs-vue-charts vue-chartjs vue-chartkick
팁: npm 5 이상 버전부터는 --save 플래그를 사용하지 않아도 자동으로 패키지가 package.json에 저장됩니다. 참고
이제 우리가 필요한 모든 dependencies와 Chart.js Vue wrapper를 설치했습니다. 아래 명령어로 테스트 해봅시다.
npm run dev
Routes 추가
다음으로 할 일은 각 wrapper에 대한 차트를 볼 수 있는 여러 경로를 만드는 것 입니다. 최종적으로 우리는 vue-charts wrapper로 만든 차트를 보여줄 /charts 라우트, vue-chartjs wrapper로 만든 차트를 보여줄 /chartjs, 마지막으로 vue-chartkick wrapper로 만든 차트를 보여줄 /chartkick를 만들 것 입니다. 앱의 router 폴더로 가서 index.js를 열어서 안의 내용을 아래 내용으로 교체해봅시다.
index.js
import Vue from 'vue'
import Router from 'vue-router'
import Home from '@/views/Home'
import VueChartJS from '@/views/VueChartJS'
import VueChartKick from '@/views/VueChartKick'
import VueCharts from '@/views/VueCharts'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/chartjs',
name: 'VueChartJS',
component: VueChartJS
},
{
path: '/chartkick',
name: 'VueChartKick',
component: VueChartKick
},
{
path: '/charts',
name: 'VueCharts',
component: VueCharts
}
]
})
- VueChartJS.vue
- VueChartKick.vue
- VueCharts.vue
이제 위의 코드에 대해 설명하자면,
우리는 우선 위에서 만든 Vue components에서 몇몇 파일을 import 했습니다. Components는 Vue의 가장 강력한 기능 중 하나입니다. 기본 HTML 요소를 확장하여 재사용 가능한 코드를 캡슐화하는 데 도움이됩니다. 좀 더 깊은 수준에서보면 components는 Vue 컴파일러가 behavior를 attach하는 커스텀 요소입니다.마지막 부분에는 다른 차트를 표시하는 데 필요한 여러 페이지를 제공하는 경로와 구성 요소를 정의했습니다.
Home Component
<template>
<section class="hero is-success is-fullheight">
<div class="hero-body">
<div class="container">
<h1>Creating Beautiful Charts Using Vue.js Wrappers For Chart.js</h1>
<ul>
<li><router-link to="/chartjs">vue-chartjs</router-link></li>
<li><router-link to="/charts">vue-charts</router-link></li>
<li><router-link to="/chartKick">vue-chartKick</router-link></li>
</ul>
</div>
</div>
</section>
</template>
<script>
export default {
name: 'home'
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.home {
display: flex;
align-items: center;
align-content: center;
justify-content: center;
}
h1, h2 {
font-weight: normal;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
text-decoration: underline;
}
</style>
Bulma 프레임워크 추가
<link href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.4.2/css/bulma.min.css" rel="stylesheet">
VueChart.js로 차트 만들기
- LineChart.vue
- BarChart.vue
- BubbleChart.vue
- Reactive.vue
Line Chart
<script>
//Importing Line class from the vue-chartjs wrapper
import {Line} from 'vue-chartjs'
//Exporting this so it can be used in other components
export default {
extends: Line,
data () {
return {
datacollection: {
//Data to be represented on x-axis
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July',
'August', 'September', 'October', 'November', 'December'],
datasets: [
{
label: 'Data One',
backgroundColor: '#f87979',
pointBackgroundColor: 'white',
borderWidth: 1,
pointBorderColor: '#249EBF',
//Data to be represented on y-axis
data: [40, 20, 30, 50, 90, 10, 20, 40, 50, 70, 90, 100]
}
]
},
//Chart.js options that controls the appearance of the chart
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
},
gridLines: {
display: true
}
}],
xAxes: [ {
gridLines: {
display: false
}
}]
},
legend: {
display: true
},
responsive: true,
maintainAspectRatio: false
}
}
},
mounted () {
//renderChart function renders the chart with the datacollection and options object.
this.renderChart(this.datacollection, this.options)
}
}
</script>
<template>
<section class="container">
<ul>
<li><router-link to="/">Home</router-link></li>
<li><router-link to="/chartjs">vue-chartjs</router-link></li>
<li><router-link to="/charts">vue-charts</router-link></li>
<li><router-link to="/chartKick">vue-chartKick</router-link></li>
</ul>
<h1>Demo examples of vue-chartjs</h1>
<div class="columns">
<div class="column">
<h3>Line Chart</h3>
<line-chart></line-chart>
</div>
<div class="column">
<h3>Bar Chart</h3>
<!--Bar Chart example-->
</div>
</div>
<div class="columns">
<div class="column">
<h3>Bubble Chart</h3>
<!--Bubble Chart example-->
</div>
<div class="column">
<h3>Reactivity - Live update upon change in datasets</h3>
<!--Reactivity Line Chart example-->
</div>
</div>
</section>
</template>
<script>
import LineChart from '@/components/LineChart'
import BarChart from '@/components/BarChart'
import BubbleChart from '@/components/BubbleChart'
import Reactive from '@/components/Reactive'
export default {
name: 'VueChartJS',
components: {
LineChart,
BarChart,
BubbleChart,
Reactive
},
}
</script>
<style scoped>
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
Bar Chart
<script>
//Importing Bar class from the vue-chartjs wrapper
import {Bar} from 'vue-chartjs'
//Exporting this so it can be used in other components
export default {
extends: Bar,
data() {
return {
datacollection: {
//Data to be represented on x-axis
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
datasets: [
{
label: 'Data One',
backgroundColor: '#f87979',
pointBackgroundColor: 'white',
borderWidth: 1,
pointBorderColor: '#249EBF',
//Data to be represented on y-axis
data: [40, 20, 30, 50, 90, 10, 20, 40, 50, 70, 90, 100]
}
]
},
//Chart.js options that controls the appearance of the chart
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
},
gridLines: {
display: true
}
}],
xAxes: [ {
gridLines: {
display: false
}
}]
},
legend: {
display: true
},
responsive: true,
maintainAspectRatio: false
}
}
},
mounted() {
//renderChart function renders the chart with the datacollection and options object.
this.renderChart(this.datacollection, this.options)
}
}
</script>
Bubble Chart
참고: bubble 차트는 3차원 함수(x, y, r)를 이용하여 bubble, circle을 만듭니다. x는 가로축, y는 세로축, r은 각 bubble의 크기를 표현하는데 사용됩니다.
<script>
//Importing Bubble class from the vue-chartjs wrapper
import {Bubble} from 'vue-chartjs'
//Exporting this so it can be used in other components
export default{
extends: Bubble,
data () {
return {
datacollection: {
//Data to be represented on x-axis
labels: ['Data'],
datasets: [
{
label: 'Data One',
backgroundColor: '#f87979',
pointBackgroundColor: 'white',
borderWidth: 1,
pointBorderColor: '#249EBF',
//Data to be represented on y-axis
data: [
{
x: 100,
y: 0,
r: 10
},
{
x: 60,
y: 30,
r: 20
},
{
x: 40,
y: 60,
r: 25
},
{
x: 80,
y: 80,
r: 50
},
{
x: 20,
y: 30,
r: 25
},
{
x: 0,
y: 100,
r: 5
}
]
}
]
},
//Chart.js options that controls the appearance of the chart
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
},
gridLines: {
display: true
}
}],
xAxes: [ {
gridLines: {
display: false
}
}]
},
legend: {
display: true
},
responsive: true,
maintainAspectRatio: false
}
}
},
mounted () {
//renderChart function renders the chart with the datacollection and options object.
this.renderChart(this.datacollection, this.options)
}
}
</script>
위의 코드 역시 LineChart.vue나 BarChart.vue와 유사합니다. 차이는 Line이나 Bar 클래스 대신 Bubble 클래스를 import, export한 것, datasets 객체가 x, y, z라는 다른 변수를 갖고 있는 것입니다.
Reactive Chart
- reactiveProp
- reactiveData
<script>
//Importing Bar and mixins class from the vue-chartjs wrapper
import {Bar, mixins} from 'vue-chartjs'
//Getting the reactiveProp mixin from the mixins module.
const { reactiveProp } = mixins
export default {
extends: Bar,
mixins: [reactiveProp],
data () {
return {
//Chart.js options that control the appearance of the chart
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
},
gridLines: {
display: true
}
}],
xAxes: [ {
gridLines: {
display: false
}
}]
},
legend: {
display: true
},
responsive: true,
maintainAspectRatio: false
}
}
},
mounted () {
// this.chartData is created in the mixin and contains all the data needed to build the chart.
this.renderChart(this.chartData, this.options)
}
}
</script>
<template>
<section class="container">
<ul>
<li><router-link to="/">Home</router-link></li>
<li><router-link to="/chartjs">vue-chartjs</router-link></li>
<li><router-link to="/charts">vue-charts</router-link></li>
<li><router-link to="/chartKick">vue-chartKick</router-link></li>
</ul>
<h1>Demo examples of vue-chartjs</h1>
<div class="columns">
<div class="column">
<h3>Line Chart</h3>
<line-chart></line-chart>
</div>
<div class="column">
<h3>Bar Chart</h3>
<bar-chart></bar-chart>
</div>
</div>
<div class="columns">
<div class="column">
<h3>Bubble Chart</h3>
<bubble-chart></bubble-chart>
</div>
<div class="column">
<h3>Reactivity - Live update upon change in datasets</h3>
<reactive :chart-data="datacollection"></reactive>
<button class="button is-primary" @click="fillData()">Randomize</button>
</div>
</div>
</section >
</template >
<script>
import LineChart from '@/components/LineChart'
import BarChart from '@/components/BarChart'
import BubbleChart from '@/components/BubbleChart'
import Reactive from '@/components/Reactive'
export default {
name: 'VueChartJS',
components: {
LineChart,
BarChart,
BubbleChart,
Reactive
},
data() {
return {
datacollection: null // instantiating datacollection with null
}
},
created() {
this.fillData() //anytime the vue instance is created, call the fillData() function.
},
methods: {
fillData() {
this.datacollection = {
// Data for the y-axis of the chart
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August',
'September', 'October', 'November', 'December'
],
datasets: [
{
label: 'Data One',
backgroundColor: '#f87979',
// Data for the x-axis of the chart
data: [this.getRandomInt(), this.getRandomInt(), this.getRandomInt(), this.getRandomInt(),
this.getRandomInt(), this.getRandomInt(), this.getRandomInt(), this.getRandomInt(),
this.getRandomInt(), this.getRandomInt(), this.getRandomInt(), this.getRandomInt()
]
}
]
}
},
getRandomInt() {
// JS function to generate numbers to be used for the chart
return Math.floor(Math.random() * (50 - 5 + 1)) + 5
}
}
}
</script>
위 내용을 한번 살펴봅시다. data 객체 안에서 우리는 null로 셋팅된 datacollection을 리턴해줍니다. 그리고 컴포넌트 인스턴스가 생성될 때 created 매소드에서 fillData()를 불러줍니다. fillData 함수는 methods 객체에서 생성됩니다.
method 객체에서 생성한 fillData라는 함수는 label 배열, y축에서 사용될 data 배열을 가진 datasets 배열을 포함한 datacollection 객체를 생성합니다.
마지막으로, 우리의 차트를 보여주고 reactivity가 잘 동작하는지 확인하기 위해 <!--Reactivity Line Chart example-->를
<reactive :chart-data="datacollection"></reactive>
<button class="button is-primary" @click="fillData()">Randomize</button>
vue-charts로 차트 만들기 데모
마지막 line 차트는 동적으로 데이터를 수정할 수 있습니다. 예를 들어 Label: August, Data: 88 이라는 값을 넣고 Submit하면
아래와 같이 실시간으로 그래프가 변하는 것을 확인 할 수 있습니다.
vue-chartkick로 차트 만들기 데모
위의 두가지 내용에 대해 더 알고 싶으신 분들은 아래 reference의 원문을 참조해주세요.
References
원문 - Creating Beautiful Charts Using Vue.js Wrappers for Chart.js
소스코드 - https://github.com/sitepoint-editors/vue-charts
제 글이 도움이 되셨다면 간단하게 '공감', '댓글' 부탁드립니다!
'Languages > Vue.js' 카테고리의 다른 글
Vuex 튜토리얼 코드 (0) | 2018.11.22 |
---|
댓글