d3.js d3.behaviour.zoom在仅使用一个手指时禁用触摸屏上的平移

vecaoik1  于 2022-11-12  发布在  其他
关注(0)|答案(2)|浏览(145)

我有一个强制布局d3图表,我使用d3.behaviour.zoom来启用缩放和平移。
这一切都工作得很好,但因为我的图表充满了iPad上的屏幕,它变得不可能进一步向下滚动页面,因为我的触摸只是平移图表。
我想在触控设备上保持缩放行为。
是否可以 * 仅 * 在d3.event.touches.length === 1时取消touchmove.zoom事件?
这只是禁用了所有触摸交互-所以滚动是好的,但我不能缩放图表了:

selection.call(zoom)
    .on('touchstart.zoom', null)
    .on('touchmove.zoom', null)
    .on('touchend.zoom', null);

我还尝试添加另一个touchmove侦听器,如下所示:

selection.call(zoom)
    .on('touchmove', function () {
        if (d3.event.touches.length === 1) {
            d3.event.stopPropagation();
            // i've also tried d3.event.preventDefault() but it doesn't do anything         
        }
    });

我不认为我可以在d3中访问默认的zoom touchmove侦听器,可以吗?我想知道如果用户只使用一次触摸,我是否可以删除touchstart上的侦听器,然后在touchend上重新绑定它。

iecba09b

iecba09b1#

一种不使用d3调度的方法是使用原始的touchstart事件侦听器而不是d3。通过event.touches.length,您可以获得在屏幕上检测到的触摸次数的计数。
通过添加侦听器并对d3.behaviour.zoom中的触摸计数为1时进行额外检查,它可以防止在一个手指位于图形上时进行平移,并默认为正常滚动页面。

let touchCount = 0;

// Only necessary to add listener when running on mobile/tablet
// (assuming you already have some detection set up)

if (isMobileSize) {
    document.querySelector('.your-svg').addEventListener('touchstart', (e) => {
        touchCount = e.touches.length;
    });
}

let selection = d3.select('.your-svg');
let zoom = d3.behavior.zoom().on('zoom', () => {

    // When 1 finger, do not zoom
    if (touchCount === 1) {
        d3.event.sourceEvent.stopPropagation();
        return;
    }

    // Otherwise run zoom/move
    // ... zoom logic goes here....
})

selection.call(zoom)
z0qdvdin

z0qdvdin2#

听起来您需要比使用内置事件更细粒度的事件控制。尝试创建一个处理标准事件并将其转换为自定义事件的对象(基于您选择的规则,例如,仅1次触摸)。然后,您可以在d3调度机制的帮助下侦听这些抛出的自定义事件。

Events = function() {

  // custom event set up using d3 dispatch
  var dispatch = d3.dispatch("drag", "drag2");

  //listen for standard event on containing DOM element
  var events = function (g) {
    //g is the container DOM element

    // register the standard events required
    g.on("touchmove", touchmove)

    return events;
  };

  //function that handles the touchmove standard event
  function touchmove(d,i) {

    //stop the default event going any further
    d3.event.stopPropagation();

    //depending on your conditions choose which custom event you trigger
    if(condition1)
    {
      dispatch.drag.call(d3.event.target, d, i);
    }
    else if(condition2)
    {
      dispatch.drag2.call(d3.event.target, d, i);
    }
  }

  //add events defined in d3 dispatch function to events object and return   
  return d3.rebind(events, dispatch, "on");
}

在程式码的其他地方建立events对象,并侦听其自订事件:

events = new Events();

//Set the containing element the events object should be registering event listeners to
d3.select(container).call(events);

events.on("drag", function (d, i, position) {
    //do something here
})

events.on("drag2", function (d, i, position) {
    //do something else here
})

相关问题