讲师中心 微信公众号
AI工具推荐 视频效率加速

Chart.js 高级教程:构建分组堆叠柱状图的数据转换与配置实践

胖敏姑娘_9025

胖敏姑娘_9025

发布时间:2025-11-06 12:16:18

|

745人浏览过

|

来源于php中文网

原创

chart.js 高级教程:构建分组堆叠柱状图的数据转换与配置实践

本教程详细介绍了如何在 Chart.js 中创建分组堆叠柱状图,以可视化多维度数据。文章重点讲解了如何将原始的复杂数据结构转换为 Chart.js 所需的格式,包括数据的扁平化处理和数据集的动态生成。同时,提供了完整的 Chart.js 配置代码,确保图表正确显示堆叠效果,帮助开发者高效实现复杂的数据可视化需求。

引言:理解分组堆叠柱状图的需求

在数据可视化中,分组堆叠柱状图是一种强大的工具,它能够同时展示多个类别(分组)在不同主维度下的累积贡献。例如,在分析用户行为时,我们可能需要在一个设备类别下,查看不同用户所贡献的积分总和,并且希望这些用户的积分以堆叠的形式展示在同一根柱子上,而不同的设备则作为独立的柱子分组。

Chart.js 是一个流行的 JavaScript 图表库,但要实现这种复杂的分组堆叠效果,关键在于如何将原始数据结构正确地转换为 Chart.js 所期望的 data 和 datasets 格式。通常,原始数据可能包含嵌套的或非标准的对象结构,这需要进行细致的预处理。

Chart.js 数据结构解析

Chart.js 的柱状图数据主要由两部分组成:

  1. labels: 这通常对应于图表的 X 轴分类,代表主分组。在我们的场景中,这将是设备名称(如 "Laptop", "Phone")。
  2. datasets: 这是一个数组,数组中的每个对象代表一个数据系列(或称子分组)。对于堆叠柱状图,每个 dataset 对象通常代表一个堆叠的类别(如用户名称 "amckinlay", "cvu")。每个 dataset 对象内部的 data 数组,其索引应与 labels 数组的索引相对应,存储该子分组在每个主分组下的具体数值。

原始数据结构如下所示:

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

这种结构的问题在于 values 数组中的对象是键值对的形式({amckinlay: '30'}),而不是扁平化的 category: 'amckinlay', value: 30 形式,这使得直接提取 datasets 变得困难。

原始数据分析与转换策略

为了适配 Chart.js 的要求,我们需要将原始数据进行以下转换:

  1. 提取主标签(X 轴): 从 alldata 中提取所有唯一的 device 名称,作为 Chart.js 的 labels。
  2. 扁平化并重构数据: 将 alldata 中的 values 数组进行扁平化处理,并将其中的键值对转换为更易于处理的 device、category 和 value 字段。
    • 目标中间结构:{ device: "Laptop", category: "amckinlay", value: 30 }。
  3. 识别子标签(堆叠类别): 从扁平化后的数据中提取所有唯一的 category 名称(如用户名称),作为 datasets 的 label 属性。
  4. 动态生成 Chart.js 数据集: 根据识别出的子标签,遍历所有主标签,为每个子标签构建一个 dataset 对象,并填充其 data 数组。

数据转换实现

我们将通过一系列 JavaScript 数组方法来完成上述数据转换。

dmap-jsapi-skill
dmap-jsapi-skill

DMap GL地图JSAPI(dmapgl)开发指南。用于编写、审查、调试 DMap 地图 API 代码,涵盖地图初始化、覆盖物渲染、图层管理、事件处理、控件交互等任务。当用户提及 dmap、dmapgl、jsapi‑gl 或相关地图开发需求时自动触发。

下载

1. 定义颜色配置

为了使图表更具可读性,我们可以预定义每个类别的颜色。

const colorSettings = [
  {
    category: 'amckinlay',
    backgroundColor: 'rgba(75, 192, 192, 0.6)',
  },
  {
    category: 'cvu',
    backgroundColor: 'rgba(255, 99, 132, 0.6)',
  },
  // 可以根据需要添加更多类别及其颜色
];

2. 提取主标签 (X 轴)

这是最直接的一步,使用 map 方法从 alldata 中提取 device 名称。

const labels = alldata.map((x) => x.device);
// 结果: ['Laptop', 'Phone']

