简体   繁体   English

使用来自 api 的数据初始化 Chart.js 图表

[英]Initialize a Chart.js chart with data from an api

As I mentioned in my title I would like to initialize a Chart.js chart with an api.正如我在标题中提到的,我想用 api 初始化 Chart.js 图表。 I found tutorials but they mostly update the data after the page is rendered.我找到了教程,但它们大多在呈现页面后更新数据。 I would like to update the chart before the page is rendered.我想在页面呈现之前更新图表。 So I directly see the initialized chart without a reload.所以我直接看到初始化图表而无需重新加载。

<template>
    <h3>Stacked</h3>
    <Chart type="bar" v-if="isReady" :data="stackedData" :options="stackedOptions"/>
</template>

<script>
import axios from "axios";
import {defineComponent, ref} from 'vue';
export default {
 
    data()  {  
 
       return {
              isReady: false,
              stackedData: {
                labels: ['A', 'B', 'C', 'D'],
                datasets: [{
                    type: 'bar',
                    label: 'Something',
                    backgroundColor: '#42A5F5',
                    data: this.list_all
                }, {
                    type: 'bar',
                    label: 'Another',
                    backgroundColor: '#66BB6A',
                    data: this.list_intersection
                }]
            },
           
            stackedOptions: {
                tooltips: {
                    mode: 'index',
                    intersect: false
                },
                responsive: true,
                scales: {
                    xAxes: [{
                        stacked: true,
                    }],
                    yAxes: [{
                        stacked: true
                    }]
                }
            },
            basicOptions: null,

//---------------------------------------------------
            all:[]
            list_intersection:[],
            list_all:[]
        }    
    },

    beforeCreate() {
            let apiKaderURL = 'http://localhost:4000/apiKader';
            axios.get(apiKaderURL).then(res => {

                this.all = res.data;
                this.saveData()
                this.isReady=true;
            }).catch(error => {
                console.log(error)
            });
        },

     methods:{
       saveData: function (){
          
          for (var i in this.all){
                if(this.all[i].id==='2' ){
                    this.list_all.push(this.all[i].someNumber)
                }
                if(this.all[i].id==='8'){
                    this.list_intersection.push(this.all[i].someNumber) 
                }                     
           }
           return this.list_all && this.list_intersection
       }
    }
}
</script>


I am simply trying to get values with axios, filter them and then return them back to the data property of the chart objects so it gets initialized with these values.我只是想用 axios 获取值,过滤它们,然后将它们返回到图表对象的数据属性,以便使用这些值进行初始化。

I thought, because I call beforeCreate , it should work, because I initialize the values before rendering but the chart does not show any values.我想,因为我调用beforeCreate ,它应该可以工作,因为我在渲染之前初始化了值,但图表没有显示任何值。

I did also try to do it with vue-chartjs but I think it is not really working with Vue 3 or I did something wrong.我也尝试过使用vue-chartjs来实现,但我认为它并不能真正与 Vue 3 一起使用,或者我做错了什么。

How can I accomplish that?我怎样才能做到这一点? Thank you really much in advance.非常感谢您。

I haven't worked with Chart.js before, but I read through Installation, Integration, and Usage documentation and came up with an example that might help you (Vue 2 with Vue CLI).我之前没有使用过 Chart.js,但我通读了安装、集成和使用文档并提出了一个可能对您有所帮助的示例(带有 Vue CLI 的 Vue 2)。

I used my App.vue SFC as the parent of the child chart component ChartTest.vue.我使用我的 App.vue SFC 作为子图表组件 ChartTest.vue 的父级。 In the parent, I simulated an API call delay using a 'setTimeout' call in the 'mounted' hook.在父级中,我使用“mounted”挂钩中的“setTimeout”调用模拟了 API 调用延迟。

App.vue应用程序.vue

<template>
  <div id="app">
    <chart-test v-if="dataReady" :chartData="chartData" />
  </div>
</template>

<script>
  import ChartTest from '@/components/ChartTest'

  export default {
    name: 'App',
    components: {
      ChartTest
    },
    data() {
      return {
        chartData: [12, 19, 3, 5, 2, 3],
        dataReady: false
      }
    },
    methods: {
      getData() {
        this.dataReady = true;
      }
    },
    mounted() {
      // Simulate API call
      setTimeout(this.getData(), 2000);
    }
  }
</script>

ChartTest.vue ChartTest.vue

<template>
  <div class="chart-test">
    <h3>Chart Test</h3>
    <canvas id="my-chart" width="400" height="400" ref="chartref"></canvas>
  </div>
</template>

<script>
  import Chart from 'chart.js';

  export default {
    data() {
      return {
        myChart: null
      }
    },
    props: {
      chartData: {
        type: Array,
        required: true
      }
    },
    mounted() {
      this.myChart = new Chart(this.$refs.chartref, {
        type: 'bar',
        data: {
          labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
          datasets: [{
            label: '# of Votes',
            data: this.chartData,
            backgroundColor: [
              'rgba(255, 99, 132, 0.2)',
              'rgba(54, 162, 235, 0.2)',
              'rgba(255, 206, 86, 0.2)',
              'rgba(75, 192, 192, 0.2)',
              'rgba(153, 102, 255, 0.2)',
              'rgba(255, 159, 64, 0.2)'
            ],
            borderColor: [
              'rgba(255, 99, 132, 1)',
              'rgba(54, 162, 235, 1)',
              'rgba(255, 206, 86, 1)',
              'rgba(75, 192, 192, 1)',
              'rgba(153, 102, 255, 1)',
              'rgba(255, 159, 64, 1)'
            ],
            borderWidth: 1
          }]
        },
        options: {
          scales: {
            yAxes: [{
              ticks: {
                beginAtZero: true
              }
            }]
          }
        }
      });
    }
  }
</script>

The lifecycle hooks (like beforeCreate , etc.) don't actually delay the subsequent component lifecycle steps, even when async, they just provide an entry point in which to run code.生命周期钩子(如beforeCreate等)实际上不会延迟后续组件生命周期步骤,即使是异步的,它们只是提供运行代码的入口点。

Use a v-if to delay the rendering of the chart until the data is ready.使用v-if延迟图表的呈现,直到数据准备好。 The v-if acts like a watch and won't render the chart at all until then. v-if就像watch一样,在此之前根本不会渲染图表。 Use an isReady variable which you will set when the data is finished saving:使用isReady变量,您将在数据完成保存时设置该变量:

<Chart type="bar" v-if="isReady" :data="stackedData" :options="stackedOptions"/>
data()  {  
  return {
    isReady: false,
    ...
  }
}
axios.get(apiKaderURL).then(res => {
  this.all = res.data;
  this.saveData()
  this.isReady = true;  // Triggering the `v-if`
})

(Untested, but should work on principle) (未经测试,但应该在原则上工作)


Additionally, you can't set a data property from another data property using this , it will be undefined .此外,您不能使用this从另一个数据属性设置数据属性,它将是undefined You can just set them to null :您可以将它们设置为null

data: this.list_all  // Does nothing, can't use `this` like that
data: null           // Change to this

So set it to null and fix the saveData method:因此将其设置为null并修复saveData方法:

methods: {
  saveData() {
    const listAll = [];
    const listIntersection = [];

    for (var i in this.all){
      if(this.all[i].id==='2' ){
        listAll.push(this.all[i].someNumber)
      }
      if(this.all[i].id==='8'){
        listIntersection.push(this.all[i].someNumber) 
      }                     
    }
   
    this.stackedData.datasets[0].data = listAll;
    this.stackedData.datasets[1].data = listIntersection;
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM