如何在存在顶部边距时确保D3.js的Y轴缩放以光标为中心
如何在存在顶部边距时确保D3.js的Y轴缩放以光标为中心
我完全懂你遇到的这个困扰——加了顶部边距后,Y轴缩放时光标和对应的数据点就“分家”了,这本质是因为你的zoom行为绑定在了整个SVG上,但实际的绘图区域(那个被margin偏移后的g元素)有自己的坐标系,两者没对齐导致的。
给你两个简单的解决思路,推荐第一个,最直接高效:
方法1:把Zoom行为绑定到偏移后的g元素上
既然你的坐标轴和未来的绘图内容都在这个被translate(${margin.left},${margin.top})移动后的g元素里,那直接把zoom行为绑定到它上面就好了,这样zoom的坐标系就和你实际的绘图区域完全匹配:
- 首先修改zoom的绑定对象:
// 把原来的 svg.call(zoom); 改成: g.call(zoom);
- 然后调整重置缩放的函数,让它作用在g元素上:
function resetZoom() { // 把 svg.transition() 改成 g.transition() g.transition().duration(750).call(zoom.transform, d3.zoomIdentity); }
- 最后把右键重置的事件也绑定到g元素上:
// 把 svg.on("contextmenu", ...) 改成: g.on("contextmenu", (event) => { event.preventDefault(); resetZoom(); });
这样修改后,zoom的计算就完全基于你的实际绘图区域坐标系,顶部边距的偏移就不会再干扰缩放中心了,光标指在哪里,缩放后那个点就还在光标位置。
方法2:调整Zoom的坐标范围(适合不想改变绑定对象的情况)
如果你还是想把zoom绑定在SVG上,那需要手动告诉D3,zoom的有效范围是g元素在SVG中的实际位置,也就是把extent和translateExtent设置为包含margin的范围:
修改你的zoom初始化代码:
const zoom = d3.zoom() .scaleExtent([0.5, 5]) // 把原来的translateExtent改成对应g元素的位置 .translateExtent([[margin.left, margin.top], [margin.left + width, margin.top + height]]) // 同样修改extent .extent([[margin.left, margin.top], [margin.left + width, margin.top + height]]) .on("zoom", zoomed);
这样D3在计算zoom中心时,就会自动考虑顶部边距的偏移,光标和数据点就能对齐了。
你可以直接把第一种方法的修改用到你的代码里,测试一下,应该就能解决问题了~
备注:内容来源于stack exchange,提问作者Rory McDonald
相关产品推荐
相关产品推荐

