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>元素,避免复用冲突:
- 在页面中添加三个独立画布:
<canvas id="service1Chart"></canvas> <canvas id="service2Chart"></canvas> <canvas id="service3Chart"></canvas>
- 为每个画布创建单独的图表实例:
// 服务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
相关产品推荐
相关产品推荐

