You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Chart.js复用Canvas报错,多服务图表创建问题求解决方案

Canvas重复使用导致Chart.js报错的解决方案

问题场景

我要为三个不同的服务展示图表,于是创建了图表数组,每次将新创建的图表推入数组。代码如下:

import Chart from 'chart.js'; // 修正原代码语法错误:补全闭合引号
public charts: any[]; // 建议初始化为空数组:public charts: any[] = [];
canvas: any;
ctx: any;

this.canvas = document.getElementById('serviceChart') as HTMLCanvasElement;
this.ctx = this.canvas.getContext('2d');
  
this.charts.push(new Chart(this.ctx, {
  // 图表类型
  type: 'bar',
  // 数据集
  data: barChartDataCollection,
  // 配置项
  options: this.barChartOptions
}));

执行时遇到错误:

Canvas已被占用。在重新使用ID为'idpService'的画布前,必须先销毁ID为'0'的图表。

请问:是否需要销毁每个图表?如果需要,该如何销毁以及在哪里执行?如果不需要,解决方案是什么?

附API获取的数据:

[
  {
    "timestamp": ":2023-04-18",
    "status": null,
    "majorVersion": "0",
    "minorVersion": "74",
    "statusCodes": [],
    "receivedPackets": 8640,
    "expectedPackets": 8640,
    "received": 100,
    "lost": 0
  },
  {
    "timestamp": ":2023-04-20",
    "status": null,
    "majorVersion": "0",
    "minorVersion": "74",
    "statusCodes": [],
    "receivedPackets": 8639,
    "expectedPackets": 8640,
    "received": 99,
    "lost": 1
  },
  {
    "timestamp": ":2023-04-24",
    "status": null,
    "majorVersion": "0",
    "minorVersion": "74",
    "statusCodes": [],
    "receivedPackets": 8601,
    "expectedPackets": 8640,
    "received": 99,
    "lost": 1
  },
  {
    "timestamp": ":2023-05-11",
    "status": null,
    "majorVersion": "0",
    "minorVersion": "78",
    "statusCodes": [],
    "receivedPackets": 8639,
    "expectedPackets": 8640,
    "received": 99,
    "lost": 1
  }
]

错误原因

你重复使用了同一个<canvas>元素创建多个Chart.js实例,而Chart.js不允许一个画布同时绑定多个图表实例,因此触发了该报错。

解决方案

方案一:销毁旧图表后创建新实例(适用于数据更新、复用同一画布的场景)

如果是需要在同一个画布上更新图表(比如切换服务数据时),必须先销毁旧的图表实例,再创建新的:

  • 销毁时机:创建新图表之前
  • 销毁方法:调用图表实例的destroy()方法,同时从数组中移除该实例
  • 示例代码:
// 先检查数组中是否已有当前画布的图表实例
const targetCanvasId = 'idpService';
const existingChart = this.charts.find(chart => chart.canvas.id === targetCanvasId);

if (existingChart) {
  // 销毁旧实例
  existingChart.destroy();
  // 从数组中移除
  this.charts = this.charts.filter(chart => chart !== existingChart);
}

// 再创建新图表并推入数组
this.canvas = document.getElementById(targetCanvasId) as HTMLCanvasElement;
this.ctx = this.canvas.getContext('2d');
this.charts.push(new Chart(this.ctx, {
  type: 'bar',
  data: barChartDataCollection,
  options: this.barChartOptions
}));

方案二:为每个服务分配独立画布(推荐,多服务展示场景)

既然是展示三个不同服务的图表,最直接的方法是给每个服务对应一个独立的<canvas>元素,避免复用冲突:

  1. 在页面中添加三个独立画布:
<canvas id="service1Chart"></canvas>
<canvas id="service2Chart"></canvas>
<canvas id="service3Chart"></canvas>
  1. 为每个画布创建单独的图表实例:
// 服务1图表
const canvas1 = document.getElementById('service1Chart') as HTMLCanvasElement;
this.charts.push(new Chart(canvas1.getContext('2d'), {
  type: 'bar',
  data: service1BarData, // 对应服务1的数据
  options: this.barChartOptions
}));

// 服务2图表
const canvas2 = document.getElementById('service2Chart') as HTMLCanvasElement;
this.charts.push(new Chart(canvas2.getContext('2d'), {
  type: 'bar',
  data: service2BarData, // 对应服务2的数据
  options: this.barChartOptions
}));

// 服务3图表
const canvas3 = document.getElementById('service3Chart') as HTMLCanvasElement;
this.charts.push(new Chart(canvas3.getContext('2d'), {
  type: 'bar',
  data: service3BarData, // 对应服务3的数据
  options: this.barChartOptions
}));

额外注意事项

  • 初始化图表数组时务必赋值为空数组:public charts: any[] = [];,避免undefined报错
  • 原代码的import语句存在语法错误,需补全闭合引号:import Chart from 'chart.js';

内容的提问来源于stack exchange,提问作者KamalaH

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 23:34:55