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

Chart.js实时传感器图表创建失败:无法获取上下文,求助

Fixing Chart.js "Failed to create chart: can't acquire context from the given item" & Real-Time Update Issues

Let's break down your problems and fix them step by step:

Core Issues Identified

  1. Chart Instance Timing Problem
    You're instantiating makeChart in the Dashboard constructor, but at that point, your dashboard.html (and the <canvas id="testChart"> element) hasn't been loaded into the DOM yet. That's why ctx and canvas are null, triggering the context acquisition error.

  2. Data Update Logic Errors

    • You're pushing raw data directly to the datasets array instead of the data property of your existing dataset.
    • The chart_updateCount variable is local to addData, so it resets to 0 every time the method runs—meaning you'll never trim old data.
    • You commented out this.testChart.update(), which is required to trigger the chart to redraw with new data.

Step-by-Step Fixes

1. Fix Chart Instantiation Timing

Move the makeChart instantiation into the callback of $('#tab_info').load(), ensuring the canvas exists in the DOM before trying to create the chart.

2. Correct Data Update Logic

  • Store chart_numberElements and chart_updateCount as instance properties of makeChart (so they persist between method calls).
  • Push new data to the data array of your first dataset, not the datasets array itself.
  • Uncomment this.testChart.update() to trigger chart redraws.
  • Adjust the old data trimming logic to keep only the last 60 data points.

3. Ensure Proper Context Acquisition

Use document.getElementById() to grab the canvas element explicitly (after the DOM is ready) and pass its context to the Chart constructor.


Corrected Code

dashboard.js

class Dashboard {
  constructor(jsonRPC, auth){
    this.jsonRPC = jsonRPC;
    this.auth = auth;
    this.updateInterval = 10; // every 10 seconds
    this.makeChart = null; // Initialize as null, instantiate later
  }

  run() {
    const that = this;
    that.jsonRPC.call('extension.get', {'select':'data'}).then(function (result) {
      // Initialize Device Infos
      $('#tab_info').load('html/dashboard.html #content', function(){
        $(".GaugeMeter").gaugeMeter(); // Initialize GaugeMeter plugin
        
        // NOW the canvas exists in DOM—create the chart instance
        that.makeChart = new makeChart();
        
        // Start Data Refresh Cycle
        that.refresh();
      });
    });
  }

  refresh() {
    const that = this;
    that.jsonRPC.call('extension.get', {'select':'data'}).then(function (result) {
      // Only update if the chart instance exists
      if (that.makeChart) {
        that.makeChart.addData(result.particles.PM0_3);
      }
    });
    // Wait 10 seconds before next refresh
    setTimeout(function(){ that.refresh(); }, this.updateInterval * 1000);
  }
}

class makeChart{
  constructor(){
    // Grab the canvas element (now exists because we instantiate after DOM load)
    const canvas = document.getElementById('testChart');
    if (!canvas) {
      console.error('Canvas element with id "testChart" not found!');
      return;
    }
    const ctx = canvas.getContext('2d');

    // Chart configurations
    const commonOptions = {
      scales: {
        xAxes: [{
          type: 'time',
          distribution: 'series',
          time: {
            displayFormats: { second: 'h:mm:ss a' },
            unit:'second'
          }
        }],
        yAxes: [{ ticks: { beginAtZero:true } }]
      },
      legend: {display: false},
      tooltips:{ enabled: true }
    };

    // Chart instance
    this.testChart = new Chart (ctx,{
      type: 'line',
      data: {
        labels: [], // x axis
        datasets: [{
          label: "Particles Number10",
          data: [], // y axis
          fill: false,
          borderColor: '#343e9a',
          borderWidth: 1
        }]
      },
      options: Object.assign({}, commonOptions, {
        title:{
          display: true,
          text: "Particles Number10",
          fontSize: 18
        },
        maintainAspectRatio: false,
        responsive: false,
      })
    });

    // Instance properties for data trimming
    this.chart_numberElements = 60;
    this.chart_updateCount = 0;
    console.log(this.testChart);
  };

  addData (data) {
    if(!data || !this.testChart) return;

    const today = new Date();
    // Use a time format compatible with Chart.js time scale
    const time = today.toISOString();
    
    // Add new data points
    this.testChart.data.labels.push(time);
    this.testChart.data.datasets[0].data.push(data);

    this.chart_updateCount++;
    // Trim old data if we exceed the limit
    if(this.chart_updateCount > this.chart_numberElements){
      this.testChart.data.labels.shift();
      this.testChart.data.datasets[0].data.shift();
      // Keep count at the limit to avoid unnecessary increments
      this.chart_updateCount = this.chart_numberElements;
    }

    // Trigger chart redraw with new data
    this.testChart.update();
  };
};

dashboard.html (unchanged, just confirming the canvas exists)

<div class="modal-body">
  <canvas id="testChart" width="800" height="400"></canvas>
</div>

Key Notes

  • We only create the makeChart instance after the dashboard.html content is loaded into the DOM, ensuring the canvas is available.
  • The data update logic now correctly targets the first dataset's data array instead of pushing to the datasets array.
  • The chart_updateCount is now an instance property, so it retains its value between addData calls.
  • We added a check for this.makeChart in the refresh method to avoid errors if the chart isn't ready yet.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 08:07:36