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

Angular下拉选择更新Chart.js X轴值报Canvas复用错误解决方案

问题根因

报错来自Chart.js的实例绑定限制:你每次调用filtereTokenPrice都会在同一个<canvas>元素上初始化全新的Chart实例,首次执行时canvas无绑定实例所以可以正常渲染,后续切换选项时前一次创建的实例仍占用canvas资源,没有被销毁,就会抛出「Canvas is already in use」的错误。

解决方法

两种实现都可以解决问题,优先选第一种复用实例的方案,性能更好。

方案1:复用Chart实例(推荐)

不要重复初始化实例,首次创建实例后,后续切换选项只更新数据再触发重绘即可。

  1. 先在组件类的顶层声明chart实例属性,不要在方法内部直接声明变量:
    // 组件类属性区新增
    chart: Chart | null = null;
    
  2. 修改filtereTokenPrice方法逻辑,区分首次初始化和后续更新场景:
    async filtereTokenPrice(){
      // 原map是同步方法,不需要加await
      this.usd = this.TokenUsdPrice.map(item=>item.usdPrice);
      const chartLabels = this.service.getdates();
      const chartDatasets = [{
        data: this.usd,
        borderWidth: 1,
        fill: false
      }];
    
      if (!this.chart) {
        // 实例不存在,首次初始化
        this.chart = new Chart('canvas', {
          type: 'line',
          data: {
            labels: chartLabels,
            datasets: chartDatasets
          }
        });
      } else {
        // 实例已存在,替换数据后重绘
        this.chart.data.labels = chartLabels;
        this.chart.data.datasets = chartDatasets;
        this.chart.update();
      }
    }
    
  3. 新增组件销毁生命周期逻辑,避免内存泄漏:
    // 类实现OnDestroy接口
    ngOnDestroy(): void {
      if (this.chart) {
        this.chart.destroy();
      }
    }
    

方案2:每次新建前销毁旧实例

如果不需要复用实例,每次创建新实例前手动销毁已存在的旧实例即可:

  1. 同样先在组件类顶层声明chart属性:
    chart: Chart | null = null;
    
  2. 修改filtereTokenPrice逻辑:
    async filtereTokenPrice(){
      this.usd = this.TokenUsdPrice.map(item=>item.usdPrice);
      // 存在旧实例先销毁
      if (this.chart) {
        this.chart.destroy();
      }
      // 再创建新实例
      this.chart = new Chart('canvas',{
        type:'line',
        data:{
          labels:this.service.getdates(),
          datasets:[
            {
              data:this.usd,
              borderWidth:1,
              fill:false
            }
          ]
        }
      })
    }
    
额外优化点
  • 不推荐在mat-option上绑定(click)事件触发数据查询,这种方式可能出现点击事件触发时表单值还没更新的问题,建议直接监听表单控件的valueChanges事件触发逻辑:
    // 在ngOnInit生命周期中添加订阅
    ngOnInit(): void {
      this.selectedValue.valueChanges.subscribe(() => {
        this.TokenPrice();
      });
    }
    
    模板中直接移除mat-option上的(click)="TokenPrice()"绑定即可。
  • 你原需求描述是「动态价格展示在X轴,固定日期展示在Y轴」,当前配置中labels(默认对应X轴)放的是日期数据,data放的是价格,和需求正好相反,如果轴显示不符合预期,可以在Chart的options配置中修改轴映射规则。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 19:15:28