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

D3 v4中缩放平移后调整窗口时axisBottom比例尺域偏移问题

D3 v4 缩放平移后窗口resize导致X轴域偏移问题解决

问题根因

窗口resize时,你没有基于当前的缩放平移状态更新比例尺,而是直接重置了比例尺的domain,导致之前的缩放变换状态丢失,X轴域出现偏移。核心是要在resize过程中,保留并复用当前的zoom变换来更新比例尺。

解决思路

  1. 保留一个原始比例尺(比如x0),存储初始的domain和动态更新的range(对应容器宽度变化)。
  2. 绘制用的比例尺x始终通过当前zoom变换对x0进行rescale得到。
  3. 窗口resize时,先更新x0的range为新容器宽度,再用当前的zoom变换重新rescale得到新的x,最后更新轴和图表元素。

修改后的可复现代码

// 初始化SVG和容器
const svg = d3.select("#chart")
  .append("svg")
  .attr("width", "100%")
  .attr("height", 400)
  .call(d3.zoom().scaleExtent([1, 8]).translateExtent([[0, 0], [Infinity, 0]]).on("zoom", zoomed));

const margin = {top: 20, right: 20, bottom: 30, left: 20};
let width = parseInt(svg.style("width"), 10) - margin.left - margin.right;
const height = 400 - margin.top - margin.bottom;

const g = svg.append("g").attr("transform", `translate(${margin.left},${margin.top})`);

// 原始比例尺:存储初始domain,动态更新range
const x0 = d3.scaleLinear()
  .domain([0, 100])
  .range([0, width]);

// 绘制用的比例尺
let x = x0.copy();

const y = d3.scaleLinear()
  .domain([0, 100])
  .range([height, 0]);

const xAxis = g.append("g")
  .attr("class", "x-axis")
  .attr("transform", `translate(0,${height})`)
  .call(d3.axisBottom(x));

// 示例路径
const line = d3.line()
  .x(d => x(d.x))
  .y(d => y(d.y));

const data = d3.range(100).map(i => ({x: i, y: Math.random() * 100}));

g.append("path")
  .datum(data)
  .attr("fill", "none")
  .attr("stroke", "steelblue")
  .attr("stroke-width", 1.5)
  .attr("d", line);

// 缩放事件处理
function zoomed() {
  x = d3.event.transform.rescaleX(x0);
  xAxis.call(d3.axisBottom(x));
  g.select("path").attr("d", line);
}

// 窗口resize处理
window.addEventListener("resize", resize);

function resize() {
  width = parseInt(svg.style("width"), 10) - margin.left - margin.right;
  
  // 更新原始比例尺的range为新宽度
  x0.range([0, width]);
  
  // 获取当前的zoom变换
  const currentTransform = d3.zoomTransform(svg.node());
  
  // 基于新的x0和当前变换重新计算绘制用的比例尺
  x = currentTransform.rescaleX(x0);
  
  // 更新X轴和路径
  xAxis.call(d3.axisBottom(x));
  g.select("path").attr("d", line);
  
  // 更新SVG高度(可选,根据需求调整)
  svg.attr("height", 400);
}

关键说明

  • x0作为原始比例尺,只在初始化时设置domain,resize时仅更新range,保证缩放的基准始终是初始数据域。
  • currentTransform = d3.zoomTransform(svg.node())获取当前的缩放平移状态,确保resize后不会丢失之前的操作。
  • 通过transform.rescaleX(x0)重新计算x的domain,保证X轴的缩放平移状态与resize前一致,不会出现偏移。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 22:05:22