web-dev-qa-db-fra.com

Vue Chart.js - Le graphique ne se met pas à jour lorsque les données changent

J'utilise Vue.js et Chart.js pour dessiner un graphique. Chaque fois que j'appelle la fonction generateChart(), le graphique n'est pas mis à jour automatiquement. Lorsque je vérifie les données dans le VueDevTools, elles sont correctes mais le graphique ne les représente pas.

Fait amusant: le graphique est mis à jour lorsque je redimensionne la fenêtre.

  • Quel est le problème avec ce que je fais?
  • Comment mettre à jour le graphique chaque fois que j'appelle generateChart()?

Je pense que cela va être lié à object et array change la mise en garde de détection, mais je ne sais pas quoi faire.

https://codepen.io/anon/pen/bWRVKB?editors=101

 <el-dialog title="Chart" v-model="showGeneratedChart">
     <line-chart :chartData="dataChart"></line-chart>
</el-dialog>

 export default{
    data (){
        const self = this;
        return {
         dataChart : {
                labels : [],
                datasets: [{
                        label: 'label',
                        backgroundColor: '#FC2525',
                        data: [0, 1, 2, 3, 4],
                    }]
        }
    }
}


 generateChart() { 
     this.dataChart['labels'] = [];
     this.dataChart['datasets'] = [];

     ... compute datasets and formattedLabels

     this.dataChart['labels'] = formattedLabels;
     this.dataChart['datasets'] = datasets;
 }

LineChart.js

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

export default Line.extend({
    mixins: [mixins.reactiveProp],
    props: ["options"],
    mounted () {
        this.renderChart(this.chartData, this.options)
    }
})
15
Léo Coco

Utilisez une propriété calculée pour les données du graphique. Et au lieu d'appeler this.renderChart on watch envelopper dans une méthode et réutiliser cette méthode sur mounted et dans watch.

Vue.component("line-chart", {
  extends: VueChartJs.Line,
  props: ["data", "options"],
  mounted() {
    this.renderLineChart();
  },
  computed: {
    chartData: function() {
      return this.data;
    }
  },
  methods: {
    renderLineChart: function() {
    this.renderChart(
      {
        labels: [
          "January",
          "February",
          "March",
          "April",
          "May",
          "June",
          "July"
        ],
        datasets: [
          {
            label: "Data One",
            backgroundColor: "#f87979",
            data: this.chartData
          }
        ]
      },
      { responsive: true, maintainAspectRatio: false }
    );      
    }
  },
  watch: {
    data: function() {
      this._chart.destroy();
      //this.renderChart(this.data, this.options);
      this.renderLineChart();
    }
  }
});

var vm = new Vue({
  el: ".app",
  data: {
    message: "Hello World",
    dataChart: [10, 39, 10, 40, 39, 0, 0],
    test: [4, 4, 4, 4, 4, 4]
  },
  methods: {
    changeData: function() {
      this.dataChart = [6, 6, 3, 5, 5, 6];
    }
  }
});
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>Vue.jS Chart</title>
</head>
<body>
<div class="app">
    {{ dataChart }}
   <button v-on:click="changeData">Change data</button>
  <line-chart :data="dataChart" :options="{responsive: true, maintainAspectRatio: false}"></line-chart>
 
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.2.6/vue.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/vue-chartjs.full.min.js"></script>
</body>
</html>

Vous pouvez également faire des options une propriété calculée et si l'option ne change pas beaucoup, vous pouvez configurer les accessoires par défaut. https://vuejs.org/v2/guide/components.html#Prop-Validation

Voici un codepen de travail https://codepen.io/azs06/pen/KmqyaN?editors=101

23
azs06
watch: {
chartData: function (newData, oldData) {
  // let ctx = document.getElementById('doughnut-chart').getContext('2d')
  // console.log(ctx)
  // var chart = new Chart(ctx, {type: 'doughnut', data:, options: self.options})
  // // chart.config.data.datasets.Push(newData)
  // chart.config.options.animation = false
  // console.log(chart)
  // chart.config.data.datasets.Push(newData)
  // chart.config.optionsNoAnimation = optionsNoAnimation
  // console.log(chart.config.data.datasets.Push(newData))
  // this.dataset = newData
  // chart.update()
  // console.log('options', this.data)
  console.log('new data from watcher', newData)
  this.data.datasets[0].data = newData
  this.renderChart(this.data, this.options)
}
}

ajouter un observateur personnalisé pour mettre à jour tout graphique de graphique vue

2
Shrikant

Je n'ai jamais utilisé vue-chartjs auparavant, mais il semble que votre seul problème est que vous avez oublié de recevoir explicitement chartData comme accessoire dans votre composant graphique en ligne:

Changement

export default Line.extend({
    mixins: [mixins.reactiveProp],
    props: ["options"],
    mounted () {
        this.renderChart(this.chartData, this.options)
    }
})

avec

export default Line.extend({
    mixins: [mixins.reactiveProp],
    props: ["chartData", "options"],
    mounted () {
        this.renderChart(this.chartData, this.options)
    }
})

Aussi, soyez conscient des problèmes de réactivité vue lors du changement d'objets, cela ne fonctionnera pas:

this.dataChart['datasets'] = datasets;

vous devez faire quelque chose comme ça:

Vue.set(this.dataChart, 'datasets', datasets);

dans l'ordre Vue pour détecter les changements dans votre objet.

Plus d'informations sur la réactivité: https://vuejs.org/v2/guide/reactivity.html

Plus d'informations sur la réactivité dans les graphiques: http://vue-chartjs.org/#/home?id=reactive-data

1