【问题标题】:Repel Objects when mouse is near鼠标靠近时排斥物体
【发布时间】:2012-04-08 07:50:36
【问题描述】:

我在名为“.background”的父 div 内有一堆随机位置的 span 元素。这些是用 Javascript 生成的。像这样:

<span class="circle" style="width: 54px; height: 54px; background: #5061cf; top: 206px; left: 306px"></span>

我希望它们在鼠标靠近时移开(或排斥),但我不知道该怎么做!我将如何在 jQuery 中实现这一点?

我想你必须搜索附近的跨度,然后如果它们在鼠标周围的某个半径内则改变它们的位置,但我真的不知道从哪里开始。任何帮助表示赞赏!

【问题讨论】:

    标签: javascript jquery


    【解决方案1】:

    一种简单的方法是将每个跨度包装在另一个更大的跨度中。通过您希望鼠标能够接近内部跨度的最小距离,使其在每一侧都变大。绑定一个函数 (evade),将每个包装器移动到包装器上的 mouseover。这种方法为您提供了一个方形边框,因此如果内部跨度中的图形元素不是方形的,则从鼠标到图形元素边框的距离不会是恒定的,但很容易实现。

    或者,使用保险杠进行粗略的接近测试。不要将 evade 函数绑定到 mouseover,而是绑定一个在 mousemove 上绑定 evade 的函数 (beginEvade)。此外,将一个函数绑定到 mouseout 以取消绑定 evade。然后您的evade 可以执行更精确的接近测试。

    首先,找到一个提供矢量类型的好几何库。如果没有,这里是一个示例实现:

    Math.Vector = function (x,y) {
        this.x = x;
        this.y = y;
    }
    Math.Vector.prototype = {
        clone: function () {
            return new Math.Vector(this.x, this.y);
        },
        negate: function () {
            this.x = -this.x;
            this.y = -this.y;
            return this;
        },
        neg: function () {
            return this.clone().negate();
        },
        addeq: function (v) {
            this.x += v.x;
            this.y += v.y;
            return this;
        },
        subeq: function (v) {
            return this.addeq(v.neg());
        },
        add: function (v) {
            return this.clone().addeq(v);
        },
        sub: function (v) {
            return this.clone().subeq(v);
        },
        multeq: function (c) {
            this.x *= c;
            this.y *= c;
            return this;
        },
        diveq: function (c) {
            this.x /= c;
            this.y /= c;
            return this;
        },
        mult: function (c) {
            return this.clone().multeq(c);
        },
        div: function (c) {
            return this.clone().diveq(c);
        },
    
        dot: function (v) {
            return this.x * v.x + this.y * v.y;
        },
        length: function () {
            return Math.sqrt(this.dot(this));
        },
        normal: function () {
            return this.clone().diveq(this.length());
        }
    };
    

    接下来,一个示例循环规避函数(实现起来最简单)。大纲:

    1. 计算保险杠的中心(保险杠的corner 加上outer dimensions 分成两半)
    2. 计算鼠标偏移矢量(从mouse cursor 到元素中心)
    3. 接近测试:如果距离 >= 允许的最小距离,则提前返回。
    4. calculate delta:到鼠标光标的距离太小,所以我们需要从保险杠所在的位置到它应该在的位置的向量(delta)。加长偏移矢量使其成为允许的最小距离,从而给出保险杠中心相对于鼠标位置的位置。从中减去偏移向量,得到从邻近边缘到鼠标的增量,这也恰好是增量。
    5. 计算新位置:
      1. 将增量添加到当前位置。
      2. 边界检查:将圆的所有边界保留在文档内。
    6. 移动保险杠

    在代码中:

    function evade(evt) {
        var $this = $(this),
            corner = $this.offset(),
            center = {x: corner.left + $this.outerWidth() / 2, y: corner.top + $this.outerHeight() / 2},
            dist = new Math.Vector(center.x - evt.pageX, center.y - evt.pageY),
            closest = $this.outerWidth() / 2;
    
        // proximity test
        if (dist.length() >= closest) {
            return;
        }
    
        // calculate new position
        var delta = dist.normal().multeq(closest).sub(dist),
            newCorner = {left: corner.left + delta.x, top: corner.top + delta.y};
    
        // bounds check
        var padding = parseInt($this.css('padding-left'));
        if (newCorner.left < -padding) {
            newCorner.left = -padding;
        } else if (newCorner.left + $this.outerWidth() - padding > $(document).width()) {
            newCorner.left = $(document).width() - $this.outerWidth() + padding;
        }
        if (newCorner.top < -padding) {
            newCorner.top = -padding;
        } else if (newCorner.top + $this.outerHeight() - padding > $(document).height()) {
            newCorner.top = $(document).height() - $this.outerHeight() + padding;
        }
    
        // move bumper
        $this.offset(newCorner);
    }
    

    之后,剩下的就是绑定/取消绑定evade 的函数,以及设置所有内容的调用。

    function beginEvade() {
        $(this).bind('mousemove', evade);
    }
    
    function endEvade() {
       $(this).unbind('mousemove', evade);
    }
    
    $(function () {
        // you can also wrap the elements when creating them.
        $('.circle').wrap('<span class="bumper" />')
    
        $('.bumper').bind('mouseover', beginEvade);
        $('.bumper').bind('mouseout', endEvade);
    });
    

    你可以在jsFiddle预览这个

    【讨论】:

    • 但不是perfect。 z 指数会导致不止一个逃避者出现问题。
    • 哈哈哈,JSfiddle 玩起来很有趣,我可以想象将它用于显示“点击我!”的链接然后就不能了。
    【解决方案2】:

    您使用 jQuery 选择所有具有类 circle 的对象,将其放入一个变量中,然后通过循环遍历它们来检查 mousemove(也可以使用 jQuery 完成),如果一个对象在鼠标的某个半径范围内。

    【讨论】:

    • 给每个跨度一个 id 并在执行此操作之前保存所有位置,这样您就不必每次都重新计算。
    猜你喜欢
    • 2011-02-02
    • 2018-04-10
    • 1970-01-01
    • 2015-05-05
    • 1970-01-01
    • 2012-11-06
    • 2013-11-06
    • 2019-04-04
    • 1970-01-01
    相关资源
    最近更新 更多