Desired Outcome
Display multiple instances of the same chart type on a single page. Example image contains additional data stripped from the code below.

The initial chart canvas object is created with Chart.vue component:
<!-- Chart.vue -->
<template>
<div :class="chartType">
<canvas style="height: 100%; width: 100%;"></canvas>
</div>
</template>
<script>
import Chart from "chart.js/auto";
Chart.defaults.elements.point.radius = 0;
export default {
props:{
chartType:String,
chartData:Object,
chartOptions:Object
},
methods: {
chartConstructor(chartType, chartData, chartOptions) {
const chartElement = document.querySelector(`.${this.chartType} canvas`);
const chart = new Chart(chartElement, {
type: chartType,
data: chartData,
options: chartOptions,
});
},
},
mounted(){
let {chartType,chartData,chartOptions} = this;
this.chartConstructor(chartType, chartData, chartOptions);
}
};
</script>
The chart options and data are currently established in a "chart type" component, in this case a combined bar and line chart BarLine.vue (there are other components for other chart types). Although the data is provided here, the data will ultimately be sourced externally.
<!-- BarLine.vue -->
<template>
<div class="chart">
<Chart id="chartImage" :chartData="chartData" :chartOptions="chartOptions" :chartType="chartType" :style="{ width: chartWidth + 'px', height: chartHeight + 'px' }"/>
</div>
</template>
<script>
import Chart from "@/components/Chart.vue";
export default {
props:{
chartWidth: {default: 500, type: Number},
chartHeight: {default: 250, type: Number},
},
components: {
Chart,
},
data() {
return {
chartType: "bar",
chartData: {
labels: ["T", "F", "S", "S", "M", "T", "W", "T"],
datasets: [
{
type: 'line',
backgroundColor: "rgba(128, 0, 0, 0.2)",
borderColor: "rgba(128, 0, 0, 1)",
borderRadius: 3,
borderWidth: 1,
data: [55, 43, 38, 38, 38, 53, 54, 42],
hoverBackgroundColor: "rgba(128, 0, 0, 0.5)",
label: "H",
yAxisID: 'y',
},
{
type: 'bar',
backgroundColor: "rgba(0, 200, 255, 0.2)",
borderColor: "rgb(0,200,255, 0.6)",
borderRadius: 5,
borderWidth: 1,
data: [100, 50, 0, 40, 0, 0, 40, 0],
hoverBackgroundColor: "rgba(0, 200, 255, 0.5)",
label: "P",
yAxisID: 'y1',
}
]
},
chartOptions: {
layout: {
padding: {
left: 5,
right: 20,
top: 15,
}
},
plugins: {
tooltip: {
position: 'average',
mode: 'index',
},
legend: {
position: 'bottom',
labels: {
boxWidth: 20,
},
},
},
responsive: true,
scales: {
x: {
barPercentage: 0.5,
categoryPercentage: 0.5,
stacked: false,
fontSize: 5,
grid: { // x grid doesn't make much sense for this chart.
color: "#333333",
display: true,
borderDash: [1, 2],
},
},
y: {
grid:{
color: "#333333",
display: true,
borderDash: [1, 2],
},
ticks: {
stepSize: 20,
},
barPercentage: 0,
categoryPercentage: 0,
fontSize: 5,
stacked: false,
position: 'left',
},
y1: {
ticks: {
stepSize: 25,
},
barPercentage: 0,
categoryPercentage: 0,
fontSize: 5,
stacked: false,
position: 'right',
min: 0,
max: 100,
}
},
maintainAspectRatio: false,
animation: {
duration: 2000,
easing:'easeInOutQuart'
}
},
};
},
};
</script>
Then the chart object is displayed on Home.vue (and ultimately App.vue):
<!-- Home.vue -->
<template>
<div class="home">
<TileFormat class="A" tileSize="tile-double" :showButton="false" :yOverflow="false" header="A">
<BarLine class="ChartBarTile" :chartHeight="160" :chartWidth="375" style="display: flex; justify-content: center;"/>
</TileFormat>
<TileFormat class="B" tileSize="tile-double" :showButton="false" :yOverflow="false" header="B">
This will be a second chart just as soon as I figure out how to do it.
</TileFormat>
</div>
</template>
<script>
import TileFormat from '@/components/Tile.vue'
import BarLine from '@/components/BarLine.vue'
export default {
components: {
TileFormat,
BarLine,
}
}
</script>
What I've tried:
Console reports "Canvas is already in use. Chart with ID '0' must be destroyed before the canvas can be reused". What I have tried:
- Multiple different attempts to destroy the canvas between calls.
- Creating unique chart ids for each component.
- Duplicate chart type components.
- Moving
Chart.vuecode into the chart type component Vue files. - Making the second chart object of a different type which does display.
