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

D3.js分组条形图网格线与坐标轴刻度自定义实现问题

解决方案

针对你提出的三个问题,修改方案如下:

1. 调整X轴网格线到分组结束边界

原有X轴网格线默认使用x0比例尺的刻度(即每个分组的中心位置),我们可以自定义网格刻度值,计算每个分组的右侧边界位置作为网格线的绘制位置。

2. 网格线移至图表下层

SVG元素遵循「先渲染的元素层级更低」的规则,将网格线的渲染逻辑移到条形图柱子、坐标轴的渲染逻辑之前即可。

3. Y轴刻度改为完整数值

原有Y轴调用了ticks(null, 's'),其中s参数表示使用SI单位缩写,删除该参数即可取消k格式的简写。


修改后完整代码

<html>
  <head>
    <meta charset="UTF-8" />
  </head>
  <body>
    <div id="grouped-chart"></div>
    <script src="https://d3js.org/d3.v4.min.js"></script>
    <script>
      const data = [
        {
          category: {
            model: 'A',
          },
          type1: '1000',
          type2: '2000',
        },
        {
          category: {
            model: 'B',
          },
          type1: '2000',
          type2: '3000',
        },
        {
          category: {
            model: 'C',
          },
          type1: '1500',
          type2: '4000',
        },
      ];
      const margin = { top: 20, right: 30, bottom: 30, left: 60 };
      const width = 400 - margin.left - margin.right;
      const height = 400 - margin.top - margin.bottom;
      const svg = d3
        .select('#grouped-chart')
        .append('svg')
        .attr('width', width + margin.left + margin.right)
        .attr('height', height + margin.top + margin.bottom)
        .style('background', '#fff');
      const g = svg
        .append('g')
        .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
      const x0 = d3.scaleBand().rangeRound([0, width]).paddingInner(0.1);

      const x1 = d3.scaleBand().padding(0.05);

      const y = d3.scaleLinear().rangeRound([height, 0]);

      const z = d3.scaleOrdinal().range(['#004c6d', '#255e7e', '#3d708f']);
      const keys = Object.keys(data[0]).slice(1);
      x0.domain(data.map((d) => d.category.model));
      x1.domain(keys).rangeRound([0, x0.bandwidth()]);
      y.domain([0, 4000]);

      // 先渲染网格(最下层)
      // Y轴网格
      g.append('g')
        .attr('class', 'grid')
        .call(d3.axisLeft().scale(y).tickSize(-width, 0, 0).tickFormat(''));
      // X轴网格:自定义刻度为每个分组的右侧边界
      const xGridTicks = x0.domain().map(d => x0(d) + x0.bandwidth());
      g.append('g')
        .attr('class', 'grid')
        .attr('transform', `translate(0, ${height})`)
        .call(d3.axisBottom().scale(x0.copy().domain(xGridTicks)).tickSize(-height, 0, 0).tickFormat(''));

      // 再渲染坐标轴
      const gX = g
        .append('g')
        .attr('class', 'axis')
        .attr('transform', 'translate(0,' + height + ')')
        .call(d3.axisBottom(x0));

      const gY = g
        .append('g')
        .attr('class', 'axis')
        // 删除's'参数取消SI单位缩写
        .call(d3.axisLeft(y).ticks(null));

      // 最后渲染柱子(最上层)
      g.append('g')
       .selectAll('g')
       .data(data)
       .enter()
       .append('g')
       .attr('transform', (d) => 'translate(' + x0(d.category.model) + ',0)')
       .selectAll('rect')
       .data((d) =>
         keys.map((key) => {
           return { key: key, value: d[key] };
         })
       )
       .enter()
       .append('rect')
       .attr('x', (d) => x1(d.key))
       .attr('y', (d) => y(d.value))
       .attr('width', x1.bandwidth())
       .attr('height', (d) => height - y(d.value))
       .attr('fill', (d) => z(d.key));
    </script>
  </body>
</html>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 08:54:03