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

Chart.js水平条形图无法修改条形宽度的技术求助

Chart.js水平条形图:自定义条形宽度+独立图例解决方案

问题描述

用Chart.js实现水平条形图时遇到两个核心问题:

  • 无法调整条形的宽度
  • 若将所有数据合并到单个数据集,无法为每个Y轴条目显示独立颜色的图例

为实现Y轴每个条目对应独立图例,我采用了每个分类单独创建数据集的方式,格式如下:

data: [99, null, null, null, null, null, null, null, null],

以下是原始实现代码:

原始JavaScript代码

var chrt = document.getElementById("chartId").getContext("2d");

var chartId = new Chart(chrt, {
   type: 'Capacity', // 无效配置,会被下一行覆盖
   type: 'bar',
   data: {
      labels: ["Amkor-FJ", "ASE-CL", "ASE-KH", "ATMC", "Global7", "SSMC", "TSMC8", "TSTSTAT", "UMCF8E"],
      datasets: [
         {
            label: "Amkor-FJ",
            data: [99, null, null, null, null, null, null, null, null],
            backgroundColor: "yellow",
            borderColor: 'yellow',
            borderWidth: 1,
         },
         {
            label: "ASE-CL",
            data: [null, 97, null, null, null, null, null, null, null],
            backgroundColor: "yellow",
            borderColor: 'yellow',
            borderWidth: 1,
         },
         {
            label: "ASE-KH",
            data: [null, null, 100, null, null, null, null, null, null],
            backgroundColor: "red",
            borderColor: 'red',
            borderWidth: 1,
         },
         {
            label: "ATMC",
            data: [null, null, null, 110, null, null, null, null, null],
            backgroundColor: "red",
            borderColor: 'red',
            borderWidth: 1,
         },
         {
            label: "Global7",
            data: [null, null, null, null, 105, null, null, null, null],
            backgroundColor: "red",
            borderColor: 'red',
            borderWidth: 1,
         },
         {
            label: "SSMC",
            data: [null, null, null, null, null, 87, null, null, null],
            backgroundColor: "green",
            borderColor: 'green',
            borderWidth: 1,
         },
         {
            label: "TSMC8",
            data: [null, null, null, null, null, null, 85, null, null],
            backgroundColor: "green",
            borderColor: 'green',
            borderWidth: 1,
         },
         {
            label: "TSTSTAT",
            data: [null, null, null, null, null, null, null, 100, null],
            backgroundColor: "yellow",
            borderColor: 'yellow',
            borderWidth: 1,
         },
         {
            label: "UMCF8E",
            data: [null, null, null, null, null, null, null, null, 92],
            backgroundColor: "green",
            borderColor: 'green',
            borderWidth: 1,
         },
      ],
   },
   options: {
      indexAxis: 'y',
      elements: {
         bar: {
            borderWidth: 2,
         }
      },
      plugins: {
         legend: {
            display: true,
            position: "bottom",
            align: "left"
         }
      },
      legend: { // 重复配置,3.x版本应放在plugins.legend下
         labels: {
            boxWidth: 1
         }
      },
      scales: {
         yAxes: [{ // 3.x版本已废弃该写法,改用scales.y
            categorySpacing: 0,
            barThickness : 73
         }],
         x: {
            beginAtZero: true,
            ticks: {                  
               callback: function (value) {
                  return (value / 100 * 100).toFixed(0) + '%';
               },
            },
            scaleLabel: {
               display: true,
               labelString: 'Percentage',
            },
         }
      }
   }
});

原始HTML代码

<div style="display:inline-block; width:400px; height:400px">
  <canvas id="chartId" aria-label="chart" width="350px" height="300px"></canvas>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.1.1/chart.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/chart.min.js"></script> <!-- 版本冲突,需移除 -->

解决方案

核心修复点

  1. 移除版本冲突:只保留一个Chart.js版本(推荐3.x,语法更统一)
  2. 统一配置语法:使用3.x版本的配置规则,废弃2.x的yAxes写法
  3. 优化数据集结构:用单个数据集+颜色数组替代多数据集,简化代码
  4. 自定义图例生成:通过插件实现每个Y轴条目的独立图例,支持点击控制显示隐藏
  5. 正确设置条形宽度:在scales.y中配置barThickness和categorySpacing

修改后的完整代码

JavaScript代码

var chrt = document.getElementById("chartId").getContext("2d");

// 定义每个条目的颜色,与labels顺序对应
const barColors = [
  "yellow", "yellow", "red", "red", "red", "green", "green", "yellow", "green"
];

var chartId = new Chart(chrt, {
   type: 'bar',
   data: {
      labels: ["Amkor-FJ", "ASE-CL", "ASE-KH", "ATMC", "Global7", "SSMC", "TSMC8", "TSTSTAT", "UMCF8E"],
      datasets: [{
         data: [99, 97, 100, 110, 105, 87, 85, 100, 92],
         backgroundColor: barColors,
         borderColor: barColors,
         borderWidth: 1,
      }]
   },
   options: {
      indexAxis: 'y',
      elements: {
         bar: {
            borderWidth: 2,
         }
      },
      plugins: {
         legend: {
            display: true,
            position: "bottom",
            align: "left",
            labels: {
               boxWidth: 12 // 调整图例方块大小
            },
            // 自定义图例生成器
            generateLabels: function(chart) {
               const labels = chart.data.labels;
               return labels.map((label, index) => ({
                  text: label,
                  fillStyle: barColors[index],
                  strokeStyle: barColors[index],
                  lineWidth: 1,
                  // 控制图例点击时的状态
                  hidden: !chart.getDataVisibility(index),
                  index: index
               }));
            }
         },
         // 处理图例点击事件
         onClick: function(e, legendItem) {
            const index = legendItem.index;
            const chart = this.chart;
            const currentVisibility = chart.getDataVisibility(index);
            chart.setDataVisibility(index, !currentVisibility);
            chart.update();
         }
      },
      scales: {
         y: {
            categorySpacing: 0, // 分类间间距
            barThickness: 30, // 条形固定宽度,可根据需求调整
            maxBarThickness: 50 // 可选,限制最大宽度
         },
         x: {
            beginAtZero: true,
            ticks: {                  
               callback: function (value) {
                  return value.toFixed(0) + '%';
               },
            },
            title: { // 3.x版本用title替代scaleLabel
               display: true,
               text: 'Percentage',
            },
         }
      }
   }
});

HTML代码

<div style="display:inline-block; width:400px; height:400px">
  <canvas id="chartId" aria-label="chart" width="350px" height="300px"></canvas>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.1.1/chart.min.js"></script>

关键说明

  • 单个数据集优势:避免多数据集导致的条形宽度无法控制问题,同时减少代码冗余
  • 自定义图例:通过generateLabels生成每个Y轴条目对应的图例,onClick事件实现点击切换对应条形的显示状态
  • 条形宽度控制:barThickness设置固定宽度,categorySpacing调整分类之间的空白,适配不同布局需求
  • 版本兼容:完全适配Chart.js 3.x版本,废弃2.x的旧配置语法

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 23:25:01