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

Chart.js双数据集自动更新时出现TypeError错误求助

Chart.js双数据集自动更新时出现TypeError错误求助

我帮你分析下这个问题哈,你遇到的TypeError: Cannot set properties of undefined (setting 'data')本质上是代码执行到myChart.data.datasets[1].data时,datasets[1]是undefined,所以没法给它的data属性赋值。结合你描述的“单独更新第一个数据集没问题,第二个就报错”的情况,我梳理了几个可能的原因,以及对应的解决方案:

核心问题:图表实例被重复创建,状态不稳定

你原来的代码里,loadData函数每次执行都会重新创建myChart实例,覆盖之前的变量。虽然你只调用了一次loadData(),但如果网络请求延迟,刚好赶上第一次updateChartData触发时,loadData还没完成图表初始化,或者某些意外情况导致图表的第二个数据集没被正确创建,就会出现这个报错。

解决方案:重构代码,分离图表初始化与数据更新

我给你调整了代码结构,把图表初始化和数据加载/更新分开,确保图表实例只创建一次,后续只更新数据,同时添加了必要的检查避免报错:

const ctx3 = document.getElementById('verteilerboxchart');
var displayVoltage = document.getElementById('displayVoltageVerteilerbox');
var displayCurrent = document.getElementById('displayCurrentVerteilerbox');
var myChart;

// 只执行一次:初始化空图表,确保双数据集存在
function initChart() {
  if (!ctx3) {
    console.error("找不到verteilerboxchart画布元素!");
    return;
  }
  myChart = new Chart(ctx3, {
    type: 'line',
    data: {
      labels: [],
      datasets: [{
        label: 'Verteilerboxspannung in V',
        data: [],
        borderWidth: 1,
        borderColor: 'rgba(0,0,255,1)'
      }, {
        label: 'Verteilerboxstrom in A',
        data: [],
        borderWidth: 1,
        borderColor: 'rgba(255,0,0,1)'
      }]
    },
    options: {
      scales: {
        y: {
          beginAtZero: true,
          ticks: {
            color: 'rgba(0,0,0,1)'
          }
        },
        x: {
          beginAtZero: true,
          ticks: {
            color: 'rgba(0,0,0,1)'
          }
        }
      },
      plugins: {
        legend: {
          labels: {
            color: 'rgba(0,0,0,1)'
          }
        }
      }
    }
  });
}

// 加载初始数据并更新图表
async function loadData() {
  try {
    const response = await fetch('verteilerboxDb_into_website.php');
    const data = await response.json();
    console.log('从PHP获取的数据: ', data);

    const voltageValue = [];
    const time = [];
    const currentValue = [];

    data.forEach(rowData => {
      voltageValue.push(parseFloat(rowData.Spannung));
      currentValue.push(parseFloat(rowData.Strom));
      time.push(rowData.zeitstempel);
    });

    // 更新当前电压显示
    if (voltageValue.length > 0) {
      const VoltageAtMoment = voltageValue[voltageValue.length - 1];
      if (displayVoltage) {
        displayVoltage.textContent = VoltageAtMoment;
      } else {
        console.error("找不到displayVoltageVerteilerbox元素!")
      }
    }
    // 更新当前电流显示
    if (currentValue.length > 0) {
      const CurrentAtMoment = currentValue[currentValue.length - 1];
      if (displayCurrent) {
        displayCurrent.textContent = CurrentAtMoment;
      } else {
        console.error("找不到displayCurrentVerteilerbox元素!")
      }
    }

    // 更新图表数据(先检查图表实例是否存在)
    if (myChart) {
      myChart.data.labels = time;
      myChart.data.datasets[0].data = voltageValue;
      myChart.data.datasets[1].data = currentValue;
      myChart.update();
    } else {
      console.error("图表实例未初始化!");
    }

  } catch (error) {
    console.error('加载数据失败: ', error);
  }
}

// 定时更新图表数据的函数
async function updateChartData() {
  try {
    const response = await fetch('verteilerboxDb_into_website.php');
    const data = await response.json();
    console.log('从PHP获取的更新数据: ', data);

    const voltageValue = [];
    const currentValue = [];
    const time = [];

    data.forEach(rowData => {
      voltageValue.push(parseFloat(rowData.Spannung));
      currentValue.push(parseFloat(rowData.Strom));
      time.push(rowData.zeitstempel);
    });

    // 更新当前值显示
    if (voltageValue.length > 0) {
      const VoltageAtMoment = voltageValue[voltageValue.length - 1];
      if (displayVoltage) {
        displayVoltage.textContent = VoltageAtMoment;
      } else {
        console.error("找不到displayVoltageVerteilerbox元素!")
      }
    }
    if (currentValue.length > 0) {
      const CurrentAtMoment = currentValue[currentValue.length - 1];
      if (displayCurrent) {
        displayCurrent.textContent = CurrentAtMoment;
      } else {
        console.error("找不到displayCurrentVerteilerbox元素!")
      }
    }

    // 关键检查:确保图表实例和双数据集都存在
    if (!myChart) {
      console.error("图表实例不存在!");
      return;
    }
    if (myChart.data.datasets.length < 2) {
      console.error("图表中数据集数量不足!");
      return;
    }

    // 更新图表数据
    myChart.data.labels = time;
    myChart.data.datasets[0].data = voltageValue;
    myChart.data.datasets[1].data = currentValue;
    myChart.update();

  } catch (error) {
    console.error('更新数据失败', error);
  }
}

// 启动流程:初始化图表 -> 加载初始数据 -> 设置定时更新
initChart();
loadData();
var UpdateInterval = setInterval(updateChartData, 10000);

关键修改点说明

  1. 分离初始化与数据操作:initChart只执行一次,提前创建好包含双数据集的空图表,避免每次加载数据都重建图表导致实例状态混乱。
  2. 添加安全检查:在更新数据前,先确认图表实例存在、数据集数量足够,防止访问undefined属性。
  3. 优化数据处理逻辑:去掉了不必要的ID数组,直接通过数组长度获取最新值,代码更简洁。
  4. 修复潜在语法问题:去掉了数据集定义中的尾逗号,避免旧浏览器解析错误。

额外调试建议

如果还是有问题,可以在updateChartData函数开头加一行打印:

console.log('当前图表数据集:', myChart?.data?.datasets);

这样就能直观看到datasets数组的内容,确认datasets[1]是否真的存在,帮助进一步定位问题。

备注:内容来源于stack exchange,提问作者Kasma456

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.21 07:29:36