准确计算鼠标速度

4
我写了一个小脚本,旨在输出鼠标移动的速度。我遇到的问题是,偶尔会有不准确的数字输出,从而影响整个结果。此外,当用户释放鼠标按钮时,脚本并不总是终止。为解决第一个问题,我认为可以将值放入数组中并确定异常值,但我希望这里的某个人告诉我我做了什么愚蠢的事情,并且有一种方法可以修复我的代码,使其更有效率。
JS:
var test_obj = {
    mouse_coors: function(x2) {

        $(document).on("mousemove", function(e) {
            var x = e.clientX,
            velocity = Math.abs(x-x2);

            console.log(velocity);
            $(document).off("mousemove");

            setTimeout(function() {
                x2 = e.clientX;
                test_obj.mouse_coors(x2);
            }, 100);
        });

        $(document).on("mouseup", function() {
            $(document).off("mouseup").off("mousemove");
        });
    },
};


$(document).ready(function() {

    $('#testbox').on("mousedown", function() {
        test_obj.mouse_coors(0);
    });

});

HTML:

JSfiddle:http://jsfiddle.net/mkb2t/

(注:此处为原文内容,无需翻译)
1个回答

14
仅仅因为这不是鼠标的速度。你目前计算的是鼠标在x方向上移动的距离,这被称作“距离”。
你所体验到的不准确可能是因为忽略了y方向和setTimeout的不准确性——使用日期时间戳。
此外,你正在构建一系列mousemove处理程序(不仅不正确,而且效率低下)。在每个事件(它们非常频繁!)上,你都要等待0.1秒,然后添加一个新的监听器,从那时起,在每个事件上输出鼠标自第一个事件以来移动了多少距离。另一个问题是当鼠标按下时,你用值0调用mouse_coors函数,但鼠标几乎不会在那里。
更好的方法是:全局存储鼠标的当前坐标。每次更新它们时,计算差异并将其除以自上次更新以来经过的时间。然后记录速度。
function makeVelocityCalculator(e_init, callback) {
    var x = e_init.clientX,
        y = e_init.clientY,
        t = Date.now();
    return function(e) {
        var new_x = e.clientX,
            new_y = e.clientY,
            new_t = Date.now();
        var x_dist = new_x - x,
            y_dist = new_y - y,
            interval = new_t - t;
        var velocity = Math.sqrt(x_dist*x_dist+y_dist*y_dist)/interval;
        callback(velocity);
        // update values:
        x = new_x;
        y = new_y;
        t = new_t;
    };
}
$(document).ready(function() {
    $('#testbox').on("mousedown", function(e) {
        var log = makeVelocityCalculator(e, function(v) {
            console.log(v+"pixel/ms");
        });
        $(document).on("mousemove", log).one("mouseup", function(){
            $(document).off("mousemove", log);
        });
    });
});

更新后的演示代码


我并不想获取y方向。也许速度这个词用错了,因为我只关心水平方向上随时间移动的距离。谢谢! - tom c
2
@tomc:好的,但你还忘了时间...我认为我的脚本很容易适应仅获取水平速度。 - Bergi
我以为超时时间会考虑自从创建坐标之间的暂停时间,但是你的方法似乎更准确! - tom c
2
setTimeout 不旨在精确。 - Justin L.
2
@tomc:但它没有暂停以获取新的坐标,而是在设置新的侦听器之前暂停。这可能适用于 .one("mousemove", …),但不像您的脚本。尽管如此,它仍然无法考虑设置侦听器和获取第一个事件之间的时间。[这里有类似的东西](http://jsfiddle.net/mkb2t/4/),可以进行比较。 - Bergi
2
JavaScript 引擎是单线程的。setTimeoutsetInterval 不会在您期望的确切时间触发,这会导致不准确的计算。请注意。 - Dragan Okanovic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接