avatar

目錄
用 Chart.js 來做資料視覺化

Chart.js

Chart.js 是款好用的圖表 JavaScript library,支援折線圖(line)、長條圖(bar)、雷達圖(radar)、圓餅圖(pie & doughnut)、圓面積圖(polarArea)、氣泡圖(bubble)、分布圖(scatter),也夠將圖表混合在一起使用,也有支援動畫效果。下列就用 Vue 結合 Chart.js 來做範例。

安裝

NPM

npm install vue-chartjs chart.js --save

CDN

<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.1/Chart.min.js"></script>
<script src="https://unpkg.com/vue-chartjs/dist/vue-chartjs.min.js"></script>

使用

先建立 Chart.vue 檔,作為元件來使用。

Chart.vue

先引用

import { Line, mixins } from 'vue-chartjs'

Line 是要使用的圖表類別。

const { reactiveProp } = mixins

mixins 中的 reactiveProp 會自動建立名為 chartData 的 prop 並同時添加 watch 在這 prop 上,只要 data 改變,會自動更新圖表資料。讓我們可以更方便使用。

接下來,參考官方文件完成下列程式碼。

e.g.

Code
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
<script>
import { Line, mixins } from 'vue-chartjs'
const { reactiveProp } = mixins

export default {
extends: Line,
mixins: [reactiveProp],
data: () => ({
options: {
// RWD
responsive: true,
maintainAspectRatio: false,
// 尺度、比例
scales: {
// y軸
yAxes: [
{
ticks: {
beginAtZero: true,
stepSize: 1,
fontSize: 20,
fontColor: 'green'
}
}
]
},
legend: {
position: 'right',
align: 'start',
labels: {
fontColor: 'black',
fontSize: 16,
fontFamily: 'Microsoft YaHei',
padding: 30,
}
},
// 動畫效果
animation: {
// 持續時間
duration: 1000,
// 完成後執行
// onComplete: function() {
// alert('hi')
// }
},
}
}),
// 隨資料重複渲染畫面
mounted() {
this.chartRender()
},
methods: {
chartRender() {
this.renderChart(this.chartData, this.options)
}
}
}
</script>

建立 ChartLine.vue 檔,圖表資料部分也由此傳入 Chart.vue。通常資料來源會由外部提供,因此可以加入 loaded 資料欄位來控制加上 v-if。等資料透過非同步技術取得後,再渲染出畫面。另外可使用 computed 來改變自訂圖表樣式。

ps.記得要設定 position: ‘relative’

e.g.

ChartLine.vue

Code
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
<template>
<div>
<chart v-if="loaded" :chart-data="chartData" :styles="myStyles" />
</div>
</template>


<script>
import chart from '../components/Chart.vue'

export default {
components: {
chart
},
data: () => ({
// 處理資料非同步問題,確認有資料後,才畫圖
loaded: true,
width: 500,
chartData: {
// 位於 x 軸的各筆數據 key
labels: ['今天', '昨天', '前天','一週前'],
// 圖表
datasets: [
{
// x 軸的標籤項目
label: '排名',
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)'
],
borderColor: [
'rgba(255,99,132,1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
],
borderWidth: 5,
// 位於 y 軸對應的各筆數據 value
data: ['2', '3', '2'],
},
{
label: '排名2',
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)'
],
borderColor: [
'rgba(255,99,132,1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
],
borderWidth: 5,
data: ['1', '2', '1'],
}
]
}
}),
computed: {
myStyles () {
return {
width: `${this.width}px`,
position: 'relative'
}
}
}
}
</script>

完成圖如下:

混合圖表

若要混合圖表的話,可在圖表資料的 datasets 屬性加入 type: ‘bar’ 來顯示。

記得要按照圖表間的配合效果,例如:長條配折線、長條配氣泡…等等,不然圖表會無法顯示。

e.g.

Code
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
	...
data: () => ({
// 處理資料非同步問題,確認有資料後,才畫圖
loaded: true,
width: 500,
chartData: {
// 位於 x 軸的各筆數據 key
labels: ['今天', '昨天', '前天', '一週前'],
// 圖表
datasets: [
{
type: 'bar',
// x 軸的標籤項目
label: '排名',
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)'
],
borderColor: [
'rgba(255,99,132,1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)'
],
borderWidth: 5,
// 位於 y 軸對應的各筆數據 value
data: ['2', '3', '2']
},
{
label: '排名2',
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)'
],
borderColor: [
'rgba(255,99,132,1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)'
],
borderWidth: 5,
data: ['1', '2', '1']
}
]
}
}),
...

補充:

  1. chart-data 的格式必須遵照官方文件,為物件型態。
  2. watch 只會偵測物件本身的改變,而非其屬性的變化(更新資料時只會更新屬性資料),所以父組件在傳 chartData 給子組件時必須傳物件的複製,不然 watch 會無法偵測到 props 變化,因此需要 return 一個新的物件提供給子組件。

參考:
https://medium.com/@tiahi5914/前端筆記-在-nuxt-js-專案中使用-vue-chartjs-ca799560ba44
https://vue-chartjs.org/guide/#vue-single-file-components