Repousser les objets lorsque la souris est proche

J'ai un tas d'éléments de portée dans des positions aléatoires enfermées à l'intérieur d'un parent div appelé '.background'. Ceux-ci sont générés avec Javascript. Comme ça:

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

Je veux qu'ils s'éloignent (ou repoussent) à mesure que la souris s'approche, mais je n'ai aucune idée de comment faire ça! Comment puis-je accomplir cela dans jQuery?

J'imagine que vous devriez chercher des espaces proches, puis changer de position s'ils se trouvaient à l'intérieur d'un certain rayon entourant la souris, mais je ne sais vraiment pas par où commencer. Toute aide est appréciée!

Une approche simple serait d'envelopper chaque portée dans une autre, une plus grande portée. Faites-en plus grand de chaque côté par la distance minimale que vous voulez que la souris puisse aborder les travées intérieures. Liez une fonction ( evade ) qui déplace chaque enveloppe pour passer la mouseover sur les wrappers. Cette approche vous donne une bordure carrée, donc si les éléments graphiques dans les travées internes ne sont pas carrés, la distance entre la souris et la bordure de l'élément graphique ne sera pas constante, mais elle est facile à mettre en œuvre.

Alternativement, utilisez le pare-chocs pour un test de proximité approximatif. Au lieu de relier la fonction d' mouseover à la mouseover , liez une fonction ( beginEvade ) qui se lie à evade à mousemove. Aussi, lier une fonction à la mouseout qui se détache evade . Votre evade peut ensuite effectuer un test de proximité plus précis.

Tout d'abord, trouvez une bonne bibliothèque de géométrie qui fournit un type de vecteur. En l'absence d'un, voici un exemple de mise en œuvre:

 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 += vx; this.y += vy; 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 * vx + this.y * vy; }, length: function () { return Math.sqrt(this.dot(this)); }, normal: function () { return this.clone().diveq(this.length()); } }; 

Ensuite, un exemple de fonction d'évasion circulaire (qui est le plus simple à mettre en œuvre). Contour:

  1. Calculez le centre du pare-chocs (le coin du pare-chocs plus les dimensions extérieures divisées en deux)
  2. Calculer le vecteur de décalage de la souris (du curseur de la souris au centre de l'élément)
  3. Test de proximité: si la distance est> = la distance minimale autorisée, retournez tôt.
  4. Calculer delta: la distance au curseur de la souris est trop petite, donc nous avons besoin du vecteur d'où le pare-chocs est là où il devrait être (le delta). L'allongement du vecteur décalé est donc la distance minimale autorisée, là où le centre du pare-chocs devrait être, par rapport à la position de la souris. En soustrayant le vecteur décalé de celui qui donne le delta du bord de proximité à la souris, qui est également le delta.
  5. Calculer le nouveau poste:
    1. Ajoutez le delta à la position actuelle.
    2. Vérification des limites: conservez toutes les bordures du cercle dans le document.
  6. Déplace le pare-chocs

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

Ensuite, tout ce qui reste sont des fonctions pour lier / déconnecter l' evade et les appels pour configurer tout.

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

Vous pouvez l'afficher en jsFiddle

Vous sélectionnez tous les objets avec le cercle de classe avec jQuery, placez-le dans une variable, puis vérifiez mousemove (peut-être également fait avec jQuery) en les bouclant si l'un est dans un certain rayon de la souris.