Bounce objects when the mouse is near

I have a group of span elements at random positions, enclosed inside a parent div called ".background". They are created using Javascript. Like this:

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

      

I want them to move away (or push off) when the mouse gets closer, but I have no idea how to do that! How can I do this in jQuery?

I suppose you will have to look for gaps that were nearby and then reposition if they are within a certain radius around the mouse, but I really don't know where to start. Any help is appreciated!

+3


source to share


2 answers


A simple approach would be to wrap each span in a different, larger range. Make it larger on each side by the minimum distance you want the mouse to be able to get closer to the inner gaps. Bind a function ( evade

) that moves each wrapper on mouseover

to the wrappers. This approach gives a square border, so if the graphics in the inner spans are not square, the distance from the mouse to the border of the graphics will not be constant, but it is easy to implement.

Alternatively, use a bumper for a rough proximity check. Instead of binding the evade function to, bind mouseover

the ( beginEvade

) function that binds evade

to mousemove. Also, bind a function to mouseout

that unbinds evade

. Yours evade

can then perform a more accurate proximity test.

First, find a good geometry library that provides vector type. In the absence of one, here's an example implementation:

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());
    }
};

      

Next, a sample of the circular evasion function (which is the easiest to implement). Structure:

  • calculate bumper center (bumper angle and outer dimensions are halved)
  • calculate the mouse displacement vector (from the mouse cursor to the center of the element)
  • Proximity test: If distance> = minimum distance allowed, then return earlier.
  • calculate delta: the distance to the mouse cursor is too short, so we need a vector from which the bumper should be where it should be (delta). Extends the displacement vector so that the minimum distance allowed is where the center of the bumper is located relative to the mouse position. Subtracting the offset vector from it gives the delta from the edge of the proximity to the mouse, which is also the delta.
  • calculate new position:
    • add a delta to the current position.
    • border check: preserve all circle borders in the document.
  • move bumper


In code:

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);
}

      

After that, all the rest are bind / unbind functions evade

, and the calls to set all.

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);
});

      

You can view this at jsFiddle

+12


source


you select all class circle objects with jQuery, put that in a variable, and then check for mousemove (can also be done with jQuery), iterating over them if it's within a certain radius of the mouse.



+1


source







All Articles