D3: remap mousewheel to be panning gesture instead of zoom gesture

后端 未结 2 1274
不思量自难忘°
不思量自难忘° 2021-01-07 04:06

By default, when you create a new zoom behavior in D3, it maps the mousewheel to control zoom level. You can also click and drag to pan the chart if it\'s larger than the c

相关标签:
2条回答
  • 2021-01-07 04:11

    Ok, here we go: Based on Lars' comment, we can specify event handler for mousewheel event. As shown in the answer, we start by mapping wheel.zoom event to a custom handler pan

    selection.call(zoomer)
          .on("wheel.zoom",pan) // handler function for mousewheel zoom
    

    Second, we need to define the pan gesture, which is basically a translate in x and/or y direction.

    function pan() {
      svg.attr("transform", "translate(" + [dx,dy] + ")");
    }
    

    We also need to quantify the movement in both directions, and relate it to mousewheel movement. By inspecting the details of MouseWheel event, we find two useful attributes deltaX and deltaY, indicating how much the mousewheel moved in each direction.

    The final pan function is as follows

    function pan() {
        current_translate = d3.transform(svg.attr("transform")).translate;
        dx = d3.event.wheelDeltaX + current_translate[0];
        dy = d3.event.wheelDeltaY + current_translate[1];
        
      svg.attr("transform", "translate(" + [dx,dy] + ")");
      d3.event.stopPropagation();
    }
    

    Here is a working fiddle and bl.ock also modifying Mike's geometric zoom example.

    Cross-browser support:

    It seems that mousewheel events differs between browsers. For Safari and Firefox support, you need to add the following:

    selection.call(zoomer)
      .on("wheel.zoom",pan) 
      .on("mousewheel.zoom", pan)
      .on("DOMMouseScroll.zoom", pan)
    

    Also, the interpretation of wheelDelta is reversed in Firefox. wheelDelta can be fixed by this function

    function crossWheelDelta()
      // cross-browser wheel delta
      var e = window.event || e; // old IE support
      return Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail)));
    }
    
    0 讨论(0)
  • 2021-01-07 04:31

    You can also intercept wheel events in the function you create with d3.behavior.zoom(). "Zoom" events are triggered on both wheel scroll and mouse drag by default, so one potential strategy is to just wait for zoom events and intercept the wheel events within the zoom function.

    For example, here's an approach to doing Y translations with both wheel scroll and mouse drag:

    var panYOnScrollAndDrag = d3.behavior.zoom()
       .scaleExtent([1, 1]) // prevents wheel events (or anything) from changing the scale
       .on("zoom", function() {
          if (d3.event.sourceEvent.type === "wheel") {
             // use the `d3.event.sourceEvent.deltaY` value to translate
             // e.g., yTranslation += yTranslationDelta;
          } else if (d3.event.sourceEvent.type === "mousemove") {
             // use the normal d3.event.translate array to translate
             // e.g., yTranslation = d3.event.translate[1];
          }
          container.attr("transform", "translate(0," + yTranslation + ")");
       });
    

    Then you can throw this function at the relevant d3 container like so, selection.call(panYOnScrollAndDrag), and all the logic is contained in that one function.

    0 讨论(0)
提交回复
热议问题