9

ズームおよびパンできる単純なD3.js折れ線グラフを実装しました。これは、StephenBannaschの優れた例に基づいています

私のデータの定義域は、x次元で[0、n]です。

組み込みのズーム動作を使用して(つまり、マウスホイールイベントを使用して)、ズームとパンをこのドメインに制限するにはどうすればよいですか?

ユーザーが下端の0または上端のnを超えてパンするのを防ぎたい。たとえば、x軸に負の値が表示されないようにし、ズームを同じウィンドウに制限したい。

Jason Daviesがextent([...]、[...]、[...])を使用して機能することに基づいて見つけた例は、バージョン2.9.1では機能しなくなったようです。残念ながら、ズーム動作は現在、他の点では優れたAPIドキュメントに記載されていない数少ない機能の1つです。

どんなポインタでも大歓迎です。

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 に答える