D3: Is it possible to zoom+pan one axis and only pan the other?

前端 未结 3 1751
北海茫月
北海茫月 2020-12-28 16:34

I have zoom and pan working for the x axis but I\'d like to add panning for the y axis. I tried using d3.behavior.zoom and d3.event.translate[1] to

相关标签:
3条回答
  • 2020-12-28 17:15

    You can use

    zoom.center
    to get the code a bit cleaner, like this:

    var lastY = 0;
    var x = d3.scale.linear()
      .domain([0, 800])
      .range([0, 800]);
    
    var y = d3.scale.linear()
      .domain([0, 800])
      .range([0, 800]);
    
    var rectangleSelector = d3.select('svg')
      .append('g')
      .selectAll('rect')
      .data([[0, 0], [50, 50], [100, 100]])
      .enter()
      .append('rect')
      .attr('fill', 'black')
      .attr('x', d => x(d[0]))
      .attr('y', d => y(d[1]))
      .attr('width', d => x(d[0] + 40) - x(d[0]))
      .attr('height', d => y(40));
      
     var zoom = d3.behavior.zoom().center([400, 400]).x(x);
     zoom.on('zoom', () => {
         var translateY = d3.event.translate[1];
         zoom.center([400, translateY]);
         rectangleSelector.attr('x', d => x(d[0]))
                          .attr('y', d => y(d[1] + translateY))
                          .attr('width', d => x(d[0] + 40) - x(d[0]))
                          .attr('height', d => y(40));
    });
    
    d3.select('svg').call(zoom);
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
    <svg width="800" height="800"></svg>

    0 讨论(0)
  • 2020-12-28 17:20

    JSFIDDLE: https://jsfiddle.net/sladav/o8vaecyn/

    For starters, the zoom behavior handles both pan and zoom for the x axis, and that's handled by...

    var zoom = d3.behavior.zoom()
        .x(x)
        .scaleExtent([1, 10])
        .on("zoom", zoomed);
    

    So we'll use zoom to handle the x axis stuff.

    FOR THE Y AXIS, to get JUST the pan behavior...

    Create a separate drag behavior that captures the "dy", shifts the y domain, and reapplies it.

    1. Add in a drag behavior

      var drag = d3.behavior.drag()
           .on("drag", dragging)
      
    2. Let the y scale's domain be variable (we'll modify that as we drag)

      var yPan = 0;
      var yMin = (-height / 2);
      var yMax = (height / 2);
      
      var y = d3.scale.linear()
          .domain([yMin, yMax])
          .range([height, 0]);
      
    3. Add a function to rescale the Y axis on the drag event

      function dragging(d) {
         yPan = d3.event.dy;
         yMin += yPan;
         yMax += yPan;
         y.domain([yMin, yMax])
         d3.select(".y.axis").call(yAxis)};
      
    4. Call the drag function from your SVG element

      var svg = d3.select("body").append("svg")
          .attr("width", width + margin.left + margin.right)
          .attr("height", height + margin.top + margin.bottom)
          .append("g")
             .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
             .call(zoom)
             .call(drag);
      
    0 讨论(0)
  • 2020-12-28 17:25

    I've figured out one way to do this but it feels like a gigantic hack:

    var lastY = 0;
    
    var zoom = d3.behavior.zoom().x(x);
    
    zoom.on('zoom', () => {
      var translateY;
    
      if (d3.event.sourceEvent.type === 'mousemove') {
        // if it's a drag event then use the value from the drag
        translateY = d3.event.translate[1];
        lastY = translateY;
      } else {
        // if it's a wheel event then set the y translation to the last value
        translateY = lastY;
        zoom.translate([d3.event.translate[0], translateY]);
      }
    
      // translateY can now be used here as an offset to any drawing like so:
      rectangleSelector.attr('y', y(d[1] + translateY));
    });
    
    0 讨论(0)
提交回复
热议问题