D3.js V4甘特图iPad端X轴缩放平移异常问题求助
修复iPad端D3.js甘特图缩放平移异常问题
问题分析
iPad端出现的缩放时内容上移、恢复后下移,且无法精准针对区块缩放的问题,核心原因是:
- 触摸设备的默认浏览器行为(如滚动、缩放)干扰了D3的触摸事件处理
- d3-xyzoom在触摸操作下会产生y轴方向的意外平移/缩放,虽然代码中强制
ky=1但未锁定y轴平移 - 触摸事件的
preventDefault未正确生效(默认passive: true导致无法阻止默认行为)
修复方案及代码修改
1. 完善触摸事件拦截,阻止浏览器默认行为
修改SVG的触摸事件监听,覆盖touchstart和touchmove,并设置passive: false确保preventDefault生效:
const svg = d3.select("#chart").append("svg") .attr("width", WIDTH) .attr("height", HEIGHT) .on("touchstart touchmove", function () { d3.event.preventDefault(); }, { passive: false }); // 关键:禁用passive模式,确保能阻止默认行为
2. 完全锁定y轴的平移与缩放
在zoomer函数中,不仅强制y轴缩放比例为1,还固定y轴平移值为初始位置(避免触摸操作产生y方向偏移):
function zoomer() { const FULL_DATE_RANGE_MILLISECS = 604800000; const WEEK_NUMBER_RANGE_MILLISECS = 21427200000; let transform = d3.event.transform; // 完全锁定y轴:缩放比例固定为1,平移固定为0(对应g元素初始位置) transform.ky = 1; transform.y = 0; g.attr("transform", `translate(${transform.x},${transform.y}) scale(${transform.kx},${transform.ky})`); // 以下原有逻辑保持不变 var new_xScale = transform.rescaleX(xScale); var visibleTimeSpan = new_xScale.domain()[1] - new_xScale.domain()[0]; if (visibleTimeSpan < FULL_DATE_RANGE_MILLISECS) { xAxis.tickFormat(d3.timeFormat('%b %d, %y')); } else if (visibleTimeSpan < WEEK_NUMBER_RANGE_MILLISECS) { xAxis.tickFormat(function (date) { return "#" + getWeekNumber(date) + ', \'' + d3.timeFormat('%y')(date); }); } else { xAxis.tickFormat(d3.timeFormat('%b %Y')); } axisG.call(xAxis.scale(new_xScale)); }
3. 配置xyzoom限制y轴范围
在xyzoom初始化时,添加translateExtent限制y轴的平移范围,从根源上阻止y轴产生偏移:
svg.call(xyzoom .extent([[0, 0], [WIDTH, HEIGHT]]) .scaleExtent([.5, 8]) .translateExtent([[0, 0], [WIDTH, 0]]) // 限制y轴只能在0位置平移 .on("zoom", zoomer));
4. 调整xyzoom的缩放比例配置
将原有的scaleRatio([1, 0])改为scaleRatio([1, 1]),确保y轴缩放比例固定为1,避免插件内部产生异常缩放逻辑:
var xyzoom = d3.xyzoom(); xyzoom.scaleRatio([1, 1]); // 固定x、y缩放比例为1,后续通过代码强制仅x轴缩放
验证效果
修改后,iPad端的触摸操作将仅触发x轴的平移与缩放,不会再出现y方向的偏移,同时可以精准针对特定区块进行缩放操作。
内容的提问来源于stack exchange,提问作者NoveltyPachyderm
相关产品推荐
相关产品推荐

