Для начинающих

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})
  }
})

Пример на Сodepen.

Интеграция

Каждый тип графика, доступный в 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 по мутации массивов и объектов

Caveats Change-Detection-Caveats vm.$watch

События

Реактивные миксины вызывают события при изменении данных. Вы можете прослушивать их при помощи v:on на графике-компоненте. Доступны следующие события:

  • chart:render - если миксин выполняет полную перерисовку графика
  • chart:destroy - если миксин удаляет объект графика
  • chart:update - если миксин совершает обновление вместо полной перерисовки
  • labels:update - если были установлены новые метки
  • xlabels:update - если новые метки были установлены по оси x
  • ylabels: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 на других ресурсах: