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

D3.js绘制甘特图时translate(0,0)引发Y轴元素偏移异常

问题描述

使用d3.js v7绘制甘特图时出现异常:gantt-y-axis是左侧固定的Y轴信息容器,gantt-chart存储甘特图主体内容。其中yAxisG(g类型元素)执行translate(0,0)后,左边界未与父元素yAxisSvg左边界对齐,反而跑到了yAxisSvg外侧;但ganttG执行同样的translate(0,0)却能与父元素ganttSvg左边界正常对齐。目前只能通过设置偏移量将yAxisG右移拉回容器内,但偏移量难以控制,需明确该异常的原因。

相关代码

JavaScript代码

function drawGanttChart(entries) {
    d3.select('#gantt-chart').selectAll('*').remove();
    d3.select('#gantt-y-axis').selectAll('*').remove();
    const yAxisSvg = d3.select('#gantt-y-axis').append('svg')
        .attr('width', margin.left)
        .attr('height', height);

    const ganttSvg = d3.select('#gantt-chart').append('svg')
        .attr('width', svgWidth)
        .attr('height', height);
        
    const yAxisG = yAxisSvg.append('g').attr('transform', `translate(0,0)`);
    const ganttG = ganttSvg.append('g').attr('transform', `translate(0,0)`);
    
    const x = d3.scaleTime()
        .domain([startTimeExtent[0], endTimeExtent[1]])
        .range([0, width]);

    const y = d3.scaleBand()
        .domain(uniqueResources)
        .range([0, height - margin.top - margin.bottom])
        .padding(0.2);
        
    yAxisG.append('g')
        .attr('class', 'axis axis--y')
        .call(d3.axisLeft(y));

    ganttG.append('g')
        .attr('class', 'axis axis--x')
        .attr('transform', `translate(0,0)`)
        .call(d3.axisBottom(x)
            .ticks(d3.timeMillisecond.every(100))
            .tickFormat(customTimeFormat)); 
    
    ganttG.selectAll('.bar')
        .data(entries)
        .enter().append('rect')
        .attr('class', 'bar')
        .attr('x', d => x(new Date(d['StartTime'])))
        .attr('y', d => y(d['ResourceName']))
        .attr('width', d => x(new Date(d['EndTime'])) - x(new Date(d['StartTime'])))
        .attr('height', y.bandwidth())
}

CSS代码

#gantt-y-axis {
    position: sticky;
    left: 0;
    background: white; /* 确保背景色与图表一致 */
    z-index: 1;
    font-family:sans-serif;
    font-size: 10px;
}

#gantt-chart {
    flex: 1 0 auto;
    overflow-x: auto;
    overflow-y: auto;
    white-space: nowrap;
}
原因分析与解决方案

原因

  • D3的axisLeft()方法生成的Y轴,默认会为刻度标签预留左侧空间,导致整个轴组(g元素)向左偏移,超出SVG容器的左边界。而axisBottom()生成的X轴不存在这个方向的偏移问题,因此ganttG表现正常。
  • 你设置的yAxisSvg宽度为margin.left,该宽度可能刚好等于或小于Y轴标签所需的左侧空间,直接导致轴元素溢出到SVG容器外部。

解决方案

  1. 调整SVG容器宽度:在margin.left基础上增加刻度标签的预估宽度,确保容器能容纳整个Y轴;或通过d3.axisLeft(y).tickSizeOuter(0)去掉外侧刻度,减少轴的偏移量。
  2. 手动设置偏移:给yAxisG设置合适的translate偏移,将轴拉回SVG内部,例如:
    const yAxisG = yAxisSvg.append('g').attr('transform', `translate(20, 0)`);
    
    其中20为适配标签宽度的偏移值,可根据实际情况调整。
  3. 动态计算宽度:获取Y轴元素的实际宽度后,动态调整yAxisSvg的宽度,确保容器足够容纳轴内容:
    yAxisG.append('g')
      .attr('class', 'axis axis--y')
      .call(d3.axisLeft(y))
      .call(axis => {
        const bbox = axis.node().getBBox();
        yAxisSvg.attr('width', bbox.width + Math.abs(bbox.x));
      });
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 13:03:14