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容器外部。
解决方案
- 调整SVG容器宽度:在
margin.left基础上增加刻度标签的预估宽度,确保容器能容纳整个Y轴;或通过d3.axisLeft(y).tickSizeOuter(0)去掉外侧刻度,减少轴的偏移量。 - 手动设置偏移:给
yAxisG设置合适的translate偏移,将轴拉回SVG内部,例如:
其中const yAxisG = yAxisSvg.append('g').attr('transform', `translate(20, 0)`);20为适配标签宽度的偏移值,可根据实际情况调整。 - 动态计算宽度:获取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
相关产品推荐
相关产品推荐

