9

我已经实现了一个可以缩放和平移的简单 D3.js 折线图。它基于 Stephen Bannasch 的出色示例

我的数据域是 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 。为交叉张贴道歉。

4

2 回答 2

6

可悲的是,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)
于 2012-08-16T23:31:57.087 回答
0

您只需要在重绘时限制域。以下代码将防止图形被缩小超过其初始域(如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)]);

    ....
于 2012-05-04T21:14:20.110 回答