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

D3 scaleTime日期异常:初始显示2034年,缩放后仍不准确

问题分析与修复方案

核心问题

  1. 自定义滚轮事件覆盖默认缩放行为:自定义的滚轮处理函数重置了平移参数,导致缩放后视图偏离中心日期。
  2. 平移范围限制过严:translateExtent 设置为 SVG 尺寸范围,导致初始平移参数被强制截断,无法正确居中当前日期。
  3. 变量命名混淆:oneYearAgo 和 oneYearLater 实际计算的是前后一个月的日期,易引发逻辑误解。

修复代码

import { useRef, useEffect } from 'react';
import * as d3 from 'd3';

const D3Timeline = () => {
  const svgRef = useRef<SVGSVGElement>(null);
  const initializedRef = useRef(false);
  const height = 100;
  const width = 600;

  useEffect(() => {
    if (initializedRef.current) return;
    initializedRef.current = true;

    const svg = d3
      .select(svgRef.current)
      .attr('width', width)
      .attr('height', height);

    const now = new Date();
    // 修正变量命名,实际为前后一个月的日期
    const oneMonthAgo = new Date(
      now.getFullYear(),
      now.getMonth() - 1,
      now.getDate()
    );
    const oneMonthLater = new Date(
      now.getFullYear(),
      now.getMonth() + 1,
      now.getDate()
    );

    const initialStartDate = new Date(now.getTime() - 6 * 60 * 60 * 1000);
    const initialEndDate = new Date(now.getTime() + 6 * 60 * 60 * 1000);

    const x = d3
      .scaleTime()
      .domain([oneMonthAgo, oneMonthLater])
      .range([0, width]);

    const xAxisGroup = svg
      .append('g')
      .attr('transform', `translate(0,${height - 20})`);

    svg
      .append('line')
      .attr('x1', width / 2)
      .attr('y1', 0)
      .attr('x2', width / 2)
      .attr('y2', height)
      .attr('stroke', 'red')
      .attr('stroke-width', 2);

    const zoom = d3
      .zoom()
      .scaleExtent([1, 200]) // 扩大最大缩放比例以适配初始视图需求
      .extent([
        [0, 0],
        [width, height],
      ])
      .on('zoom', zoomed);

    // 初始轴渲染
    xAxisGroup.call(
      d3
        .axisBottom(x)
        .ticks(width / 80)
        .tickSizeOuter(0)
    );

    // 计算初始缩放和平移以居中当前日期并显示12小时范围
    const initialScale = width / (x(initialEndDate) - x(initialStartDate));
    const initialTranslate = -x(now) * initialScale + width / 2;

    const initialZoom = d3.zoomIdentity
      .scale(initialScale)
      .translate(initialTranslate, 0);

    svg.call(zoom).call(zoom.transform, initialZoom);

    function zoomed(event) {
      const transform = event.transform;
      const xz = transform.rescaleX(x);
      xAxisGroup.call(
        d3
          .axisBottom(xz)
          .ticks(width / 80)
          .tickSizeOuter(0)
      );

      const centerDate = xz.invert(width / 2);
      console.log(centerDate);
    }

    // 移除自定义滚轮处理,使用D3默认缩放行为
  }, []);

  return <svg ref={svgRef}></svg>;
};

修复说明

  • 移除自定义滚轮事件:D3 的 zoom 行为已内置滚轮处理,可正确保留平移参数并围绕鼠标位置缩放,避免视图跳转。
  • 删除 translateExtent:取消平移范围限制,允许初始平移参数生效,确保视图居中当前日期。
  • 调整缩放范围:将最大缩放比例从 365 提高到 200,确保初始缩放比例(约120)在允许范围内,避免被强制截断。
  • 修正变量命名:将 oneYearAgo/oneYearLater 改为 oneMonthAgo/oneMonthLater,匹配实际逻辑,避免混淆。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 06:30:55