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

JS D3带时间刻度图表如何将X轴数字替换为数组内日期

D3折线图X轴替换为日期的解决方案

核心问题

报错和显示异常主要由以下几个错误导致:

  • X轴使用了仅支持数字的线性比例尺scaleLinear,日期类型数据需要使用D3提供的时间比例尺scaleTime
  • 日期重复解析:已经在遍历xdata的循环里把日期字符串转成了Date对象,后续生成dataset时再次调用parseDate解析已转换的Date对象,会得到null值导致日期失效
  • Y轴范围配置错误:原Y轴range([height, max_value])不符合SVG坐标规则,会导致数值显示偏移
  • 折线、圆点、标签的X坐标仍然使用索引计算,没有绑定实际日期值

修改步骤

  1. 替换X轴线性比例尺为时间比例尺,定义域取数据集的最小、最大日期值
  2. 移除dataset生成时的重复日期解析逻辑
  3. 修正Y轴范围配置为range([height, 0]),匹配SVG坐标从上到下增大的规则
  4. 将折线生成器、圆点、标签的X坐标取值改为从日期字段获取
  5. 自定义X轴日期显示格式,避免默认格式过于复杂

完整修正代码

<!DOCTYPE html>
<meta charset="utf-8">

<body>
</body>

<!-- 加载d3库 -->
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>
// 边距配置
var margin = {top: 200, right: 300, bottom: 400, left: 300}
  , width = window.innerWidth - margin.left - margin.right 
  , height = window.innerHeight - margin.top - margin.bottom;

var parseDate = d3.timeParse("%Y-%m-%d");
// 定义日期格式化工具,用于X轴显示
var formatDate = d3.timeFormat("%Y-%m-%d");

// 原始数据
var xdata = [
    ["2021-08-01",(d3.randomUniform(100)()).toFixed(1)],
    ["2021-08-02",(d3.randomUniform(100)()).toFixed(1)],
    ["2021-08-03",(d3.randomUniform(100)()).toFixed(1)],
    ["2021-08-04",(d3.randomUniform(100)()).toFixed(1)],
    ["2021-08-05",(d3.randomUniform(100)()).toFixed(1)],
    ["2021-08-06",(d3.randomUniform(100)()).toFixed(1)],
    ["2021-08-07",(d3.randomUniform(100)()).toFixed(1)],
    ["2021-08-08",(d3.randomUniform(100)()).toFixed(1)],
    ["2021-08-09",(d3.randomUniform(100)()).toFixed(1)],
    ["2021-08-10",(d3.randomUniform(100)()).toFixed(1)],
    ["2021-08-11",(d3.randomUniform(100)()).toFixed(1)]
];

var n = xdata.length;
var max_value = 0;
var col1 = 0;
for (let i = 0; i < n; i++) {
xdata[i][0] = parseDate(xdata[i][0]);
col1 = parseFloat(xdata[i][1])
if (col1 > max_value)
    max_value = col1
}

// 生成数据集,移除重复日期解析
var dataset = xdata.map(function(d) {
      return {
         x: d[0],
         y: parseFloat(d[1])
      };
  });

// X轴改用时间比例尺
var xScale = d3.scaleTime()
  .domain(d3.extent(dataset, d => d.x)) // 输入为日期范围
  .range([0, width]); // 输出为像素范围

// 修正Y轴range配置
var yScale = d3.scaleLinear()
    .domain([0, max_value]) // 输入为数值范围
    .range([height, 0]); // 输出匹配SVG坐标规则

// 修改线生成器X坐标取值
var line = d3.line()
    .x(function(d) { return xScale(d.x); }) // 从日期字段取X值
    .y(function(d) { return yScale(d.y); })
    .curve(d3.curveMonotoneX)

// 挂载SVG容器
var svg = d3.select("body").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

// 渲染X轴,新增日期格式化配置
svg.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + height + ")")
    .call(d3.axisBottom(xScale).tickFormat(formatDate));

// 渲染Y轴
svg.append("g")
    .attr("class", "y axis")
    .call(d3.axisLeft(yScale));

// 渲染折线
svg.append("path")
    .datum(dataset)
    .attr("fill", "none")
    .attr("stroke", "steelblue")
    .attr("stroke-width", 3)
    .attr("d", line);

// 渲染数据点
svg.selectAll(".dot")
    .data(dataset)
  .enter().append("circle")
    .style("fill","steelblue")
    .attr("cx", function(d) { return xScale(d.x) })
    .attr("cy", function(d) { return yScale(d.y) })
    .attr("r", 5);

// 渲染数值标签
svg.selectAll(".text")
    .data(dataset)
    .enter().append("text")
    .style("fill", "red") 
    .attr("x", function(d) { return xScale(d.x) - 15 })
    .attr("y", function(d) { return yScale(d.y) - 10 })
    .text(function(d) { return d.y });
    
</script>

运行修正后的代码即可看到X轴正常显示日期,折线、圆点、数值标签位置完全匹配。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 20:45:00