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

Chart.js动态多柱状图适配缺失数据:避免类型错位问题

柱状图数据错位问题解决方法

我尝试基于随过滤器动态变化的JSON数据创建柱状图,要求图表仅展示对应Period的Type数据(存在则显示,缺失则不展示)。参考实现后,只有当所有数据选项齐全时图表正常工作;如果某Period缺失某个Type,会导致该Type的数据错位到上一个Period,不符合需求。

示例1:两个月、两类数据(显示正常)

[
    {
        "Period": "2023-12",
        "Total": 2238.86,
        "Type": "Drinks"
    },
    {
        "Period": "2023-12",
        "Total": 4672.35,
        "Type": "Food"
    },
    {
        "Period": "2024-01",
        "Total": 1166.5,
        "Type": "Drinks"
    }
]

示例2:三个月、三类数据(数据错位)

[
    {
        "Period": "2023-11",
        "Total": 2782.13,
        "Type": "Other"
    },
    {
        "Period": "2023-12",
        "Total": 2238.86,
        "Type": "Drinks"
    },
    {
        "Period": "2023-12",
        "Total": 4672.35,
        "Type": "Food"
    },
    {
        "Period": "2024-01",
        "Total": 1166.5,
        "Type": "Drinks"
    }
]

当前使用代码

jQuery.ajax({
    url: "../../ajax/barGraph.php?period=<?= $period; ?>",
    type: "GET",
    dataType: 'json',
    success: function(soldeInfo) {


          let labels = [...new Set(soldeInfo.map((x) => x.Period))];
          let datasets = soldeInfo.reduce(function (acc, cur) {
            let Type = acc.find((x) => x.label == cur.Type);
            if (Type == null) {
              let color = '';

              switch (cur.Type) {
                case 'Food':
                  color = 'red';
                  break;
                case 'Drinks':
                  color = 'green';
                  break;
                default:
                  color ='gray';
              }

              Type = {
                label: cur.Type,
                data: [cur.Total],
                backgroundColor: color,
                borderColor: color,
                borderWidth: 1,
              };

              acc.push(Type);
            } else {
              Type.data.push(cur.Total);
            }

            return acc;
          }, []);

          var soldeInfo = {
            type: 'bar',
            data: {
              labels: labels,
              datasets: datasets,
            },
          };

            const soldeChart = document.getElementById('chartSolde');
            new Chart(soldeChart, soldeInfo);



    }
});

问题原因

当前代码的核心问题是:reduce方法只是按原始数据顺序把每个Type的Total追加到data数组,没有对应到具体的Period位置。当某个Period缺失某类Type时,后续的Total会直接补到上一个空位,导致数据和Period标签错位。

解决方法

要让每个Type的data数组和Period标签完全对应,缺失的位置填充null(Chart.js会自动跳过该位置的柱子绘制)。具体步骤:

  1. 提取所有唯一的Period作为标签,同时提取所有唯一的Type。
  2. 为每个Type初始化和标签长度一致的数组,默认填充null。
  3. 遍历原始数据,找到当前Period在标签中的索引,把Total填充到对应Type数组的指定位置。

修改后的代码:

jQuery.ajax({
    url: "../../ajax/barGraph.php?period=<?= $period; ?>",
    type: "GET",
    dataType: 'json',
    success: function(soldeInfo) {
        // 提取所有唯一Period并按时间排序,保证顺序正确
        let labels = [...new Set(soldeInfo.map(x => x.Period))].sort((a, b) => new Date(a) - new Date(b));
        // 提取所有唯一的Type类型
        let allTypes = [...new Set(soldeInfo.map(x => x.Type))];
        
        // 初始化每个Type的数据集
        let datasets = allTypes.map(type => {
            // 创建和标签长度一致的数组,默认填充null
            let data = new Array(labels.length).fill(null);
            // 筛选当前Type的所有数据
            let typeData = soldeInfo.filter(item => item.Type === type);
            
            // 把对应Period的Total填充到指定索引位置
            typeData.forEach(item => {
                let index = labels.indexOf(item.Period);
                if (index !== -1) {
                    data[index] = item.Total;
                }
            });
            
            // 设置对应颜色
            let color = '';
            switch (type) {
                case 'Food':
                    color = 'red';
                    break;
                case 'Drinks':
                    color = 'green';
                    break;
                default:
                    color = 'gray';
            }
            
            return {
                label: type,
                data: data,
                backgroundColor: color,
                borderColor: color,
                borderWidth: 1,
            };
        });

        var chartConfig = {
            type: 'bar',
            data: {
                labels: labels,
                datasets: datasets,
            },
        };

        const soldeChart = document.getElementById('chartSolde');
        new Chart(soldeChart, chartConfig);
    }
});

额外说明

  • 对Period标签做了时间排序,避免原始数据顺序混乱导致的标签错位。
  • 每个Type的data数组和标签完全对齐,缺失数据的位置用null填充,Chart.js会自动不绘制该位置的柱子,彻底解决错位问题。
  • 逻辑更清晰,先构建完整结构再填充数据,避免了原代码中顺序追加的漏洞。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 15:50:59