creativetimofficial / ct-vue-paper-dashboard-pro

Vue Paper Dashboard PRO - made by Creative Tim
https://www.creative-tim.com/product/vue-paper-dashboard-pro
41 stars 12 forks source link

Updating chart data #49

Closed Fatflo closed 6 years ago

Fatflo commented 6 years ago

Hello, when I modify the data in this.activityChart.data (axis request inmounted event) on the Overview page, the chart is not updated. Is there a way to trigger chart update ?

Thanks, Florian

cristijora commented 6 years ago

Hello @Fatflo The charts are not reactive by default but you can change that quite easily. You can go to the ChartCard component and add a chart property to data

data() {
 return {
   chartId: 'no-id',
   $Chartist: null,
   chart: null
 }
}

Then save the initialized chart like this:

this.chart = this.$Chartist[this.chartType](chartIdQuery, this.chartData, this.chartOptions)

After that, you could simply add a watcher on chartData and update the chart reference. Chartist has an update method

watch: {
 chartData(newData) {
  this.chart.update(newData)
 }
}
Fatflo commented 6 years ago

Hi Cristi, I updated the ChartCard as follow, then in Overview I update this.activityChart.data.labels and this.activityChart.data.series during the 'mounted:' event and also multiple times using setInterval, however the chart stays empty. I know the new data are correctly copied into this.activityChart are correct because they appear in chart when I resize the window. Any idea of what's wrong ? The watch seems to be never triggered according to console logs.

 <script>
  export default {
    name: 'chart-card',
    props: {
      footerText: {
        type: String,
        default: ''
      },
      headerTitle: {
        type: String,
        default: 'Chart title'
      },
      chartType: {
        type: String,
        default: 'Line' // Line | Pie | Bar
      },
      chartOptions: {
        type: Object,
        default: () => {
          return {}
        }
      },
      chartData: {
        type: Object,
        default: () => {
          return {
            labels: [],
            series: []
          }
        }
      }
    },
    data () {
      return {
        chartId: 'no-id',
        $Chartist: null,
        chart: null
      }
    },
    watch: {
      chartData (newData) {
        console.log('WATCH')
        this.chart.update(newData)
      }
    },
    methods: {
      /***
       * Initializes the chart by merging the chart options sent via props and the default chart options
       */
      initChart () {
        var chartIdQuery = `#${this.chartId}`
        this.chart = this.$Chartist[this.chartType](chartIdQuery, this.chartData, this.chartOptions)
        console.log('initChart')
      },
      /***
       * Assigns a random id to the chart
       */
      updateChartId () {
        var currentTime = new Date().getTime().toString()
        var randomInt = this.getRandomInt(0, currentTime)
        this.chartId = `div_${randomInt}`
      },
      getRandomInt (min, max) {
        return Math.floor(Math.random() * (max - min + 1)) + min
      }
    },
    async mounted () {
      this.updateChartId()
      const Chartist = await import('chartist')
      this.$Chartist = Chartist
      this.initChart()
    }
  }
</script>
cristijora commented 6 years ago

Hey @Fatflo sorry for the really late response on this one. Most likely watch is not triggered because it's not watched with deep property. Since in your case, chart data contains both labels and series what happens is that, only series is updated and the watcher doesn't recognize this as un update because it's a nested array that changed.

Try this instead:

chartData: {
 deep: true,
 handler(newValue){
  this.chart.update(newData)
 }
}

Also there is a Version 2 of the dashboard which users Vue Chart.js and has reactivity option by default. If you don't have access to V2, let me know your username from creativetim and I will give you access to it.