Vuejs上下文中chartjs的闪烁图表和getcontext错误
您好,我正在尝试通过调用 API 来使用 chartjs 显示不同的图表.下面的代码显示了我如何格式化chart.vue
Chart.vue:
<模板><div 类=图表容器"风格=位置:相对;高度:40vh;宽度:100%;"><插槽名称=test1"></slot><插槽名称=test2"></slot></div></模板><脚本>导出默认{名称:'图表',数据 () {返回 {日期: [],挑战: [],数据: []}},挂载(){this.check(8, 'chart_8')this.check(7, 'chart_7')},方法: {检查(身份证,姓名){this.$http.get(`/api_chart/${ id }/full`).then((响应) => {this.date = response.data.datethis.challenge = response.data.challengethis.data = this.date.map((日期, 索引) => ({x:新日期(日期 * 1000),y: this.challenge[索引]}))const ctx = document.getElementById([name]).getContext('2d')让 myChart = new Chart(ctx, {类型:'线',数据: {数据集:[{标签:挑战",数据:this.data,边框颜色:'#EA5455',}]},选项: {线张力:0,保持纵横比:假,秤:{y轴:[{刻度标签:{显示:假},滴答声:{beginAtZero:是的,回调(值){返回`${value}%`}}}],x轴:[{类型:'时间',时间: {单位:'月'},刻度标签:{显示:真,}}]}}})})}}}</脚本>
App.vue:
<模板><div class="为了显示chart1"><图表显示><画布槽=test1";id="chart_7";></画布></图表显示></div><div class="为了显示chart1"><图表显示><画布槽=test2";id="chart_8";></画布></图表显示></div></模板><脚本>从 './Chart.vue' 导入图表显示导出默认{组件:{图表显示}}</脚本>
如您所见,我已经共享了我的 Chart.vue 和 App.vue,我可以在浏览器中看到我的图表,但是每当我运行代码或刷新页面时,图表都会闪烁并停止.然后在我的控制台中出现以下错误:
请有人帮我解决这个问题,并请告诉我是否应该对我的代码进行任何更改来解决它.请把修改码发给我.
解决方案正如我在评论中所写,图表被渲染了两次.这会导致闪烁.
//每次使用<chart-display>,都会渲染2个图表,也就是说图表1会渲染//自身和图表 2,char 2 渲染自身和图表 1,这在 Vue 中通常是一个不好的模式挂载(){this.check(8, "chart_8");this.check(7, "chart_7");}
进行以下更改:
ChartDisplay.vue
<template>
App.vue
<template><div class="为了显示chart1"><图表显示/></div></div></模板><脚本>从./ChartDisplay.vue"导入 ChartDisplay;导出默认{组件:{ ChartDisplay },};</脚本>
在 沙盒上查看它p>
Hello i am trying to display different charts using the chartjs by calling the API. Below code shows how i have formatted the chart.vue
Chart.vue:
<template>
<div class="chart-container" style="position: relative; height: 40vh; width:100%;">
<slot name="test1"></slot>
<slot name="test2"></slot>
</div>
</template>
<script>
export default {
name: 'charts',
data () {
return {
date: [],
challenge: [],
data: []
}
},
mounted () {
this.check(8, 'chart_8')
this.check(7, 'chart_7')
},
methods: {
check (id, name) {
this.$http.get(`/api_chart/${ id }/full`)
.then((response) => {
this.date = response.data.date
this.challenge = response.data.challenge
this.data = this.date.map((date, index) => ({
x: new Date(date * 1000),
y: this.challenge[index]
}))
const ctx = document.getElementById([name]).getContext('2d')
let myChart = new Chart(ctx, {
type: 'line',
data: {
datasets: [
{
label: 'Challenge',
data: this.data,
borderColor: ' #EA5455',
}
]
},
options: {
lineTension: 0,
maintainAspectRatio: false,
scales: {
yAxes: [
{
scaleLabel: {
display: false
},
ticks: {
beginAtZero: true,
callback (value) {
return `${value}%`
}
}
}
],
xAxes: [
{
type: 'time',
time: {
unit: 'month'
},
scaleLabel: {
display: true,
}
}
]
}
}
})
})
}
}
}
</script>
App.vue:
<template>
<div class="In order to display chart1">
<chart-display> <canvas slot="test1" id="chart_7" ></canvas> </chart-display>
</div>
<div class="In order to display chart1">
<chart-display> <canvas slot="test2" id="chart_8" ></canvas> </chart-display>
</div>
</template>
<script>
import chart-display from './Chart.vue'
export default {
component: {chart-display}
}
</script>
As you can see i have shared my Chart.vue and App.vue, i am able to see my chart in the browser, but whenever i run the code or refresh the page, the charts flickers and stops. And then in my console i get below error:
Please someone help me to get rid of this issue, and please tell me if any changes i should do in my code to solve it. Please send me the modification code.
解决方案As I wrote in my comment, the charts are rendered twice. This causes flickering.
// every time you use <chart-display>, 2 charts are rendered, this means chart 1 renders
// itself and chart 2, char 2 renders itself and chart 1, this is a bad pattern in Vue in general
mounted() {
this.check(8, "chart_8");
this.check(7, "chart_7");
}
Make the following changes:
ChartDisplay.vue
<template>
<div
class="chart-container"
style="position: relative; height: 40vh; width: 100%"
>
<canvas ref="chart_7"></canvas>
<canvas ref="chart_8"></canvas>
</div>
</template>
<script>
import Chart from "chart.js";
export default {
name: "ChartDisplay",
data() {
return {
date: [],
challenge: [],
data: [],
// save charts in an array
charts: [],
// charts options
options: {
lineTension: 0,
maintainAspectRatio: false,
scales: {
yAxes: [
{
scaleLabel: {
display: false,
},
ticks: {
beginAtZero: true,
callback(value) {
return `${value}%`;
},
},
},
],
xAxes: [
{
type: "time",
time: {
unit: "month",
},
scaleLabel: {
display: true,
},
},
],
},
},
};
},
mounted() {
this.render(7, this.$refs.chart_7);
this.render(8, this.$refs.chart_8);
},
methods: {
render(id, ctx) {
this.fetchData(id).then((response) => {
let data = response.date.map((date, index) => ({
x: new Date(date * 1000),
y: response.challenge[index],
}));
this.charts.push(
new Chart(ctx, {
type: "line",
data: {
datasets: [
{
label: "Challenge",
data: data,
borderColor: " #EA5455",
},
],
},
options: this.options,
})
);
});
},
fetchData(id) {
return this.$http.get(`/api_chart/${ id }/full`);
},
},
beforeDestroy() {
this.charts.forEach((chart) => chart.destroy());
},
};
</script>
<style >
[v-cloak] {
display: none;
}
</style>
App.vue
<template>
<div>
<div class="In order to display chart1">
<chart-display/>
</div>
</div>
</template>
<script>
import ChartDisplay from "./ChartDisplay.vue";
export default {
components: { ChartDisplay },
};
</script>
See it on sandbox
相关文章