Для начинающих
vue-chartjs - это обёртка для Chart.js на Vue. Вы можете леко создать переиспользуемые компоненты-графики.
Вступление
vue-chartjs
позволяет вам использовать Chart.js без излишнего шаманства с Vue. Идеально для людей, которые просто хотят получить работающие графики как можно быстрее.
Бизнес-логика абстрагируется, зато предоставляется доступ к объектам Chart.js для получения максимальной гибкости.
Установка
NPM
Вы можете установить vue-chartjs
посредством npm
. Однако, вам также нужно добавить chart.js
как зависимость для вашего проекта. Потому, что Chart.js
- это peerDependency. Таким образом вы получите полный контроль над версионированием Chart.js.
Установка посредством npm: npm install vue-chartjs chart.js --save
TIP
Если вы используете vue 1.x пожалуйста, используйте тег legacy
. Однако, помните, что Vue версии 1 больше не поддерживается.
yarn add vue-chartjs@legacy
YARN
Установка посредством yarn: yarn add vue-chartjs chart.js
Браузер
Вы также можете использовать vue-chartjs
прямо в браузере. Для этого сначала добавьте скрипт Vue, если он ещё не загружен, потом - скрипт Chart.js
, а после него - минимизированную версию скрипта vue-chartjs
.
<script src="https://unpkg.com/vue"></script>
<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>
Дальше вы можете просто зарегистрировать свой компонент:
Vue.component('line-chart', {
extends: VueChartJs.Line,
mounted () {
this.renderChart({
labels: ['Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'],
datasets: [
{
label: 'Коммиты на GitHub',
backgroundColor: '#f87979',
data: [40, 20, 12, 39, 10, 40, 39, 80, 40, 20, 12, 11]
}
]
}, {responsive: true, maintainAspectRatio: false})
}
})
Интеграция
Каждый тип графика, доступный в Chart.js
, экспортируется как именованый компонент и может быть импортирован как таковой. Эти компоненты - нормальные Vue-компоненты, однако вам необходимо расширять их.
Идея, стоящая за vue-chart.js
, состоит в том, чтобы предоставить простые в использовании компоненты, с максимумом гибкости и расширяемости. Для достижения этого, вам нужно создать ваш собственный график-компонент и расширить его предоставленными vue-chart.js
компонентами.
Таким образом, методы и логика графиков-компонентов включается в ваш график-компонент.
Создание вашего первого графика
Вам необходимо импортировать базовый компонент, а затем расширить его. Это даёт больше гибкости при работе с различными данными. Однако, ваш компонент не может быть переиспользован таким образом.
Вы можете импортировать весь пакет или каждый модуль отдельно. Потом вам нужно использовать extends:
или mixins:[]
. Далее, в хуке mounted()
, вызовите this.renderChart()
. Это создаст экземпляр вашего объекта.
import { Bar } from 'vue-chartjs'
export default {
extends: Bar,
mounted () {
this.renderChart(data, options)
}
}
TIP
Вы можете использовать или extends: Bar
или mixins: [Bar]
Метод this.renderChart()
предоставляется компонентом Bar
и принимает два параметра. Об являются objects
. Первый используется для данных вашего графика, а второй - как объект опций.
Со структурой этих объектов можете ознакомиться в официальной документации Chart.js
Однофайловые компоненты Vue
Большинство примеров в документации базируется на javascript-файлах, а не на .vue
файлах. Причиной этому является то, что в большинстве случаев вам понадобится только блок <script>
. Однако, вы можете использовать и .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>
Template-теги не объединяются
Не включайте тег <template></template>
в ваши .vue
файлы компонентов. Vue не может объединять шаблоны. И шаблон включается в миксин. Если вы добавите пустой тег шаблона в вашем компоненте, он перезапишет тот, который приходит из базового графика, и вы получите пустой экран.
Обновление графиков
Chart.js не обновляет и не перерисовывает график если новые данные были переданы. Однако, вы можете просто реализовать это сами или использовать один из двух уже реализованных миксинов:
reactiveProp
reactiveData
Оба включены в модуль mixins
и оба преследуют одну цель. В большинстве случаев вы будете использовать reactiveProp
. Этот миксин расширяет логику вашего графика-компонента и автоматически создаёт свойства chartData
и автоматически добавляет vue watch
на это свойство. При изменении данных, он или вызовет update()
, если изменились только данные внутри уже существующих datasets
, или renderChart()
, если были добавлены новые наборы данных.
reactiveData
просто создаёт локальную переменную chartData
(которая не является свойством!) и добавляет watcher. Это полезно только в том случае, если вам необходимы одноцелевые графики и вы совершаете API-вызовы внутри ваших графиков-компонентов.
Пример
LineChart.js
import { Line, mixins } from 'vue-chartjs'
const { reactiveProp } = mixins
export default {
extends: Line,
mixins: [reactiveProp],
props: ['options'],
mounted () {
// this.chartData создаётся внутри миксина.
// Если вы хотите передать опции, создайте локальный объект 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>
Ограничения Vue по мутации массивов и объектов
События
Реактивные миксины вызывают события при изменении данных. Вы можете прослушивать их при помощи v:on
на графике-компоненте. Доступны следующие события:
chart:render
- если миксин выполняет полную перерисовку графикаchart:destroy
- если миксин удаляет объект графикаchart:update
- если миксин совершает обновление вместо полной перерисовкиlabels:update
- если были установлены новые меткиxlabels:update
- если новые метки были установлены по оси xylabels:update
- если новые метки были установлены по оси y
Отлов ошибок
Система реактивности в её текущем состоянии незрелая. Вы столкнётесь с некоторыми проблемами с ней, так как существует множество путей использования и путей передачи ваших данных.
Опции
Объект options
на данный момент не является реактивным. Если вы хотите динамически измените опции графика, это не будет распозно миксином.
Если вы используете миксин, вам нужно передать опции как свойство options
. Это важно, так как миксин вызовет метод update()
из chart.js или уничтожит старый и отрисует новый график. Если миксин отрисовывает новый график, он вызывает this.renderChart(this.chartData, this.options)
.
Но если вы передаёте опции напрямую в вашем хуке mounted()
, они теряются.
Неправильно
import { Line, mixins } from 'vue-chartjs'
export default {
components: { Line }
mixins: [mixins.reactiveProp],
mounted () {
this.renderChart(this.chartData, {responsive: true})
}
}
Правильно
import { Line, mixins } from 'vue-chartjs'
export default {
components: { Line }
mixins: [mixins.reactiveProp],
mounted () {
this.renderChart(this.chartData, this.options)
}
}
Собственный watcher
Если вы часто преобразуете или изменяете данные (вместо передачи новых данных), вам лучше реализовать свой собственный watcher. Вы можете самостоятельно вызвать this.$data._chart.update()
или this.renderChart()
, в зависимости от ваших потребностей.
Простой watcher выглядит так:
watch: {
chartData () {
this.$data._chart.update()
}
}
Примеры
Графики со свойствами
Вашей целью должно быть создание переиспользуемых компонентов-графиков. Для этой цели, вам необходимо использовать свойства Vue.js для передачи опций и данных для графика. Таким образом, график сам по себе не занимается стягиванием данных, а только их отображением.
В первую очередь, создайте свой компонент:
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"/>
График с локальными данными
Вы можете передать данные напрямую в ваш график-компонент. Для этого просто передайте его в метод renderChart()
:
import { Bar } from 'vue-chartjs'
export default {
extends: Bar,
data: () => ({
chartdata: {
labels: ['Январь', 'Февраль'],
datasets: [
{
label: 'Данные 1',
backgroundColor: '#f87979',
data: [40, 20]
}
]
},
options: {
responsive: true,
maintainAspectRatio: false
}
}),
mounted () {
this.renderChart(this.chartdata, this.options)
}
}
График с данными с API
Популярной моделью использования является запрос данных с API. Однако, необходимо кое-что запомнить. Самой частой проблемой является то, что вы встраиваете график-компонент напрямую и передаёте ему данные из асинхронного API-вызова. Проблема с этим подходом состоит в том, что график отрисовывается ранее, чем приходят данные из асинхронного API-вызова.
Лучшее решение для предупреждения таких ситуаций - это использование v-if
.
Создавайте ваш график-компонент со свойствами данных и опций, чтобы вы могли передать их через компонент-контейнер:
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)
}
}
Далее создавайте компонент-контейнер, который занимается API-вызовами или 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>
График с динамическими стилями
Вы можете установить responsive: true
и передать объект стилей, который будет применён как встроенный стиль для внешнего блока div. Таким образом вы можете динамически изменять высоту и ширину внешнего контейнера, что не является поведением по умолчанию для chart.js. Лучше всего использовать для этого вычисляемые параметры.
WARNING
Вам необходимо установить 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>
Настраиваемые / новые графики
Иногда вам нужно расширить обычные графики Chart.js. Существует множество примеров, как расширить или модифицировать графики по умолчанию, или создать собственный тип графика.
В vue-chartjs
, вы можете сделать это практически таким же путём:
// 1. Импортируйте Chart.js, чтобы использовать глобальный объект Chart
import Chart from 'chart.js'
// 2. Импортируйте метод `generateChart()` для создания компонента vue
import { generateChart } from 'vue-chartjs'
// 3. Расширьте один из графиков по умолчанию
// 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
// Первый аргумент - это chart-id, второй - типа графика
const CustomLine = generateChart('custom-line', 'LineWithLine')
// 5. Расширьте компонент CustomLine так же, как вы это делаете с обычными графиками vue-chartjs
export default {
extends: CustomLine,
mounted () {
// ....
}
}
Ресурсы
Вас могут также заинтересовать руководства по использованию vue-chartjs
на других ресурсах: