I have a boxplot component in my Vue project and I want to reuse it on the same page for a table I am building.
However, despite the fact that my data is different, I still get this Canvas is already in use. Chart with ID '0' must be destroyed before the canvas can be reused.
error.
I've seen this question asked previously on here, but none of the threads 'fixes' really helped me here. (Threads I've seen and video I tried to replicate).
Since I have no idea of how many rows (and charts) I will need to use, I don't think this fix is very practical. Is there anyway around this type of error?
Do I need a new id generated for each chart I am using? Since this is utilizing the basic Chartjs library and not the normal VueChart3 syntax I've been using throughout the rest of my app, I am a bit stumped.
Any help or advice would be greatly appreciated! Cheers!
BoxPlotChart.vue
<template>
<canvas id="myChart"></canvas>
</template>
<script>
import { defineComponent, onMounted } from "vue";
import { Chart, registerables } from "chart.js";
import { BoxPlotChart } from "@sgratzl/chartjs-chart-boxplot";
Chart.register(...registerables);
export default defineComponent({
name: "CBoxPlotChart",
props: {
data: {
type: Object,
required: true,
},
width: {
type: String,
// default: '400px'
},
height: {
type: String,
// default: '300px'
},
showLegend: {
type: Boolean,
default: true,
},
},
setup(props) {
onMounted(() => {
// @ts-ignore
const ctx = document.getElementById("myChart")?.getContext("2d");
ctx.canvas.parentNode.style.width = `${props.width}px`;
ctx.canvas.parentNode.style.height = `${props.height}px`;
if (!ctx) return;
const myChart = new BoxPlotChart(ctx, {
// type: 'boxplot',
// @ts-ignore
data: props.data,
options: {
responsive: true,
maintainAspectRatio: false,
indexAxis: "y",
// @ts-ignore
clip: false,
title: {
display: true,
text: "Chart.js Box Plot Chart",
},
plugins: {
datalabels: {
display: false,
},
legend: {
display: false,
},
tooltip: {
// if you want to hide the tooltip, just uncomment the line below
// enabled: false,
displayColors: false,
bodyFont: {
size: 12,
family: "Inter",
},
bodyColor: "#4771FA",
backgroundColor: "white",
callbacks: {
title: () => "",
label: (context) => {
console.log(`context!`, context.parsed.max);
const mean = context.parsed.mean.toFixed(3);
const q1 = context.parsed.q1.toFixed(3);
const q3 = context.parsed.q3.toFixed(3);
const boxplotValues = [
`Q3: ${q3}`,
`Mean: ${mean}`,
`Q1: ${q1}`,
];
return boxplotValues;
},
},
},
},
layout: {
padding: {
left: 10,
right: 5,
top: 0,
bottom: 10,
},
},
scales: {
x: {
display: false,
},
y: {
display: false,
},
},
},
});
});
return {
// isResponsive,
// getData,
// options,
// barChartProps,
// myStyles,
};
},
});
</script>
Table.vue
<template>
<table cellspacing="0">
<tr>
<th>Date</th>
<th>Value</th>
<th>Chart</th>
</tr>
<tr>
<td>
<div style="margin: 0.5rem">05/03/22</div>
</td>
<td>
<div
style="
background: #FFE2E2;
padding: 1rem;
margin: 0.5rem;
border-radius: 8px;
"
>
12.93
</div>
</td>
<td style="width: max-content">
<BoxPlotChart :data="boxplotData" />
</td>
</tr>
<tr>
<td>
<div style="margin: 0.5rem">05/03/22</div>
</td>
<td>
<div
style="
background: #FFE2E2;
padding: 1rem;
margin: 0.5rem;
border-radius: 8px;
"
>
12.93
</div>
</td>
<!-- <td style="width: max-content">
<BoxPlotChart :data="boxplotData2" />
</td> -->
</tr>
</table>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import BoxPlotChart from "./BoxPlotChart.vue";
import { boxplotData, boxplotData2 } from "./boxplot-mock-data";
export default defineComponent({
name: "",
props: {},
emits: [],
components: { BoxPlotChart },
setup() {
return { boxplotData, boxplotData2 };
},
});
</script>
<style lang="sass" scoped>
table
th
text-align: center
tr, td
border: 1px solid #DCE5FA
</style>
CodePudding user response:
ID's in web design should be unique. At the moment each time you create a new BoxPlotChart
component it adds a canvas with id 'myChart'
to the DOM.
You either have to generate a random ID within your BoxPlotChart
chart component or pass along an ID in the props which you give to the canvas