我正在使用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
但是我无法让那些按我想要的方式工作.
问题是没有传递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.我会继续努力.
感谢 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) 可以在函数内正常使用。