首页 > web前端 > js教程 > 正文

Chart.js 实现分组堆叠柱状图:数据转换与配置详解

DDD
发布: 2025-11-06 13:11:34
原创
946人浏览过

chart.js 实现分组堆叠柱状图:数据转换与配置详解

本教程详细介绍了如何在 Chart.js 中创建分组堆叠柱状图。文章从理解 Chart.js 对数据结构的要求出发,逐步演示了如何将复杂的原始数据(包含设备、用户及其点数)转换为 Chart.js 可识别的格式。重点讲解了数据扁平化、类别识别以及数据集构建过程,并提供了完整的 Chart.js 配置代码,特别是堆叠选项的设置,旨在帮助开发者高效地实现此类复杂图表。

数据可视化领域,分组堆叠柱状图是一种强大的工具,能够清晰地展示不同类别在多个分组下的构成和总和。Chart.js 作为一个流行的 JavaScript 图表库,提供了丰富的功能来实现这类图表。本文将深入探讨如何处理原始数据,并将其适配 Chart.js 的要求,最终呈现一个分组堆叠柱状图。

理解 Chart.js 对数据结构的要求

Chart.js 绘制柱状图时,通常需要两个核心部分:

  1. labels: 这代表图表的 X 轴标签,对于分组堆叠柱状图,它通常是每个“组”的名称(例如,设备名称)。
  2. datasets: 这是一个数组,每个元素代表图表中的一个数据集。在堆叠柱状图中,每个数据集通常代表一个堆叠的“层”(例如,一个用户)。每个数据集对象包含:
    • label: 数据集的名称(例如,用户名)。
    • data: 一个数组,包含对应 labels 中每个分组的数据点。
    • backgroundColor: 数据集的颜色。

原始数据结构分析

假设我们有以下原始数据,它描述了不同设备上各个用户的点数:

// 原始数据示例
const alldata = [
    {
        device: "Laptop",
        values: [
            { amckinlay: '30' },
            { cvu: '150' }
        ]
    },
    {
        device: "Phone",
        values: [
            { amckinlay: '100' }
        ]
    }
];
登录后复制

这个数据结构的问题在于 values 数组中的每个对象是一个键值对,其键名(用户)是动态的,这使得直接提取和构建 Chart.js 所需的 datasets 变得困难。我们需要将其转换为更易于处理的扁平化结构。

数据预处理与转换

为了满足 Chart.js 的数据结构要求,我们需要对原始数据进行一系列转换。

1. 提取 X 轴标签(设备名称)

首先,从原始数据中提取所有唯一的设备名称,作为图表的 X 轴 labels。

腾讯智影-AI数字人
腾讯智影-AI数字人

基于AI数字人能力,实现7*24小时AI数字人直播带货,低成本实现直播业务快速增增,全天智能在线直播

腾讯智影-AI数字人 73
查看详情 腾讯智影-AI数字人
const labels = alldata.map((x) => x.device);
// 结果: ['Laptop', 'Phone']
登录后复制

2. 扁平化并标准化数据

将原始的嵌套结构转换为一个扁平化的数组,其中每个元素都包含 device、category(用户)和 value(点数)。

let transformedData = alldata
  .map((x) =>
    x.values.reduce((acc, cur) => {
      for (let k in cur) {
        acc.push({
          device: x.device,
          category: k, // 用户名
          value: parseInt(cur[k], 10), // 点数,转换为数字
        });
      }
      return acc;
    }, [])
  )
  .flat();

/*
transformedData 结果示例:
[
  { device: 'Laptop', category: 'amckinlay', value: 30 },
  { device: 'Laptop', category: 'cvu', value: 150 },
  { device: 'Phone', category: 'amckinlay', value: 100 }
]
*/
登录后复制

这里,我们使用 map 遍历每个设备,然后用 reduce 将其 values 数组中的键值对转换为标准的对象格式,最后用 flat() 将所有设备的数据扁平化到一个数组中。

3. 识别堆叠类别(用户名称)

从扁平化后的数据中提取所有唯一的 category(即用户名),这些将作为每个 dataset 的 label。

const subLabels = [...new Set(transformedData.map((x) => x.category))];
// 结果: ['amckinlay', 'cvu']
登录后复制

4. 构建 Chart.js 数据集 (datasets)

这是最关键的一步。我们需要遍历 subLabels(用户),为每个用户创建一个 dataset 对象。每个 dataset 的 data 数组应该包含该用户在所有设备上的点数,如果某个用户在某个设备上没有数据,则填入 0。同时,定义每个类别的背景颜色。

// 定义每个类别的颜色设置
const colorSettings = [
  {
    category: 'amckinlay',
    backgroundColor: 'rgba(75, 192, 192, 0.6)',
  },
  {
    category: 'cvu',
    backgroundColor: 'rgba(255, 99, 132, 0.6)',
  },
  // 可以添加更多类别和颜色
];

