起步
vue-chartjs 是 Vue 對于 Chart.js 的封裝. 你可以很簡單的創(chuàng)建可復(fù)用的圖表組件.
介紹
vue-chartjs
讓你在 Vue 中能更好的使用 Chart.js . 非常適合想要盡快啟動和運行簡單圖表的人
它抽象了一些簡單的邏輯, 但是也暴露了 Chart.js 對象, 提供了極大的靈活性.
安裝
NPM
你可以在 npm
下安裝 vue-chartjs
. 當(dāng)然, 你也需要在項目中安裝 chart.js
依賴. 因為 Chart.js
是一個 peerDependency. 這種方式你可以完全控制 Chart.js 的版本
yarn add vue-chartjs chart.js
or npm install vue-chartjs chart.js --save
::: tip
如果你使用的是 vue 1.x 版本, 請使用 legacy
標(biāo)簽. 然而, Vue 1 所支持的版本不再維護(hù)了.
yarn add vue-chartjs@legacy
:::
瀏覽器
你也可以直接在瀏覽器中使用 vue-chartjs
.
先添加 Chart.js
腳本, 再添加 vue-chartjs
腳本.
<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.js
將所有可用的圖表類型, 都導(dǎo)出為命名組件, 并可以直接導(dǎo)入它們. 這些組件都是普通的 Vue 組件, 然而, 你需要擴(kuò)展
它.
vue-chartjs
的想法是提供容易使用的組件, 并且具有最大限度的靈活性和擴(kuò)展性. 要實現(xiàn)這一點, 你需要創(chuàng)建你自己的 Chart Component 并通過 vue-chartjs
提供的組件來擴(kuò)展它.
這樣,Chart組件中的方法和邏輯就可以合并到您自己的圖表組件中.
創(chuàng)建你自己的第一個圖表
你需要引入一個基本圖表然后擴(kuò)展它. 這為處理不同數(shù)據(jù)時提供了更大的靈活性. 你可以封裝你的組件以及使用props來處理數(shù)據(jù), 或者你可以直接在組件里輸入他們. 當(dāng)然, 如果那樣做, 你的組件就無法復(fù)用了.
你可以引入整個項目或者每個模塊單獨引用. 之后你需要使用extends:
或者 mixins:[]
. 然后在 mounted()
中調(diào)用 this.renderChart()
. 這將創(chuàng)建你的圖表實例.
import { Bar } from 'vue-chartjs'
export default {
extends: Bar,
mounted () {
this.renderChart(data, options)
}
}
:::tip
你可以使用 extends: Bar
或者 mixins: [Bar]
:::
this.renderChart()
方法由 Bar
組件提供, 接收兩個對象參數(shù).第一個是你的圖表數(shù)據(jù), 第二個是配置對象.
在這個文檔中查看你需要提供的對象結(jié)構(gòu) Chart.js docs .
Vue 單文件組件
文檔中很多例子都是基于javascript文件 而不是 .vue
文件. 這是因為你大多數(shù)只需要<script>
.當(dāng)然在 .vue
文件中你也能用的很好.
Chart.vue
<script>
import { Line } from 'vue-chartjs'
export default {
extends: Line,
props: ['chartdata', 'options'],
mounted () {
this.renderChart(this.chartdata, this.options)
}
}
</script>
<style>
</style>
::: danger 不要使用<template>
標(biāo)簽
不要在你的 .vue
文件中引入 <template>
標(biāo)簽. Vue 無法 合并模板.如果你添加了一個空的 <template>
標(biāo)簽, Vue 將會從你的主鍵里獲取模板, 而不會從你 extend
中獲取, 這將導(dǎo)致頁面為空并報錯.
:::
更新 Charts
如果你修改了數(shù)據(jù)集, Chart.js 是不會提供實時更新的. 當(dāng)然, vue-chartjs
提供了兩個 mixins 來實現(xiàn).
reactiveProp
reactiveData
這兩個mixins其實實現(xiàn)的是相同的功能. 大多數(shù)時間你將會使用reactiveProp
. 它擴(kuò)展了圖表組件的邏輯, 并自動創(chuàng)建名為 chartData
的props
參數(shù), 并為這個參數(shù)添加vue watch
. 當(dāng)數(shù)據(jù)改變, 如果數(shù)據(jù)在數(shù)據(jù)集中改變, 它將調(diào)用update()
; 如果添加了新的數(shù)據(jù)集, 它將調(diào)用renderChart()
.
reactiveData
創(chuàng)建一個本地的chartData
變量, 不是props
參數(shù)! 以及創(chuàng)建一個對這個變量的 watcher
. 如果你需要單一目的的圖表, 以及在圖表組件中進(jìn)行API調(diào)用的時候, 這將非常有用.
例子
LineChart.js
import { Line, mixins } from 'vue-chartjs'
const { reactiveProp } = mixins
export default {
extends: Line,
mixins: [reactiveProp],
props: ['options'],
mounted () {
// this.chartData 在 mixin 創(chuàng)建.
// 如果你需要替換 options , 請創(chuàng)建本地的 options 對象
this.renderChart(this.chartData, this.options)
}
}
RandomChart.vue
<template>
<div class="small">
<line-chart :chart-data="datacollection"></line-chart>
<button @click="fillData()">Randomize</button>
</div>
</template>
<script>
import LineChart from './LineChart.js'
export default {
components: {
LineChart
},
data () {
return {
datacollection: null
}
},
mounted () {
this.fillData()
},
methods: {
fillData () {
this.datacollection = {
labels: [this.getRandomInt(), this.getRandomInt()],
datasets: [
{
label: 'Data One',
backgroundColor: '#f87979',
data: [this.getRandomInt(), this.getRandomInt()]
}, {
label: 'Data One',
backgroundColor: '#f87979',
data: [this.getRandomInt(), this.getRandomInt()]
}
]
}
},
getRandomInt () {
return Math.floor(Math.random() * (50 - 5 + 1)) + 5
}
}
}
</script>
<style>
.small {
max-width: 600px;
margin: 150px auto;
}
</style>
::: danger 限制
Caveats
Change-Detection-Caveats
vm.$watch
:::
事件
如果你的數(shù)據(jù)改變, 響應(yīng)式的 mixins 將會觸發(fā)事件. 你能監(jiān)聽他們通過在圖表組件上使用 v:on
. 下列是可用的事件:
-
chart:render
- 如果 mixin 執(zhí)行完全重繪 -
chart:destroy
- 如果 mixin 刪除圖表對象實例 -
chart:update
- 如果 mixin 執(zhí)行更新而不是重繪 -
labels:update
- 如果設(shè)置了新的labels -
xlabels:update
如果設(shè)置了新的xLabels -
ylabels:update
- 如果設(shè)置了新的yLabels
故障排查
響應(yīng)式系統(tǒng), 它當(dāng)前狀態(tài)是不健全的. 你將會遇到一些問題, 因為有很多用例和方式來傳遞你的數(shù)據(jù).
Options
options
對象不是響應(yīng)式的. 所以如果你動態(tài)改變圖表的配置, 他們將無法被 mixin 識別.
如果你正在使用 mixin , 你需要使用options
來傳遞你的配置. 這是非常重要的, 因為 mixin 將調(diào)用 chart.js 的 update()
方法 或者 銷毀并渲染一個新的圖表. 如果 mixin 渲染一個新的圖表, 它將調(diào)用this.renderChart(this.chartData, this.options)
.
但是如果你在mounted()
傳遞你的配置, 它們將直接被遺棄.
::: danger 錯誤的方式
import { Line, mixins } from 'vue-chartjs'
export default {
components: { Line }
mixins: [mixins.reactiveProp],
mounted () {
this.renderChart(this.chartData, {responsive: true})
}
}
:::
::: tip 正確的方式
import { Line, mixins } from 'vue-chartjs'
export default {
components: { Line }
mixins: [mixins.reactiveProp],
mounted () {
this.renderChart(this.chartData, this.options)
}
}
:::
自己的監(jiān)視器
如果你對你的數(shù)據(jù)進(jìn)行大量更改(而不是推新的數(shù)據(jù)), 那么最好的方式是創(chuàng)建自己的 watcher.
你可以自己調(diào)用 this.$data._chart.update()
或者 this.renderChart()
來實現(xiàn), 當(dāng)然這些完全取決于你自己.
一個簡單的監(jiān)視器將會是這樣:
watch: {
chartData () {
this.$data._chart.update()
}
}
例子
使用props的圖表
你的目標(biāo)因該是創(chuàng)建可復(fù)用的圖表組件. 出于這個目的, 你應(yīng)該利用 Vue.js 的props
來傳遞你的配置和圖表數(shù)據(jù). 這種方式, 圖表自己不用關(guān)心, 關(guān)于提取數(shù)據(jù), 只用來展示.
首先, 創(chuàng)建你的組件
import { Line } from 'vue-chartjs'
export default {
extends: Line,
props: {
chartdata: {
type: Object,
default: null
},
options: {
type: Object,
default: null
}
},
mounted () {
this.renderChart(this.chartdata, this.options)
}
}
然后, 你可以把你的組件添加到父組件里
<line-chart :chartdata="chartData" :options="chartOptions"/>
圖表使用本地數(shù)據(jù)
你可以直接在你自己的圖表組件里處理你的圖表數(shù)據(jù). 你只需要把它傳遞到 renderChart()
.
import { Bar } from 'vue-chartjs'
export default {
extends: Bar,
data: () => ({
chartdata: {
labels: ['January', 'February'],
datasets: [
{
label: 'Data One',
backgroundColor: '#f87979',
data: [40, 20]
}
]
},
options: {
responsive: true,
maintainAspectRatio: false
}
}),
mounted () {
this.renderChart(this.chartdata, this.options)
}
}
Chart使用API的數(shù)據(jù)
使用API獲取數(shù)據(jù)是一種常見模式. 然而, 這里有一些問題需要記住. 最常見的問題是, 你直接安裝你的圖表, 將異步API回調(diào)的數(shù)據(jù)傳遞進(jìn)去. 這種方法導(dǎo)致的問題是, chart.js 試圖去渲染你的圖表, 訪問圖表數(shù)據(jù), 但是你的API回調(diào)是異步的. 所以你圖表在你數(shù)據(jù)到達(dá)前安裝.
防止這個問題, 一個 v-if
即可.
創(chuàng)建你的圖表組件通過一個數(shù)據(jù)參數(shù)和一個配置參數(shù), 所以我們可以從一個容器組件中傳遞我們的數(shù)據(jù)和配置.
Chart.vue
import { Line } from 'vue-chartjs'
export default {
extends: Line,
props: {
chartdata: {
type: Object,
default: null
},
options: {
type: Object,
default: null
}
},
mounted () {
this.renderChart(this.chartdata, this.options)
}
}
然后創(chuàng)建一個容器組件, 用來處理你的API回調(diào)和vuex連接.
ChartContainer.vue
<template>
<div class="container">
<line-chart
v-if="loaded"
:chartdata="chartdata"
:options="options"/>
</div>
</template>
<script>
import LineChart from './Chart.vue'
export default {
name: 'LineChartContainer',
components: { LineChart },
data: () => ({
loaded: false,
chartdata: null
}),
async mounted () {
this.loaded = false
try {
const { userlist } = await fetch('/api/userlist')
this.chartdata = userlist
this.loaded = true
} catch (e) {
console.error(e)
}
}
}
</script>
Chart的動態(tài)樣式
你可以設(shè)置 responsive: true
然后傳遞到 styles 對象, 這被當(dāng)做內(nèi)聯(lián)樣式應(yīng)用于外層div. 這種方式你可以動態(tài)改變外層容器的高度和寬度, 這并不是chart.js 的默認(rèn)行為. 使用計算屬性可以很好的完成.
::: warning
你需要設(shè)置 position: relative
:::
<template>
<div>
<line-chart :styles="myStyles"/>
<button @click="increase()">Increase height</button>
</div>
</template>
<script>
export default {
data () {
return {
height: 300
}
},
methods: {
increase () {
this.height += 10
}
},
computed: {
myStyles () {
return {
height: `${this.height}px`,
position: 'relative'
}
}
}
}
</script>
自定義/新的圖表
有時候你需要擴(kuò)展Chart.js默認(rèn)的圖表. 這里有許多例子, 來教你如何擴(kuò)展和修改默認(rèn)的圖表, 或者創(chuàng)建自己的圖表類型.
在 vue-chartjs
, 你可以使用同樣的方式來做到這一點
// 1. 引入Chart.js, 你可以使用全局的圖表對象
import Chart from 'chart.js'
// 2. 引入 `generateChart()`方法創(chuàng)建vue組件.
import { generateChart } from 'vue-chartjs'
// 3. 擴(kuò)展一個默認(rèn)圖表
// http://www.chartjs.org/docs/latest/developers/charts.html
Chart.defaults.LineWithLine = Chart.defaults.line;
Chart.controllers.LineWithLine = Chart.controllers.line.extend({ /* 自定義 */})
// 4. 生成 vue-chartjs 組件
// 第一個參數(shù)是 圖表id, 第二個參數(shù)是 圖表類型.
const CustomLine = generateChart('custom-line', 'LineWithLine')
// 5. 像使用默認(rèn)的vue-chartjs圖表一樣, 擴(kuò)展自定義組件
export default {
extends: CustomLine,
mounted () {
// ....
}
}
資源
你可以在這里找到一些資源,比如關(guān)于如何使用vue-chartjs
的教程
- Using vue-chartjs with WordPress
- Create stunning Charts with Vue and Chart.js
- Let’s Build a Web App with Vue, Chart.js and an API Part I
- Let’s Build a Web App with Vue, Chart.js and an API Part II
- Build a realtime chart with VueJS and Pusher
編碼參考
Props
這里有一些vue-chartjs
提供的基本參數(shù)定義. 因為你是 extend
他們的, 所以他們是不可見的, 但是你可以覆蓋他們:
參數(shù)名 | 描述 |
---|---|
width | 圖表寬度 |
height | 圖表高度 |
chart-id | canvas的id |
css-classes | css類的字符串 |
styles | css 樣式對象 |
plugins | chartjs 插件數(shù)組 |
事件
如果 reactiveData
或者 reactiveProp
mixin 被附加, 下面事件將會被調(diào)用:
事件 | 描述 |
---|---|
chart:render |
如果 mixin 執(zhí)行完全重繪 |
chart:destroy |
如果 mixin 刪除圖表對象實例 |
chart:update |
如果 mixin 執(zhí)行更新而不是重繪 |
labels:update |
如果設(shè)置了新的labels |
xlabels:update |
如果設(shè)置了新的xLabels |
ylabels:update |
如果設(shè)置了新的yLabels |
全局方法
全局方法需要被引入才能使用.
generateChart
-
類型:
Function
-
參數(shù):
chart-id
,chart-type
- 使用:
import { generateChart } from 'vue-chartjs'
// 第一個參數(shù)是 圖表id, 第二個參數(shù)是 圖表類型.
const CustomLine = generateChart('custom-line', 'LineWithLine')
實例方法
實例方法可以在你圖表組件內(nèi)部使用.
generateLegend()
用來生成HTML說明的工具函數(shù).
-
類型:
Function
-
參數(shù):
none
- 使用:
import { Line } from 'vue-chartjs'
export default {
extends: Line,
props: ['datasets', 'options']
data: () => ({
htmlLegend: null
})
mounted () {
this.renderChart(this.datasets, this.options)
this.htmlLegend = this.generateLegend()
}
}
addPlugin
在 Chart.js 你可以定義全局和內(nèi)聯(lián)插件. 全局插件在沒有 vue-chartjs
也可以工作. 就像這個文檔Chart.js docs 描述的.
如果你需要添加內(nèi)聯(lián)插件, vue-chartjs
暴露出來了一個工具方法 addPlugin()
你可以在renderChart()
方法前調(diào)用addPlugin()
.
-
類型:
Function
-
參數(shù):
Array
插件數(shù)組 - 使用:
mounted () {
this.addPlugin({
id: 'my-plugin',
beforeInit: function (chart) {
....
}
})
}
renderChart()
創(chuàng)建一個 Chart.js 實例, 并渲染圖表
-
類型:
Function
-
參數(shù):
Chart Data
,Chart Options
- 使用:
mounted () {
this.renderChart({
labels: ['January', 'February'],
datasets: [
{
label: 'Data One',
backgroundColor: '#f87979',
data: [40, 20]
}
]},
{
responsive: true
}
)
}
Chart.js 對象
你可以在你的圖表組件里, 通過 this.$data._chart
訪問 Chart.js 對象
Canvas
你可以通過 this.$refs.canvas
訪問 canvas