Vue中Chart.js图表标签不显示,报ctx未定义错误
Chart.js 图表数值不显示且报错"Cannot read properties of undefined (reading 'ctx')"问题排查
问题描述
开发包含柱状图和折线图的Chart.js图表时,无法在图表上显示数值,控制台抛出错误:Cannot read properties of undefined (reading 'ctx'),实际图表的柱状和折线位置均未显示预期的数值标注。
问题代码
<template> <div> <canvas id="miGrafico"></canvas> </div> </template> <script> // Importa Chart.js import { Chart } from 'chart.js/auto'; export default { data() { return { }; }, mounted() { const canvasElement = document.getElementById('miGrafico'); const ctx2 = canvasElement.getContext('2d'); // Datos de ejemplo para las jornadas const jornadas = ['J1', 'J2', 'J3', 'J4', 'J5']; const puntuaciones = [10, 15, 8, 20, 12]; const goles = [1, 0, 2, 1, 3]; const asistencias = [3, 2, 4, 1, 2]; new Chart(ctx2, { type: 'bar', // Tipo de gráfico de barras data: { labels: jornadas, datasets: [ { label: 'Puntuación', data: puntuaciones, backgroundColor: '#0493FE', // Color de las barras de puntuación barPercentage: 0.3, // Reduce el ancho de las barras de puntuación categoryPercentage: 0.8, order: -1, // Coloca las barras de puntuación detrás de las líneas }, { label: 'Goles', data: goles, backgroundColor: 'transparent', // No rellena las barras de goles borderColor: '#25D983', // Color de la línea de goles borderWidth: 2, // Grosor de la línea de goles type: 'line', // Mostrar los goles como una línea fill: false, // No llenar el área bajo la línea de goles order: -2, // Coloca las líneas de goles delante de las barras de puntuación pointRadius:0 }, { label: 'Asistencias', data: asistencias, backgroundColor: 'transparent', // No rellena las barras de asistencias borderColor: '#FF922D', // Color de la línea de asistencias borderWidth: 2, // Grosor de la línea de asistencias type: 'line', // Mostrar las asistencias como una línea fill: false, // No llenar el área bajo la línea de asistencias order: -3, // Coloca las líneas de asistencias delante de las barras de puntuación pointRadius: 0 }, ], }, options:{ animation: { duration: 1, onComplete: function () { var chartInstance = this.chart, ctx = chartInstance.ctx; ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, Chart.defaults.global.defaultFontStyle, Chart.defaults.global.defaultFontFamily); ctx.textAlign = 'center'; ctx.textBaseline = 'bottom'; ctx.fillStyle = 'white'; var ultimo = [0, 0, 0, 0]; this.data.datasets.forEach(function (dataset, i) { if(i==0){ var meta = chartInstance.controller.getDatasetMeta(i); meta.data.forEach(function (bar, index) { var data = Math.round(dataset.data[index]-0.1); ultimo[index] = data; ctx.fillText(data, bar._model.x, bar._model.y - 5); }); } if(i==1){ var meta = chartInstance.controller.getDatasetMeta(i); meta.data.forEach(function (bar, index) { var data = dataset.data[index]; if(data!=ultimo[index]){ ctx.fillText(data, bar._model.x, bar._model.y - 5); } }); } if(i==2){ var meta = chartInstance.controller.getDatasetMeta(i); meta.data.forEach(function (bar, index) { var data = parseInt(dataset.data[index]*2); if(data!=0){ ctx.fillText(data, bar._model.x, bar._model.y - 5); } }); } }); } } }, }); }, }; </script>
问题原因
- Chart.js v3+ API变更:你使用的是Chart.js v3版本,
onComplete回调内的this.chart已被移除,导致chartInstance为undefined,进而读取ctx时触发报错。 - 旧版字体配置API失效:
Chart.defaults.global在v3中已改为Chart.defaults.font,原写法无法正确设置字体样式,影响数值渲染。 - 折线图数据点半径设置错误:将折线图的
pointRadius设为0,导致无法获取到数据点的坐标信息,折线图的数值无法定位显示。
修复方案及代码
调整animation.onComplete的回调逻辑,适配Chart.js v3的API,同时修正折线图的点半径配置:
<template> <div> <canvas id="miGrafico"></canvas> </div> </template> <script> import { Chart } from 'chart.js/auto'; export default { mounted() { const canvasElement = document.getElementById('miGrafico'); const ctx2 = canvasElement.getContext('2d'); const jornadas = ['J1', 'J2', 'J3', 'J4', 'J5']; const puntuaciones = [10, 15, 8, 20, 12]; const goles = [1, 0, 2, 1, 3]; const asistencias = [3, 2, 4, 1, 2]; new Chart(ctx2, { type: 'bar', data: { labels: jornadas, datasets: [ { label: 'Puntuación', data: puntuaciones, backgroundColor: '#0493FE', barPercentage: 0.3, categoryPercentage: 0.8, order: -1, }, { label: 'Goles', data: goles, backgroundColor: 'transparent', borderColor: '#25D983', borderWidth: 2, type: 'line', fill: false, order: -2, pointRadius: 3, // 设为可见半径,保证坐标可获取 pointStyle: 'circle' }, { label: 'Asistencias', data: asistencias, backgroundColor: 'transparent', borderColor: '#FF922D', borderWidth: 2, type: 'line', fill: false, order: -3, pointRadius: 3, // 设为可见半径,保证坐标可获取 pointStyle: 'circle' }, ], }, options:{ animation: { duration: 1, // 接收chart实例作为参数 onComplete: function(chart) { const ctx = chart.ctx; // 使用v3的字体配置API const font = Chart.defaults.font; ctx.font = `${font.size}px ${font.family}`; ctx.textAlign = 'center'; ctx.textBaseline = 'bottom'; ctx.fillStyle = 'white'; const ultimo = [0, 0, 0, 0]; chart.data.datasets.forEach((dataset, i) => { const meta = chart.getDatasetMeta(i); meta.data.forEach((element, index) => { if(i === 0){ const data = Math.round(dataset.data[index] - 0.1); ultimo[index] = data; ctx.fillText(data, element.x, element.y - 5); } if(i === 1){ const data = dataset.data[index]; if(data !== ultimo[index]){ ctx.fillText(data, element.x, element.y - 10); } } if(i === 2){ const data = parseInt(dataset.data[index] * 2); if(data !== 0){ ctx.fillText(data, element.x, element.y - 15); } } }); }); } } }, }); }, }; </script>
内容的提问来源于stack exchange,提问作者Corboss
相关产品推荐
相关产品推荐