3. 扁平化并重构数据

这一步是数据转换的核心。我们使用 map 和 reduce 结合 flat 来实现。

let transformedData = alldata
  .map((x) =>
    x.values.reduce((acc, cur) => {
      // 遍历每个 { key: value } 对象
      for (let k in cur) {
        acc.push({
          device: x.device,    // 关联设备
          category: k,         // 提取键作为类别
          value: parseInt(cur[k]), // 提取值并转换为数字
        });
      }
      return acc;
    }, []) // 初始累加器为空数组
  )
  .flat(); // 扁平化数组,将所有子数组合并成一个

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

4. 识别子标签 (堆叠类别)

从 transformedData 中提取所有唯一的 category。

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

5. 动态生成 Chart.js 数据集 (datasets)

现在我们有了 labels (设备) 和 subLabels (用户),可以开始构建 datasets 数组了。我们将遍历 subLabels,为每个用户创建一个 dataset 对象,并填充其在每个设备上的积分数据。

const datasets = subLabels.reduce((acc, currentCategory) => {
  // 为当前类别找到对应的颜色
  const categoryColor = colorSettings.find((c) => c.category === currentCategory)?.backgroundColor;

  // 初始化当前类别的 dataset 对象
  const currentDataset = {
    label: currentCategory,
    data: [],
    backgroundColor: categoryColor || 'rgba(0, 0, 0, 0.2)', // 提供一个默认颜色
  };

  // 遍历所有设备,为当前类别填充数据
  for (let device of labels) {
    // 查找当前设备和类别下的值,如果没有则默认为 0
    const value =
      transformedData.find((x) => x.device === device && x.category === currentCategory)?.value ?? 0;
    currentDataset.data.push(value);
  }

  acc.push(currentDataset);
  return acc;
}, []);

/*
datasets 结果示例:
[
  {
    label: 'amckinlay',
    data: [30, 100], // 对应 Laptop, Phone
    backgroundColor: 'rgba(75, 192, 192, 0.6)'
  },
  {
    label: 'cvu',
    data: [150, 0], // 对应 Laptop, Phone (Phone 上 cvu 的数据为 0)
    backgroundColor: 'rgba(255, 99, 132, 0.6)'
  }
]
*/

Chart.js 图表配置

数据准备就绪后,最后一步是配置 Chart.js 来渲染分组堆叠柱状图。关键在于在 options.scales 中设置 stacked: true。

const ctx = document.getElementById('myChart').getContext('2d');
const myChart = new Chart(ctx, {
  type: 'bar', // 指定图表类型为柱状图
  data: {
    labels: labels,     // 使用之前生成的设备标签
    datasets: datasets, // 使用之前生成的动态数据集
  },
  options: {
    responsive: true, // 启用响应式布局
    scales: {
      x: {
        stacked: true, // X 轴启用堆叠
        title: {
          display: true,
          text: '设备类型'
        }
      },
      y: {
        stacked: true, // Y 轴启用堆叠
        title: {
          display: true,
          text: '用户积分'
        }
      },
    },
    plugins: {
        title: {
            display: true,
            text: '各设备用户积分堆叠分布图',
            font: {
                size: 18
            }
        }
    }
  },
});

在上述配置中,x.stacked: true 和 y.stacked: true 是实现堆叠效果的核心。responsive: true 确保图表在不同尺寸的容器中都能良好显示。

注意事项与最佳实践

  1. 数据完整性处理: 在生成 datasets 时,我们使用了 ?? 0 来处理数据缺失的情况。这意味着如果某个用户在某个设备上没有数据,其积分将被视为 0。这对于堆叠图表的视觉一致性很重要。
  2. 颜色管理: 建议将颜色配置集中管理,如 colorSettings 数组所示。这不仅方便维护,还能确保不同图表之间颜色的一致性。
  3. 性能考虑: 对于非常大的数据集,数据转换的性能可能成为一个问题。在生产环境中,可以考虑在后端进行部分数据预处理,或者优化前端的转换逻辑。
  4. 用户体验: 确保图表有清晰的标题、轴标签和图例,以便用户能够轻松理解图表所传达的信息。

总结

