Javascript 试图获得一个div到";跟随;光标位于mousemove上,但有延迟

Javascript 试图获得一个div到";跟随;光标位于mousemove上,但有延迟,javascript,jquery,Javascript,Jquery,我想创建类似于旧鼠标轨迹的效果,其中div延迟但跟随光标 通过使用“设置间隔”(set interval)触发光标坐标的动画,我已经相当接近了 $("body").mousemove(function (e) { if (enableHandler) { handleMouseMove(e); enableHandler = false; } }); timer = window.setInterval(function(){ enabl

我想创建类似于旧鼠标轨迹的效果,其中div延迟但跟随光标

通过使用“设置间隔”(set interval)触发光标坐标的动画,我已经相当接近了

$("body").mousemove(function (e) {
    if (enableHandler) {
        handleMouseMove(e);
        enableHandler = false;
    }
});

timer = window.setInterval(function(){
    enableHandler = true;
}, 250);

function handleMouseMove(e) {

  var x = e.pageX,
      y = e.pageY;

      $("#cube").animate({
        left: x,
        top: y
      }, 200);

}

现在仍然存在两个问题:

  • “追逐”div非常跳跃(因为需要使用设置间隔)

  • 如果鼠标移动在触发动画之前停止,则div将留在原地,远离光标


  • 尝试使用
    .css()
    css
    转换删除
    setInterval

    $(文档).ready(函数(){
    var cube=$(“#cube”);
    $(“body”).mousemove(函数(e){
    手推车(e);
    });
    功能handleMouseMove(事件){
    var x=event.pageX,
    y=event.pageY;
    cube.css({
    左:x+cube.width()/2+“px”,
    顶部:y+cube.height()/2+“px”
    }).parents(“body”).mousemove()
    }
    });
    
    正文{
    溢出:隐藏;
    位置:绝对位置;
    身高:100%;
    宽度:100%;
    背景:#efef;
    }
    #立方体{
    高度:50px;
    宽度:50px;
    利润上限:-25px;
    左边距:-25px;
    背景:红色;
    位置:绝对位置;
    最高:50%;
    左:50%;
    过渡:所有1.5s的轻松进出;
    }

    删除SetInterval并添加$(“#立方体”).stop();停止基于旧(x,y)的旧动画,以便可以启动新的“更快”动画

    工作示例
    我的做法略有不同。我没有使用
    setInterval
    (甚至
    setTimeout
    ),而是让动画用x毫秒完成。动画越长,下面的div的响应性就越差

    我注意到的唯一问题是,如果鼠标移动过多,它就会备份

    $(document).ready(function () {
    
        $("body").mousemove(function (e) {
            handleMouseMove(e);
        });
    
        function handleMouseMove(event) {
    
            var x = event.pageX;
            var y = event.pageY;
    
            $("#cube").animate({
                left: x,
                top: y
            }, 1);
        }
    });
    

    这里有一个解决方案,它可能会更像鼠标轨迹,因为它只会记住最后100个位置,并丢弃设置鼠标轨迹长度的旧位置


    旧的鼠标轨迹功能使用了几个窗口的列表,这些窗口的形状类似于光标,每一帧都会更新它们的位置。基本上,它有一个“游标”列表,列表中“游标”旁边的每一帧都被移动到当前游标位置,实现了让每个假游标更新自己位置的效果,延迟
    假游标-1帧

    可以使用
    requestAnimationFrame
    performance.now
    Event.timeStamp
    模拟单个对象的平滑、按需延迟移动。其想法是将鼠标事件保存在内部列表中,并仅在创建后经过特定时间后使用它们

    function DelayLine(delay, action){
        capacity = Math.round(delay / 1000 * 200);
        this.ring = new Array(capacity);
        this.delay = delay;
        this.action = action;
        this._s = 0;
        this._e = 0;
        this._raf = null;
        this._af = this._animationFrame.bind(this);
        this._capacity = capacity;
    }
    DelayLine.prototype.put = function(value){
        this.ring[this._e++] = value;
        if (this._e >= this._capacity) this._e = 0;
        if (this._e == this._s) this._get();
        cancelAnimationFrame(this._raf);
        this._raf = requestAnimationFrame(this._af);
    }
    DelayLine.prototype._get = function(){
        var value = this.ring[this._s++];
        if (this._s == this._capacity) this._s = 0;
        return value;
    }
    DelayLine.prototype._peek = function(){
        return this.ring[this._s];
    }
    DelayLine.prototype._animationFrame = function(){
        if (this._length > 0){
            if (performance.now() - this._peek().timeStamp > this.delay)
                this.action(this._get());
            this._raf = requestAnimationFrame(this._af);
        }
    }
    Object.defineProperty(DelayLine.prototype, "_length", {
        get: function() { 
            var size = this._e - this._s;
            return size >= 0 ? size : size + this._capacity;
        }
    });
    
    var delayLine = new DelayLine(100, function(e){
        pointer.style.left = e.x - pointer.offsetWidth/2 + "px";
        pointer.style.top = e.y - pointer.offsetHeight/2 + "px";
    });
    
    document.addEventListener("mousemove", function(e){
        delayLine.put(e);
    }, false);
    

    游戏在这里进行得太晚了,但我不太喜欢在这里添加延迟的任何选项,因为它们跟随鼠标之前的位置,而不是朝鼠标移动。因此,我对Mike Willis的代码进行了大量修改,以获得此结果-

    $(document).ready(function () {
    
    $("body").mousemove(function (e) {
      mouseMoveHandler(e);
    });
    var currentMousePos = { x: -1, y: -1 };
    function mouseMoveHandler(event) {
      currentMousePos.x = event.pageX;
      currentMousePos.y = event.pageY;
    }
    
    mouseMover = setInterval(positionUpdate, 15);
    
    function positionUpdate() {
    
      var x_cursor = currentMousePos.x;
      var y_cursor = currentMousePos.y;
      var position = $("#cube").offset();
      var x_box = position.left;
      var y_box = position.top;
    
      $("#cube").animate({
        left: x_box+0.1*(x_cursor-x_box),
        top: y_box+0.1*(y_cursor-y_box) 
      }, 1, "linear"); 
    }
    });
    -----------------------------------------------------------------------
    body { overflow:hidden; position:absolute; height:100%; width:100%; background:#efefef; }
    
    #cube {
      height:18px;
      width:18px;
      margin-top:-9px;
      margin-left:-9px;
      background:red;
      position:absolute;
      top:50%;
      left:50%;   
    }
    .circleBase {
        border-radius: 50%;
    }
    .roundCursor {
        width: 20px;
        height: 20px;
        background: red;
        border: 0px solid #000;
    }
    

    它会在每次移动时保存光标位置,并以固定的时间间隔更新div位置,更新距离为其与最新光标位置之差的一小部分。我还把它改成了一个圆圈,因为这个圆圈看起来更好


    这里的一个问题是,它经常触发,可能会减慢一台较弱的机器,降低更新频率会使光标跳得比我想象的要多,但可能在更新频率和跳跃性之间存在某种中间地带,或者使用我不熟悉的动画方法来自动移动。

    如果我不清楚的话,很抱歉-关键是div要“追赶”光标-有一个延迟,所以当鼠标移动时,div将缓慢(且平稳)跟随它,在鼠标停止后逐渐追赶。@chris.carruthers请参阅更新的帖子。“chase”可以在
    过渡设置和
    左侧设置以及
    顶部设置中进行调整,在
    .css()
    我不确定我是否遗漏了一些内容,但尝试了这两种方法,它似乎仍然完全卡在光标上。这很好,接近我所追求的,是一个很好的简单解决方案。我这里唯一的问题是,我想象div在接近光标时会减速,而不是跳过光标。此外,在一个完全理想的世界中,“追逐动画”将更加平滑。谢谢是的,我顺便去了easeOutExpo,它真的很有帮助。不客气。很高兴这有帮助。:)你可以改变动画的dalay来投入更多的精力。这真是太棒了,几乎就是我想要的效果。我想我一直在尝试类似的东西,但我担心动画会被频繁触发,这会有多大问题?可能会有很多问题,考虑到每次鼠标稍微移动一点都会触发动画,我不确定它会对性能产生多大影响。一种解决方案可能是找到一种只在鼠标移动的开始、几个中点和结束时触发的方法。这可能说起来容易做起来难。是的,我想最终可能会归结到这一点,说起来肯定容易做起来难。不幸的是,这里有一种方法,如果鼠标移动至少2个像素,你只会触发动画。不过,这仍然不是一个很好的解决方案-很好,它确实减轻了一些重量。我接受麦克风的回答,因为结果肯定是最接近我想要的效果,但这里还有其他可靠的想法,它们可能也更轻。从guest271314获得额外的灵感后,我通过使用CSS动画降低了更新率以获得类似的效果,但它远不如每次都更新那么平滑
    function DelayLine(delay, action){
        capacity = Math.round(delay / 1000 * 200);
        this.ring = new Array(capacity);
        this.delay = delay;
        this.action = action;
        this._s = 0;
        this._e = 0;
        this._raf = null;
        this._af = this._animationFrame.bind(this);
        this._capacity = capacity;
    }
    DelayLine.prototype.put = function(value){
        this.ring[this._e++] = value;
        if (this._e >= this._capacity) this._e = 0;
        if (this._e == this._s) this._get();
        cancelAnimationFrame(this._raf);
        this._raf = requestAnimationFrame(this._af);
    }
    DelayLine.prototype._get = function(){
        var value = this.ring[this._s++];
        if (this._s == this._capacity) this._s = 0;
        return value;
    }
    DelayLine.prototype._peek = function(){
        return this.ring[this._s];
    }
    DelayLine.prototype._animationFrame = function(){
        if (this._length > 0){
            if (performance.now() - this._peek().timeStamp > this.delay)
                this.action(this._get());
            this._raf = requestAnimationFrame(this._af);
        }
    }
    Object.defineProperty(DelayLine.prototype, "_length", {
        get: function() { 
            var size = this._e - this._s;
            return size >= 0 ? size : size + this._capacity;
        }
    });
    
    var delayLine = new DelayLine(100, function(e){
        pointer.style.left = e.x - pointer.offsetWidth/2 + "px";
        pointer.style.top = e.y - pointer.offsetHeight/2 + "px";
    });
    
    document.addEventListener("mousemove", function(e){
        delayLine.put(e);
    }, false);
    
    $(document).ready(function () {
    
    $("body").mousemove(function (e) {
      mouseMoveHandler(e);
    });
    var currentMousePos = { x: -1, y: -1 };
    function mouseMoveHandler(event) {
      currentMousePos.x = event.pageX;
      currentMousePos.y = event.pageY;
    }
    
    mouseMover = setInterval(positionUpdate, 15);
    
    function positionUpdate() {
    
      var x_cursor = currentMousePos.x;
      var y_cursor = currentMousePos.y;
      var position = $("#cube").offset();
      var x_box = position.left;
      var y_box = position.top;
    
      $("#cube").animate({
        left: x_box+0.1*(x_cursor-x_box),
        top: y_box+0.1*(y_cursor-y_box) 
      }, 1, "linear"); 
    }
    });
    -----------------------------------------------------------------------
    body { overflow:hidden; position:absolute; height:100%; width:100%; background:#efefef; }
    
    #cube {
      height:18px;
      width:18px;
      margin-top:-9px;
      margin-left:-9px;
      background:red;
      position:absolute;
      top:50%;
      left:50%;   
    }
    .circleBase {
        border-radius: 50%;
    }
    .roundCursor {
        width: 20px;
        height: 20px;
        background: red;
        border: 0px solid #000;
    }