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

基于p5.js(JavaScript)实现月份堆叠柱状图的技术咨询

使用p5.js实现堆叠柱状图

嘿,这需求我熟!用p5.js做堆叠柱状图其实很直观,我给你写了完整的实现代码,还加了详细注释,你直接就能跑起来。先看核心逻辑,再看代码:

核心实现思路

  • 先计算所有月份的最大堆叠高度(也就是单个月份所有元素的总和最大值),用来确定Y轴的范围,避免柱子超出画布
  • 给每个月份分配X轴的位置,柱子宽度根据画布宽度和月份数量自动适配
  • 每个月份的元素从底部往上堆叠绘制,每画完一个元素就更新下一个元素的起始Y坐标

完整代码示例

// 模拟你的数据结构:键是月份名称,值是该月份要堆叠的元素数组
const arrayOfMonths = {
  "month1": [2, 3],
  "month2": [1, 4, 2],
  "month3": [5, 1, 3],
  "month4": [2, 2, 2, 2]
};

// 图表配置参数
let barWidth;
const padding = 40; // 画布边缘的留白,避免内容贴边
let maxY; // Y轴的最大值(所有月份的堆叠总和的最大值)

function setup() {
  createCanvas(600, 400); // 创建画布,你可以按需调整尺寸
  // 计算每个柱子的宽度:(画布总宽度 - 左右留白) / 月份数量
  barWidth = (width - padding * 2) / Object.keys(arrayOfMonths).length;
  
  // 计算Y轴最大值:遍历所有月份,算出每个月份的总和,再取最大值
  maxY = Math.max(...Object.values(arrayOfMonths).map(monthData => 
    monthData.reduce((total, value) => total + value, 0)
  ));
}

function draw() {
  background(240); // 设置浅灰色背景
  
  // 先绘制Y轴的刻度和线条
  drawYAxis();
  
  // 遍历每个月份,绘制堆叠柱子
  const monthNames = Object.keys(arrayOfMonths);
  monthNames.forEach((month, index) => {
    const monthData = arrayOfMonths[month];
    // 当前柱子的X起始位置:左边留白 + 索引*柱子宽度
    const xPos = padding + index * barWidth;
    
    // 从画布底部(减去留白)开始往上堆叠
    let currentBottomY = height - padding;
    
    monthData.forEach(value => {
      // 把元素值映射到画布的高度范围(适配Y轴)
      const barHeight = map(value, 0, maxY, 0, height - padding * 2);
      
      // 用随机颜色区分不同堆叠层(你可以改成固定色系,比如HSB渐变)
      fill(random(50, 200), random(50, 200), random(50, 200));
      // 绘制矩形:X位置,Y起始位置(当前底部Y - 柱子高度),宽度,高度
      rect(xPos, currentBottomY - barHeight, barWidth - 5, barHeight);
      
      // 更新下一个堆叠元素的底部Y坐标
      currentBottomY -= barHeight;
    });
    
    // 绘制X轴的月份标签
    fill(0);
    textAlign(CENTER, TOP);
    text(month, xPos + barWidth/2, height - padding + 10);
  });
}

// 绘制Y轴的辅助函数
function drawYAxis() {
  stroke(0); // 线条颜色为黑色
  // 绘制Y轴线
  line(padding, padding, padding, height - padding);
  
  // 绘制Y轴的刻度和数值标签
  textAlign(RIGHT, CENTER);
  for (let i = 0; i <= maxY; i++) {
    // 把刻度值映射到画布的Y坐标
    const yPos = map(i, 0, maxY, height - padding, padding);
    // 绘制刻度短线
    line(padding - 5, yPos, padding, yPos);
    // 绘制刻度数值
    text(i.toString(), padding - 10, yPos);
  }
}

关键细节说明

  • 自适应尺寸:柱子宽度和Y轴范围都是自动计算的,你可以随便调整画布大小或者月份数量,图表都会自动适配
  • 堆叠逻辑:currentBottomY变量记录当前堆叠层的底部位置,每画一个元素就往上移动对应高度,完美实现堆叠效果
  • 视觉优化:柱子之间留了5px的空隙,避免挤在一起;随机颜色区分不同堆叠元素,也可以改成固定的配色方案让图表更统一

扩展建议

  • 如果想要更专业的配色,可以用colorMode(HSB)生成渐变色调,比如每个堆叠层用不同的色相
  • 可以添加鼠标悬停事件,当鼠标放到柱子上时显示对应元素的数值
  • 要是数据量很大,可以把画布改成可滚动的,或者添加缩放功能

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 03:34:16