如何使用不同的数据重用 Chartjs 图表组件并克服 **Canvas is already in use** 错误?

How to reuse a Chartjs Chart component in with different Data and get past the **Canvas is already in use** error?

我的 Vue 项目中有一个箱线图组件,我想在我正在构建的 table 的同一页面上重用它。

然而,尽管我的数据不同,我仍然得到这个 Canvas is already in use. Chart with ID '0' must be destroyed before the canvas can be reused. 错误。

我之前在这里看到过这个问题,但是 none 的线程 'fixes' 在这里确实帮助了我。 (Threads I've seen and video I tried to replicate).

因为我不知道我需要使用多少行(和图表),所以我认为 this fix 不是很实用。是否存在此类错误?

我需要为我使用的每个图表生成一个新 ID 吗?由于这是利用基本的 Chartjs 库,而不是我在应用程序的其余部分一直使用的正常 VueChart3 syntax,所以我有点难过。

如有任何帮助或建议,我们将不胜感激!干杯!

CodeSandbox Link

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 class="no-spacing" 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>

网页设计中的 ID 应该是唯一的。目前,每次您创建一个新的 BoxPlotChart 组件时,它都会向 DOM.

添加一个 ID 为 'myChart' 的 canvas

您要么必须在 BoxPlotChart 图表组件中生成一个随机 ID,要么在您提供给 canvas

的道具中传递一个 ID