D3.js图表X轴首尾刻度仅显示部分内容的技术问询
D3.js X轴首尾刻度显示异常解决方法
问题现象
使用D3.js绘制时间轴时,X轴首尾两个非整分的刻度仅显示秒数部分,而中间间隔5分钟的整分刻度显示正常。
问题代码
JavaScript代码
let margin = ({ top: 50, right: 50, bottom: 50, left: 100 }); let dim = ({ height: 100, width: 500 }); let svg = d3.select('#foo'); svg.attr('height', dim.height); svg.attr('width', dim.width); let dateTimeExtent = [new Date('2023-12-07T08:02:38.000Z'), new Date('2023-12-07T08:10:46.000Z')]; let x = d3.scaleUtc() .domain([dateTimeExtent[0], dateTimeExtent[1]]) .range([margin.left, dim.width - margin.right]); let ticks = [dateTimeExtent[0], ...d3.utcMinute.every(5).range(dateTimeExtent[0], dateTimeExtent[1]), dateTimeExtent[1]]; /* ticks数组内容: [ "2023-12-07T08:02:38.000Z", "2023-12-07T08:05:00.000Z", "2023-12-07T08:10:00.000Z", "2023-12-07T08:10:46.000Z" ]*/ // x轴绘制 svg.append('g') .attr('transform', `translate(0,${dim.height - margin.bottom})`) .call(d3.axisBottom(x) .tickValues(ticks) .tickSizeOuter(0)) .call(g => g.selectAll('.tick > text') .attr('transform', 'rotate(90) translate(23 -12)')) // 旋转刻度文本 .call(g => g.append('text') .attr('x', dim.width - margin.right) .attr('y', -4) .attr('fill', 'currentColor') .attr('font-weight', 'bold') .attr('text-anchor', 'end') .text(''));
HTML代码
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script> <div> <svg id='foo'> </svg> </div>
问题原因
D3.js的轴组件会自动根据刻度值的时间粒度选择格式化器:中间的刻度是整分时间(如08:05:00),属于分钟级粒度,默认显示时分;而首尾刻度包含秒数(如08:02:38),时间粒度更细,被自动匹配了只显示秒的格式,导致显示异常。
解决方法
通过.tickFormat()方法统一指定时间格式,覆盖D3的自动格式化逻辑。比如使用d3.utcFormat("%H:%M:%S")显示完整的时分秒,或者根据需求调整格式字符串。
修改后的核心代码
在轴的配置中添加tickFormat:
.call(d3.axisBottom(x) .tickValues(ticks) .tickSizeOuter(0) .tickFormat(d3.utcFormat("%H:%M:%S"))) // 新增:统一时间格式
完整修改后的JavaScript代码
let margin = ({ top: 50, right: 50, bottom: 50, left: 100 }); let dim = ({ height: 100, width: 500 }); let svg = d3.select('#foo'); svg.attr('height', dim.height); svg.attr('width', dim.width); let dateTimeExtent = [new Date('2023-12-07T08:02:38.000Z'), new Date('2023-12-07T08:10:46.000Z')]; let x = d3.scaleUtc() .domain([dateTimeExtent[0], dateTimeExtent[1]]) .range([margin.left, dim.width - margin.right]); let ticks = [dateTimeExtent[0], ...d3.utcMinute.every(5).range(dateTimeExtent[0], dateTimeExtent[1]), dateTimeExtent[1]]; // x轴绘制(添加了tickFormat) svg.append('g') .attr('transform', `translate(0,${dim.height - margin.bottom})`) .call(d3.axisBottom(x) .tickValues(ticks) .tickSizeOuter(0) .tickFormat(d3.utcFormat("%H:%M:%S"))) // 统一时间格式 .call(g => g.selectAll('.tick > text') .attr('transform', 'rotate(90) translate(23 -12)')) .call(g => g.append('text') .attr('x', dim.width - margin.right) .attr('y', -4) .attr('fill', 'currentColor') .attr('font-weight', 'bold') .attr('text-anchor', 'end') .text(''));
效果说明
修改后,所有刻度都会使用指定的%H:%M:%S格式显示完整的时分秒,首尾刻度的时间信息将完整展示,不会再出现仅显示秒数的情况。
内容的提问来源于stack exchange,提问作者user2233706
相关产品推荐
相关产品推荐

