如何使用D3.js限制鼠标事件的函数调用

Gui*_*ded 4 javascript d3.js

我正在使用D3.js调用DOM元素的"mousemove"事件上的函数.on(),如下所示:

d3.select("#myelement").on("mousemove", myfunc);
function myfunc(){
    // Just to show that I need to get the mouse coordinates here
    console.log(d3.mouse(this));
}
Run Code Online (Sandbox Code Playgroud)

我需要我正在调用的函数来了解事件,即鼠标坐标.

由于我的其余代码在计算上非常昂贵,我想节制调用myfunc,比如说每200毫秒.

我怎样才能保留thisin 的值myfunc(这样d3.mouse(this)仍然可以)?我试过这个去抖功能:https://davidwalsh.name/javascript-debounce-function 还有这个:https://remysharp.com/2010/07/21/throttling-function-calls 但是我无法让那些按我想要的方式工作.

Ger*_*ado 5

问题是没有传递this到debounce函数,这很容易,你可以在这个JSFiddle中看到(我正在链接一个JSFiddle,因为Stack片段在记录this或D3选择时会冻结).

真正的问题是传递D3事件:因为d3.event在事件结束后为null,所以你必须保持对它的引用.否则,您Cannot read property 'sourceEvent' of null在尝试使用时会出错d3.mouse().

因此,使用第二个链接的功能,我们可以修改它以保持对D3事件的引用:

function debounce(fn, delay) {
    var timer = null;
    return function() {
        var context = this,
            args = arguments,
            evt = d3.event;
            //we get the D3 event here
        clearTimeout(timer);
        timer = setTimeout(function() {
            d3.event = evt;
            //and use the reference here
            fn.apply(context, args);
        }, delay);
    };
}
Run Code Online (Sandbox Code Playgroud)

这是演示,将鼠标悬停在大圆圈上,慢慢移动鼠标:

var circle = d3.select("circle");

circle.on("mousemove", debounce(function() {
  console.log(d3.mouse(this));
}, 250));

function debounce(fn, delay) {
  var timer = null;
  return function() {
    var context = this,
      args = arguments,
      evt = d3.event;
    clearTimeout(timer);
    timer = setTimeout(function() {
    	d3.event = evt;
      fn.apply(context, args);
    }, delay);
  };
}
Run Code Online (Sandbox Code Playgroud)
.as-console-wrapper { max-height: 30% !important;}
Run Code Online (Sandbox Code Playgroud)
<script src="https://d3js.org/d3.v4.js"></script>
<svg>
  <circle cx="120" cy="80" r="50" fill="teal"></circle>
</svg>
Run Code Online (Sandbox Code Playgroud)

PS:在JSFiddle和Stack片段中,仅当您停止移动鼠标时才会调用该函数,这不是a的理想行为mousemove.我会继续努力.


Gui*_*ded 2

感谢 Gerardo Furtado 的回答,我通过调整此页面的节流函数来解决我的问题,如下所示:

function throttle(fn, threshhold, scope) {
  threshhold || (threshhold = 250);
  var last,
      deferTimer;
  return function () {
    var context = scope || this;

    var now = +new Date,
        args = arguments,
        event = d3.event;
    if (last && now < last + threshhold) {
      // hold on to it
      clearTimeout(deferTimer);
      deferTimer = setTimeout(function () {
        last = now;
          d3.event = event;
        fn.apply(context, args);
      }, threshhold);
    } else {
      last = now;
        d3.event = event;
      fn.apply(context, args);
    }
  };
}
});
Run Code Online (Sandbox Code Playgroud)

现在回调知道 d3.event 和 d3.mouse(this) 可以在函数内正常使用。