在 D3.js 中缩放或平移时限制域
Posted
技术标签:
【中文标题】在 D3.js 中缩放或平移时限制域【英文标题】:Limiting domain when zooming or panning in D3.js 【发布时间】:2012-05-12 10:59:32 【问题描述】:我已经实现了一个可以缩放和平移的简单 D3.js 折线图。它基于 Stephen Bannasch 的优秀示例here。
我的数据的域是 x 维度的 [0, n]。
如何使用内置缩放行为(即使用鼠标滚轮事件)将缩放和平移限制在此域?
我想防止用户在下端平移 0 或在上端平移 n,例如,他们应该永远无法在 x 轴上看到负值,并且希望将缩放限制在同一个窗口。
我发现的基于 Jason Davies 的示例使用 extent([...],[...],[...] ) 在 2.9.1 版本中似乎不再适用。不幸的是,缩放行为目前是其他出色的 API 文档中未记录的少数功能之一。
欢迎指点。
PS。 我在 D3.js 邮件列表上发布了同样的问题,但没有得到回复:https://groups.google.com/d/topic/d3-js/w6LrHLF2CYc/discussion。对交叉发布表示歉意。
【问题讨论】:
【参考方案1】:遗憾的是,Bill 发布的解决方案只成功了一半:虽然它确实抑制了平移,但如果应用缩放,它会导致图形扭曲。然后通常不可能返回到适当比例和定位的图表。
在以下版本中,即使滚动到边框,轴的比例也会保持不变。
一旦缩放达到 100%,缩放域就会重置为其原始位置。这保证了正确的定位,即使中间步骤返回了非法的轴参数。
虽然不完美,但我希望这个脚本可以帮助到 d3(重新)实现这个功能。
# x and y are the scales
# xAxis and yAxis are the axes
# graph is the graph you want attach the zoom to
x0 = x.copy()
y0 = y.copy()
successfulTranslate = [0, 0]
zoomer = d3.behavior.zoom()
.scaleExtent([1,2])
onZoom = ->
ev = d3.event # contains: .translate[x,y], .scale
if ev.scale == 1.0
x.domain x0.domain()
y.domain y0.domain()
successfulTranslate = [0, 0]
else
xTrans = x0.range().map( (xVal) -> (xVal-ev.translate[0]) / ev.scale ).map(x0.invert)
yTrans = y0.range().map( (yVal) -> (yVal-ev.translate[1]) / ev.scale ).map(y0.invert)
xTransOk = xTrans[0] >= x0.domain()[0] and xTrans[1] <= x0.domain()[1]
yTransOk = yTrans[0] >= y0.domain()[0] and yTrans[1] <= y0.domain()[1]
if xTransOk
x.domain xTrans
successfulTranslate[0] = ev.translate[0]
if yTransOk
y.domain yTrans
successfulTranslate[1] = ev.translate[1]
zoomer.translate successfulTranslate
graph.select('g.x.axis').call(xAxis)
graph.select('g.y.axis').call(yAxis)
drawBars()
zoomer.on('zoom', onZoom)
# ...
graph.call(zoomer)
【讨论】:
几乎完美。我遇到的问题是它在缩放操作期间没有效果。如果在右限附近放大,请将光标放在可视区域的左边缘,然后缩小:可视区域的右边缘将超出预期的限制。我认为对于一个完整的解决方案,您需要转向另一个方向,而不是简单地接受/拒绝对翻译的更改。从域限制计算翻译的合法范围,并限制翻译值。【参考方案2】:您只需要在重绘时限制域。以下代码将防止图形被缩小到其初始域之外(如http://bl.ocks.org/1182434 中使用的那样)。
SimpleGraph.prototype.redraw = function()
var self = this;
return function()
self.x.domain([Math.max(self.x.domain()[0], self.options.xmin), Math.min(self.x.domain()[1], self.options.xmax)]);
self.y.domain([Math.max(self.y.domain()[0], self.options.ymin), Math.min(self.y.domain()[1], self.options.ymax)]);
....
【讨论】:
我知道这篇文章已经过时了,但仅供参考:您引用的链接让我可以缩小并平移到我心中的内容。 (Chrome 29.0) 使用此示例平移时图形会缩放。以上是关于在 D3.js 中缩放或平移时限制域的主要内容,如果未能解决你的问题,请参考以下文章