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

基于D3.js创建带日期范围的时间线条形图技术问询

D3.js 实现指定日期范围的双轴日期标记图

核心实现步骤

1. 初始化基础配置与比例尺

先处理日期格式并定义核心比例尺:

  • 日期解析:用d3.timeParse将字符串日期转为可计算的Date对象,保证时区解析准确
  • X轴时间比例尺:基于指定起止日期生成连续时间轴,同时生成20个均匀分布的中间日期刻度
  • Y轴分类比例尺:绑定Actual和Scheduled两个静态分类,分配垂直位置
// 匹配输入ISO格式的日期解析器
const parseDate = d3.timeParse("%Y-%m-%dT%H:%M:%S%Z");

// 解析起止日期
const startDate = parseDate(this.startEndDateXAxis[0]);
const endDate = parseDate(this.startEndDateXAxis[1]);

// X轴时间比例尺
const xScale = d3.scaleTime()
  .domain([startDate, endDate])
  .range([margin.left, width - margin.right]);

// 生成20个均匀分布的中间日期刻度
const xTicks = d3.range(0, 20).map(i => {
  const fraction = i / 19; // 20个点对应19个间隔
  return new Date(startDate.getTime() + fraction * (endDate.getTime() - startDate.getTime()));
});

// Y轴分类比例尺
const yScale = d3.scaleBand()
  .domain(['Actual', 'Scheduled'])
  .range([margin.top, height - margin.bottom])
  .padding(0.3); // 控制两个分类的垂直间距

2. 绘制坐标轴

将配置好的比例尺绑定到坐标轴组件,添加到SVG容器:

// 创建X轴
const xAxis = d3.axisBottom(xScale)
  .tickValues(xTicks) // 使用自定义的20个刻度
  .tickFormat(d3.timeFormat("%m/%d %H:%M")); // 自定义日期显示格式

svg.append("g")
  .attr("transform", `translate(0, ${height - margin.bottom})`)
  .call(xAxis)
  .selectAll("text")
  .style("text-anchor", "end")
  .attr("dx", "-.8em")
  .attr("dy", ".15em")
  .attr("transform", "rotate(-45)"); // 旋转标签避免重叠

// 创建Y轴
const yAxis = d3.axisLeft(yScale);

svg.append("g")
  .attr("transform", `translate(${margin.left}, 0)`)
  .call(yAxis);

3. 绘制Actual/Scheduled日期标记线

遍历数据,在对应位置绘制2px宽度的垂直标记线:

// 绘制Actual日期标记
svg.selectAll(".actual-mark")
  .data(this.timelineData)
  .enter()
  .append("line")
  .attr("class", "actual-mark")
  .attr("x1", d => xScale(parseDate(d.actualDate)))
  .attr("x2", d => xScale(parseDate(d.actualDate)))
  .attr("y1", yScale('Actual'))
  .attr("y2", yScale('Actual') + yScale.bandwidth())
  .attr("stroke", "#2ecc71") // 绿色标记Actual
  .attr("stroke-width", 2);

// 绘制Scheduled日期标记
svg.selectAll(".scheduled-mark")
  .data(this.timelineData)
  .enter()
  .append("line")
  .attr("class", "scheduled-mark")
  .attr("x1", d => xScale(parseDate(d.scheduledDate)))
  .attr("x2", d => xScale(parseDate(d.scheduledDate)))
  .attr("y1", yScale('Scheduled'))
  .attr("y2", yScale('Scheduled') + yScale.bandwidth())
  .attr("stroke", "#3498db") // 蓝色标记Scheduled
  .attr("stroke-width", 2);

关键注意事项

  • 时区处理:输入日期带时区偏移时,确保d3.timeParse格式字符串包含%Z,避免解析偏差
  • SVG布局:提前定义margin、width、height变量,预留足够边距显示坐标轴标签
  • 样式自定义:可通过CSS类控制标记线的颜色、宽度,或添加hover效果增强交互性

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 17:03:37