D3.js独立X/Y轴缩放时轴域自动对齐问题求助
D3.js独立X/Y轴缩放时轴域自动对齐问题求助
嘿,我仔细看了你的代码,发现问题根源在于你每次都是基于初始的staticBaseX/staticBaseY来重新计算缩放域,而不是基于当前已经调整过的baseX/baseY。这就导致只要触发了“同时更新X/Y”的操作(比如单指平移、对角线 pinch、滚轮),轴域就会被拉回和初始缩放绑定的状态,看起来像是“自动对齐”了。
举个例子:假设你已经单独缩放X轴,把X域改成了[-20,20],这时候做一次单指平移,你用t.rescaleX(staticBaseX)计算新域,但staticBaseX的初始域是[-10,10],所以平移后的X域会基于初始范围重新计算,直接覆盖你之前调整好的X域,看起来就像是突然“跳回去”和Y域对齐了——这就是你看到的“snap”行为。
解决思路
- 单独缩放X/Y轴时,继续用
staticBaseX/staticBaseY来rescale,这样能保证只修改目标轴,另一轴的当前状态不受影响。 - 对于平移、对角线 pinch、滚轮这类需要同时调整X/Y的操作,必须基于**当前的
baseX/baseY**来计算新域,这样才能在已调整的范围基础上继续变换,不会出现跳回的情况。
修改后的代码
const staticBaseX = d3.scaleLinear().domain([-10, 10]).range([margin, svgWidth - margin]); const staticBaseY = d3.scaleLinear().domain([-10, 10]).range([svgHeight - margin, margin]); let baseX = staticBaseX.copy(); let baseY = staticBaseY.copy(); const ANGLE_TOLERANCE = 10; // degrees const zoomBehavior = d3.zoom() .filter((event) => { const t = event.type; return t === 'wheel' || t === 'mousedown' || t === 'mousemove' || t === 'touchstart' || t === 'touchmove'; }) .scaleExtent([1e-6, 1e6]) .on('zoom', (event) => { const t = event.transform; const se = event.sourceEvent; let newX = baseX.domain(); let newY = baseY.domain(); if (se?.touches && se.touches.length === 2) { // Two-finger pinch gesture — detect angle const [p1, p2] = se.touches; const dx = p2.clientX - p1.clientX; const dy = p2.clientY - p1.clientY; let angle = Math.abs(Math.atan2(dy, dx)) * 180 / Math.PI; if (angle > 180) angle -= 180; const nearH = angle <= ANGLE_TOLERANCE || angle >= 180 - ANGLE_TOLERANCE; const nearV = angle >= 90 - ANGLE_TOLERANCE && angle <= 90 + ANGLE_TOLERANCE; if (nearH) { // Only update X, keep Y fixed newX = t.rescaleX(staticBaseX).domain(); } else if (nearV) { // Only update Y, keep X fixed newY = t.rescaleY(staticBaseY).domain(); } else { // Diagonal: update both based on current domains newX = t.rescaleX(baseX).domain(); newY = t.rescaleY(baseY).domain(); } } else { // Pan, wheel, or single-finger: update both based on current domains newX = t.rescaleX(baseX).domain(); newY = t.rescaleY(baseY).domain(); } // Store the current domains currentXRange = newX; currentYRange = newY; baseX.domain(newX); baseY.domain(newY); plotGraph(currentExpr, currentXRange, currentYRange, true); });
额外说明
修改后你可以测试一下:单独缩放X/Y轴的逻辑保持正常,而平移、对角线缩放、滚轮操作会基于你当前调整好的轴域继续变换,不会再出现“自动对齐”的跳变问题。另外滚轮缩放的行为也会更符合预期——基于当前的轴域进行同步缩放,而不是每次都回到初始范围重新计算。
内容来源于stack exchange
相关产品推荐
相关产品推荐

