Chart.js实时传感器图表创建失败:无法获取上下文,求助
Let's break down your problems and fix them step by step:
Core Issues Identified
Chart Instance Timing Problem
You're instantiatingmakeChartin theDashboardconstructor, but at that point, yourdashboard.html(and the<canvas id="testChart">element) hasn't been loaded into the DOM yet. That's whyctxandcanvasare null, triggering the context acquisition error.Data Update Logic Errors
- You're pushing raw data directly to the
datasetsarray instead of thedataproperty of your existing dataset. - The
chart_updateCountvariable is local toaddData, 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.
- You're pushing raw data directly to the
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_numberElementsandchart_updateCountas instance properties ofmakeChart(so they persist between method calls). - Push new data to the
dataarray of your first dataset, not thedatasetsarray 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
makeChartinstance after thedashboard.htmlcontent is loaded into the DOM, ensuring the canvas is available. - The data update logic now correctly targets the first dataset's
dataarray instead of pushing to thedatasetsarray. - The
chart_updateCountis now an instance property, so it retains its value betweenaddDatacalls. - We added a check for
this.makeChartin therefreshmethod to avoid errors if the chart isn't ready yet.
内容的提问来源于stack exchange,提问作者Java Virgin