通过本教程,我们学习了如何在 Chart.js 中创建复杂的分组堆叠柱状图。核心在于对原始数据进行有效的转换和重构,使其符合 Chart.js 的 labels 和 datasets 结构要求。具体步骤包括提取主标签、扁平化并重构数据、识别子标签,以及动态生成数据集。最后,通过在 Chart.js 配置中设置 scales.x.stacked 和 scales.y.stacked 为 true,即可实现所需的堆叠效果。掌握这些数据处理和配置技巧,将使您能够更灵活地使用 Chart.js 可视化多维度数据。

热门AI工具

更多
音述AI
音述AI Hot

一款AI音频处理工具,主要用于音述AI是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区,适合需要提升相关任务效率的用户。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

超级简历WonderCV

一款AI办公效率工具,主要用于免费求职简历模版下载制作,应届生职场人必备简历制作神器,适合需要提升相关任务效率的用户。

切问学术

切问学术是一款AI论文写作工具,复旦大学NLP团队推出的AI学术智能体。

VibeKnow
VibeKnow Hot

一款AI视频创作工具,主要用于全球首个AI知识视频创作平台,文档、文章、网页,一键生成视频,适合需要提升相关任务效率的用户。

二狗PPT
二狗PPT Hot

一款AI演示文稿工具,主要用于专为中式职场打造的AI PPT生成工具,适合需要提升相关任务效率的用户。

UpDream
UpDream Hot

一款AI视频创作工具,主要用于哔哩哔哩推出的自研AI视频创作工具,适合需要提升相关任务效率的用户。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

相关专题

更多
treenode的用法
treenode的用法

​在计算机编程领域,TreeNode是一种常见的数据结构,通常用于构建树形结构。在不同的编程语言中,TreeNode可能有不同的实现方式和用法,通常用于表示树的节点信息。更多关于treenode相关问题详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2561

2023.12.01

C++ 高效算法与数据结构
C++ 高效算法与数据结构

本专题讲解 C++ 中常用算法与数据结构的实现与优化,涵盖排序算法(快速排序、归并排序)、查找算法、图算法、动态规划、贪心算法等,并结合实际案例分析如何选择最优算法来提高程序效率。通过深入理解数据结构(链表、树、堆、哈希表等),帮助开发者提升 在复杂应用中的算法设计与性能优化能力。

356

2025.12.22

深入理解算法:高效算法与数据结构专题
深入理解算法:高效算法与数据结构专题

本专题专注于算法与数据结构的核心概念,适合想深入理解并提升编程能力的开发者。专题内容包括常见数据结构的实现与应用,如数组、链表、栈、队列、哈希表、树、图等;以及高效的排序算法、搜索算法、动态规划等经典算法。通过详细的讲解与复杂度分析,帮助开发者不仅能熟练运用这些基础知识,还能在实际编程中优化性能,提高代码的执行效率。本专题适合准备面试的开发者,也适合希望提高算法思维的编程爱好者。

397

2026.01.06

C++ 数据结构与算法实现教程合集
C++ 数据结构与算法实现教程合集

以 C++ 为实现语言,系统讲解核心数据结构与算法,涵盖链表(单链表/双链表/环检测)、栈与队列(单调栈/优先队列)、二叉树(遍历/BST/AVL/红黑树)、哈希表(开地址法/链地址法)、图(邻接表/BFS/DFS/Dijkstra/拓扑排序)、常见排序算法(快排/归并/堆排/计数排序)的实现与复杂度分析,同时分享 LeetCode 刷题技巧、竞赛编程常用模板(二分/前缀和/滑动窗口/动态规划),帮助开发者夯实算法基础。

452

2026.05.09

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

5887

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

2508

2023.08.10

golang map内存释放
golang map内存释放

本专题整合了golang map内存相关教程,阅读专题下面的文章了解更多相关内容。

590

2025.09.05

golang map相关教程
golang map相关教程

本专题整合了golang map相关教程,阅读专题下面的文章了解更多详细内容。

343

2025.11.16

Playwright 测试失败怎么办
Playwright 测试失败怎么办

Playwright测试失败专题汇集超时、定位器匹配、浏览器提前关闭、依赖与插件配置、文件上传、SSL及Docker启动等故障文章,并介绍通过截图、报告和Trace定位错误。

0

2026.10.21

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
WebStorm 官方调试文档
WebStorm 官方调试文档

共0课时 | 0人学习

React 教程
React 教程

共58课时 | 12.3万人学习

TypeScript 教程
TypeScript 教程

共19课时 | 6.7万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn