Limiting domain when zooming or panning in D3.js

后端 未结 2 1584
半阙折子戏
半阙折子戏 2020-12-31 14:08

I have implemented a simple D3.js line chart that can be zoomed and panned. It is based on Stephen Bannasch\'s excellent example here.

The domain of my data is [0, n

相关标签:
2条回答
  • 2020-12-31 14:44

    Sadly, the solution posted by Bill did only half the trick: While it does indeed inhibit the panning, it causes the graph to distort if zoom is applied. It is then usually impossible to return to a properly proportioned and positioned graph.

    In the following version the proportions of the axes are maintained, even if scrolling to the borders.

    As soon as the scaling hits 100%, the scales' domains are reset to their original position. This guarantees a correct positioning, even if the intermediate steps return illegal parameters for the axes.

    While not perfect, I hope this script can help somebody until d3 (re)implements this feature.

    # 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)
    
    0 讨论(0)
  • 2020-12-31 15:04

    You just need to limit the domain on redraw. The following code will prevent the graph from being zoomed out past it's initial domains (as used in 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)]);
    
        ....
    
    0 讨论(0)
提交回复
热议问题