const datasets = subLabels.reduce((acc, currentCategory) => {
  const categoryData = [];
  for (let device of labels) {
    // 查找当前类别(用户)在当前设备上的值,如果没有则为0
    const value =
      transformedData.find(
        (x) => x.device === device && x.category === currentCategory
      )?.value ?? 0;
    categoryData.push(value);
  }

  // 获取当前类别的颜色
  const color = colorSettings.find((x) => x.category === currentCategory)
    ?.backgroundColor;

  acc.push({
    label: currentCategory,
    data: categoryData,
    backgroundColor: color,
  });

  return acc;
}, []);

/*
datasets 结果示例:
[
  {
    label: 'amckinlay',
    data: [30, 100], // 'Laptop' 30, 'Phone' 100
    backgroundColor: 'rgba(75, 192, 192, 0.6)'
  },
  {
    label: 'cvu',
    data: [150, 0], // 'Laptop' 150, 'Phone' 0
    backgroundColor: 'rgba(255, 99, 132, 0.6)'
  }
]
*/
登录后复制

Chart.js 配置

数据准备就绪后,就可以配置 Chart.js 来绘制图表了。关键在于设置 options.scales.x.stacked 和 options.scales.y.stacked 为 true,以启用堆叠功能。

<!DOCTYPE html>
<html>
<head>
    <title>Chart.js 分组堆叠柱状图</title>
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <style>
        #myChart {
            max-width: 800px;
            margin: 20px auto;
        }
    </style>
</head>
<body>
    <canvas id="myChart"></canvas>

    <script>
        // 原始数据
        const alldata = [
            {
                device: "Laptop",
                values: [
                    { amckinlay: '30' },
                    { cvu: '150' }
                ]
            },
            {
                device: "Phone",
                values: [
                    { amckinlay: '100' }
                ]
            }
        ];

        // 1. 提取 X 轴标签(设备名称)
        const labels = alldata.map((x) => x.device);

        // 2. 扁平化并标准化数据
        let transformedData = alldata
          .map((x) =>
            x.values.reduce((acc, cur) => {
              for (let k in cur) {
                acc.push({
                  device: x.device,
                  category: k,
                  value: parseInt(cur[k], 10),
                });
              }
              return acc;
            }, [])
          )
          .flat();

        // 3. 识别堆叠类别(用户名称)
        const subLabels = [...new Set(transformedData.map((x) => x.category))];

        // 定义每个类别的颜色设置
        const colorSettings = [
          {
            category: 'amckinlay',
            backgroundColor: 'rgba(75, 192, 192, 0.6)',
          },
          {
            category: 'cvu',
            backgroundColor: 'rgba(255, 99, 132, 0.6)',
          },
        ];

        // 4. 构建 Chart.js 数据集 (datasets)
        const datasets = subLabels.reduce((acc, currentCategory) => {
          const categoryData = [];
          for (let device of labels) {
            const value =
              transformedData.find(
                (x) => x.device === device && x.category === currentCategory
              )?.value ?? 0;
            categoryData.push(value);
          }

          const color = colorSettings.find((x) => x.category === currentCategory)
            ?.backgroundColor;

          acc.push({
            label: currentCategory,
            data: categoryData,
            backgroundColor: color,
          });

          return acc;
        }, []);

        // Chart.js 实例化
        const ctx = document.getElementById('myChart').getContext('2d');
        const myChart = new Chart(ctx, {
          type: 'bar', // 图表类型为柱状图
          data: {
            labels: labels, // X 轴标签
            datasets: datasets, // 数据集
          },
          options: {
            responsive: true, // 响应式布局
            scales: {
              x: {
                stacked: true, // X 轴堆叠
              },
              y: {
                stacked: true, // Y 轴堆叠
                beginAtZero: true // Y 轴从0开始
              },
            },
            plugins: {
                title: {
                    display: true,
                    text: '设备用户点数分组堆叠柱状图'
                }
            }
          },
        });
    </script>
</body>
</html>
登录后复制

注意事项

  • 数据完整性: 确保所有可能的类别在 colorSettings 中都有对应的颜色定义,以避免图表样式缺失。
  • 零值处理: 在构建 datasets 时,对于某个类别在特定分组下没有数据的情况,我们将其值设置为 0。这是确保 data 数组长度与 labels 匹配,并正确显示堆叠图的关键。
  • 响应式设计 responsive: true 选项可以使图表在容器大小变化时自动调整。
  • 数据类型: 确保所有数值数据都已正确转换为数字类型,例如使用 parseInt() 或 parseFloat()。

总结

通过上述步骤,我们成功地将复杂的原始数据转换为 Chart.js 所需的格式,并配置了一个功能完善的分组堆叠柱状图。核心在于理解 Chart.js 的数据模型,并通过数据转换逻辑将原始数据适配到这个模型中。掌握数据预处理和 Chart.js 配置中的 stacked 选项,是实现此类高级图表的关键。

以上就是Chart.js 实现分组堆叠柱状图:数据转换与配置详解的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号