Vue Chart.js - 图表在数据更改时不更新
Vue Chart.js - Chart is not updating when data is changing
我正在使用 Vue.js 和 Chart.js 绘制一些图表。
每次调用函数 generateChart()
时,图表都不会自动更新。当我检查 Vue Devtools 中的数据时,它们是正确的,但图表没有反映数据。但是,当我调整 window.
大小时图表会更新
- 我这样做有什么问题吗?
- 如何在每次调用
generateChart()
时更新图表?
我觉得这将与 object
和 array
变更检测注意事项相关,但我不确定该怎么做。
https://codepen.io/anon/pen/bWRVKB?editors=1010
<template>
<el-dialog title="Chart" v-model="showGeneratedChart">
<line-chart :chartData="dataChart"></line-chart>
</el-dialog>
</template>
<script>
export default {
data() {
const self = this;
return {
dataChart: {
labels: [],
datasets: [
{
label: "label",
backgroundColor: "#FC2525",
data: [0, 1, 2, 3, 4],
},
],
},
};
},
methods: {
generateChart() {
this.dataChart["labels"] = [];
this.dataChart["datasets"] = [];
// ... compute datasets and formattedLabels
this.dataChart["labels"] = formattedLabels;
this.dataChart["datasets"] = datasets;
},
},
};
</script>
行Chart.js
import { Line, mixins } from 'vue-chartjs'
export default Line.extend({
mixins: [mixins.reactiveProp],
props: ["options"],
mounted () {
this.renderChart(this.chartData, this.options)
}
})
我以前从未使用过 vue-chartjs,但看起来你唯一的问题是你忘记在折线图组件中明确接收 chartData 作为道具:
改变
export default Line.extend({
mixins: [mixins.reactiveProp],
props: ["options"],
mounted () {
this.renderChart(this.chartData, this.options)
}
})
和
export default Line.extend({
mixins: [mixins.reactiveProp],
props: ["chartData", "options"],
mounted () {
this.renderChart(this.chartData, this.options)
}
})
此外,请注意更改对象时的 vue 反应性问题,这将不起作用:
this.dataChart['datasets'] = datasets;
你必须这样做:
Vue.set(this.dataChart, 'datasets', datasets);
以便 Vue 检测对象的变化。
有关反应性的更多信息:
https://vuejs.org/v2/guide/reactivity.html
有关图表中反应性的更多信息:
http://vue-chartjs.org/#/home?id=reactive-data
对图表数据使用计算的 属性。而不是在 watch 上调用 this.renderChart
将其包装在一个方法中,然后在 mounted
和 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/vue-chartjs@2.5.7-rc3/dist/vue-chartjs.full.min.js"></script>
</body>
</html>
您还可以将选项设为计算值 属性,如果选项不会发生太大变化,您可以设置默认道具。 https://vuejs.org/v2/guide/components.html#Prop-Validation
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)
}
}
添加自定义观察器以更新任何 vue 图表图形
我的解决方案是不使用 mixins 并使用 watch 来支持 prop。
watch: {
chartData: function() {
this.renderChart(this.chartData, this.options);
}
}
但是,这不起作用,直到我像这样更改另一个组件中的图表数据:
this.chartData = {
labels: [],
datasets: []
};
this.chartData.labels = labels;
this.chartData.datasets = datasets;
如果我只是替换标签和数据集,手表不会触发。
您的解决方案实际上几乎是正确的。您不能直接修改图表数据集的子属性。您必须设置 this.datachart
对象本身。默认的 mixin mixins.reactiveProp
会自动添加一个 watcher 到组件的 chartData
属性。请参阅文档 here。这就是为什么没有进一步的代码就无法修改子属性的原因,请参阅其他答案。
generateChart() {
// If you want to clear all chart data (not necessary)
this.dataChart = {}
// Compute datasets and formattedLabels
let formattedLabels = ...
let datasets = ...
this.dataChart = {
labels: formattedLabels,
datasets: datasets
}
}
我只是在没有破坏的情况下在 nextTick 上重新渲染它并且工作正常。
(vue 3, vue3-chart-v2:0.8.2)
mounted () {
this.renderLineChart();
},
methods: {
renderLineChart() {
this.renderChart(this.chartData, this.chartOptions);
}
},
watch: {
chartData () {
this.$nextTick(() => {
this.renderLineChart();
})
}
}
我正在使用 Vue.js 和 Chart.js 绘制一些图表。
每次调用函数 generateChart()
时,图表都不会自动更新。当我检查 Vue Devtools 中的数据时,它们是正确的,但图表没有反映数据。但是,当我调整 window.
- 我这样做有什么问题吗?
- 如何在每次调用
generateChart()
时更新图表?
我觉得这将与 object
和 array
变更检测注意事项相关,但我不确定该怎么做。
https://codepen.io/anon/pen/bWRVKB?editors=1010
<template>
<el-dialog title="Chart" v-model="showGeneratedChart">
<line-chart :chartData="dataChart"></line-chart>
</el-dialog>
</template>
<script>
export default {
data() {
const self = this;
return {
dataChart: {
labels: [],
datasets: [
{
label: "label",
backgroundColor: "#FC2525",
data: [0, 1, 2, 3, 4],
},
],
},
};
},
methods: {
generateChart() {
this.dataChart["labels"] = [];
this.dataChart["datasets"] = [];
// ... compute datasets and formattedLabels
this.dataChart["labels"] = formattedLabels;
this.dataChart["datasets"] = datasets;
},
},
};
</script>
行Chart.js
import { Line, mixins } from 'vue-chartjs'
export default Line.extend({
mixins: [mixins.reactiveProp],
props: ["options"],
mounted () {
this.renderChart(this.chartData, this.options)
}
})
我以前从未使用过 vue-chartjs,但看起来你唯一的问题是你忘记在折线图组件中明确接收 chartData 作为道具:
改变
export default Line.extend({
mixins: [mixins.reactiveProp],
props: ["options"],
mounted () {
this.renderChart(this.chartData, this.options)
}
})
和
export default Line.extend({
mixins: [mixins.reactiveProp],
props: ["chartData", "options"],
mounted () {
this.renderChart(this.chartData, this.options)
}
})
此外,请注意更改对象时的 vue 反应性问题,这将不起作用:
this.dataChart['datasets'] = datasets;
你必须这样做:
Vue.set(this.dataChart, 'datasets', datasets);
以便 Vue 检测对象的变化。
有关反应性的更多信息: https://vuejs.org/v2/guide/reactivity.html
有关图表中反应性的更多信息: http://vue-chartjs.org/#/home?id=reactive-data
对图表数据使用计算的 属性。而不是在 watch 上调用 this.renderChart
将其包装在一个方法中,然后在 mounted
和 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/vue-chartjs@2.5.7-rc3/dist/vue-chartjs.full.min.js"></script>
</body>
</html>
您还可以将选项设为计算值 属性,如果选项不会发生太大变化,您可以设置默认道具。 https://vuejs.org/v2/guide/components.html#Prop-Validation
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)
}
}
添加自定义观察器以更新任何 vue 图表图形
我的解决方案是不使用 mixins 并使用 watch 来支持 prop。
watch: {
chartData: function() {
this.renderChart(this.chartData, this.options);
}
}
但是,这不起作用,直到我像这样更改另一个组件中的图表数据:
this.chartData = {
labels: [],
datasets: []
};
this.chartData.labels = labels;
this.chartData.datasets = datasets;
如果我只是替换标签和数据集,手表不会触发。
您的解决方案实际上几乎是正确的。您不能直接修改图表数据集的子属性。您必须设置 this.datachart
对象本身。默认的 mixin mixins.reactiveProp
会自动添加一个 watcher 到组件的 chartData
属性。请参阅文档 here。这就是为什么没有进一步的代码就无法修改子属性的原因,请参阅其他答案。
generateChart() {
// If you want to clear all chart data (not necessary)
this.dataChart = {}
// Compute datasets and formattedLabels
let formattedLabels = ...
let datasets = ...
this.dataChart = {
labels: formattedLabels,
datasets: datasets
}
}
我只是在没有破坏的情况下在 nextTick 上重新渲染它并且工作正常。
(vue 3, vue3-chart-v2:0.8.2)
mounted () {
this.renderLineChart();
},
methods: {
renderLineChart() {
this.renderChart(this.chartData, this.chartOptions);
}
},
watch: {
chartData () {
this.$nextTick(() => {
this.renderLineChart();
})
}
}