Cuando un mouse se mueve sobre una imagen. Se detecta por esta declaración if:
if ((distance(circles[this.index].x, circles[this.index].y, mouse.x, mouse.y)) < circles[this.index].radius)
También quiero detectar cuando un mouse está fuera de una imagen. Después de esa declaración if anterior que no puedo usar, la razón es porque:
Cuando genero varias imágenes en la pantalla y cuando mi mouse se mueve sobre 1 imagen. Se desplaza sobre esa imagen y el código la detecta, pero tampoco sobre todas las demás imágenes. Esa es la razón por la que se muestra 4 veces "círculo exterior" y 1 vez "círculo interior"
Como se ve en el registro:
Salida de Console.log:
Mouse inside circle
Mouse outside circle 4
Mouse inside circle
Mouse outside circle 4
Estoy buscando una forma de detectar cuándo el mouse está saliendo de un círculo.
Puede encontrar el código con el que estoy trabajando a continuación:
PD: es importante que detecte en qué círculo (índice) está el mouse y se va. Quiero crear una gran cantidad de imágenes, pero en el código a continuación utilicé 5 para los propósitos de demostración.
var mouse = {
x: innerWidth / 2,
y: innerHeight / 2
};
// Mouse Event Listeners
addEventListener('mousemove', event => {
mouse.x = event.clientX;
mouse.y = event.clientY;
});
//Calculate distance between 2 objects
function distance(x1, y1, x2, y2) {
let xDistance = x2 - x1;
let yDistance = y2 - y1;
return Math.sqrt(Math.pow(xDistance, 2) + Math.pow(yDistance, 2));
}
// Sqaure to circle
function makeCircleImage(radius, src, callback) {
var canvas = document.createElement('canvas');
canvas.width = canvas.height = radius * 2;
var ctx = canvas.getContext("2d");
var img = new Image();
img.src = src;
img.onload = function() {
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
// we use compositing, offers better antialiasing than clip()
ctx.globalCompositeOperation = 'destination-in';
ctx.arc(radius, radius, radius, 0, Math.PI*2);
ctx.fill();
callback(canvas);
};
}
function Circle( x, y, radius, index ) {
//Give var for circle
this.x = x;
this.y = y;
this.dx = 1;
this.dy = 1;
this.radius = radius;
this.index = index;
}
// use prototyping if you wish to make it a class
Circle.prototype = {
//Draw circle on canvas
draw: function () {
var
x = (this.x - this.radius),
y = (this.y - this.radius);
// draw is a single call
c.drawImage( this.image, x, y );
},
//Updates position of images
update: function () {
var
max_right = canvas.width + this.radius,
max_left = this.radius * -1;
this.x += this.dx;
if( this.x > max_right ) {
this.x += max_right - this.x;
this.dx *= -1;
}
if( this.x < max_left ) {
this.x += max_left - this.x;
this.dx *= -1;
}
if ((distance(circles[this.index].x, circles[this.index].y, mouse.x, mouse.y)) < circles[this.index].radius) {
// Mouse inside circle
console.log("Mouse inside circle")
} else{
//The mouse is in one circle
//And out of 4 other circles
console.log("Mouse outside circle")
}
},
init: function(callback) {
var url = "https://t4.ftcdn.net/jpg/02/26/96/25/240_F_226962583_DzHr45pyYPdmwnjDoqz6IG7Js9AT05J4.jpg";
makeCircleImage( this.radius, url, function(img) {
this.image = img;
callback();
}.bind(this));
}
};
//Animate canvas
function animate() {
c.clearRect(0, 0, window.innerWidth, window.innerHeight);
circles.forEach(function( circle ) {
circle.update();
});
circles.forEach(function( circle ) {
circle.draw();
});
requestAnimationFrame(animate);
}
//Init canvas
var canvas = document.querySelector('canvas');
var c = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
//init circle objects
var circles = [
new Circle(10, 100, 50,0),
new Circle(10, 200, 30,1),
new Circle(10, 300, 50,2),
new Circle(10, 400, 50,3),
new Circle(10, 500, 50,4)
];
var ready = 0;
circles.forEach(function(circle) {
circle.init(oncircledone);
});
function oncircledone() {
if(++ready === circles.length) {
animate()
}
}
<canvas></canvas>
fuente
Ambigüedades
No está claro lo que necesita con respecto a los círculos y algún punto (en este punto de respuesta es un sustituto del mouse y solo requiere que tenga las propiedades
x
yy
sea válido).La falta de información en su pregunta se refiere a los hechos.
que muchos círculos pueden estar debajo del punto al mismo tiempo.
y que más de un círculo puede moverse de abajo hacia afuera o hacia afuera debajo del punto por cuadro.
La redacción de la pregunta sugiere que está detrás de un solo círculo que está en conflicto con las dos preocupaciones anteriores.
Supuestos
Asumiré que la interacción con los círculos es más que un simple evento bajo como interacción. Que pueden incluir comportamientos relacionados con la animación que se desencadenan por el estado relacionado con el punto.
Supongo que el orden visual de los círculos determinará cómo seleccionar círculos de interés.
Que todos los círculos por cuadro cumplan las condiciones requeridas y se pueda acceder rápidamente.
Esa actuación es importante ya que deseas tener muchos círculos que interactúen con un punto.
Que solo hay un punto (mouse, touch, otra fuente) por cuadro que interactúa con los círculos
No hay requisitos para la interacción círculo-círculo.
Solución
El siguiente ejemplo cubre los supuestos anteriores y resuelve cualquier ambigüedad en la pregunta. Está diseñado para ser eficiente y flexible.
Los círculos se almacenan en una matriz que tiene sus propiedades extendidas llamadas
circles
Renderizado y conjuntos de estados
La función
circles.updateDraw(point)
actualiza y dibuja todos los círculos. El argumentopoint
es un punto para verificar el círculo. Por defecto es elmouse
.Todos los círculos se dibujan con un contorno. Los círculos debajo del punto (p. Ej., El mouse) se llenan de verde, los círculos que acaban de moverse debajo del punto (p. Ej., OnMouseOver) se llenan de amarillo, los círculos que acaban de salir de debajo se llenan de rojo.
Hay 3 matrices como propiedades de círculos que contienen círculos como se define ...
circles.under
Todos los círculos debajo del puntocircles.outFromUnder
Todos los círculos salen por debajo del puntocircles.newUnder
Todos los círculos nuevos debajo del puntoEstas matrices están pobladas por la función
circles.updateDraw(point)
Consulta todos los círculos del estado del punto
Los círculos también tienen 3 funciones que se refieren a las matrices anteriores como
set
el conjunto predeterminadocircles.under
.Las funciones son ..
circles.firstInSet(set)
Devuelve el primer círculo (La parte inferior visual más) enset
oundefined
circles.lastInSet(set)
Devuelve el último círculo (La parte superior visual más) enset
oundefined
circles.closestInSet(set)
Devuelve el círculo más cercano al punto enset
oundefined
Por ejemplo, para obtener el círculo visual superior de la parte superior justo debajo del mouse al que llamaría
circles.lastInSet(circles.newUnder)
o para obtener el círculo más cercano al mouse de todos los círculos debajo del mouse al que llamaríacircles.closestInSet(circles.newUnder)
(o como el valor predeterminado es establecer launder
llamadacircles.closestInSet()
)Circula estados adicionales
Cada círculo tiene algunas propiedades adicionales.
Circle.distSqr
es el cuadrado de la distancia desde el puntoCircle.rSqr
es el cuadrado del radio calculado cuando se construye.Circle.underCount
Este valor se puede usar para aplicar animaciones al círculo en función de su estado relativo al punto.Ejecución de demostración
Usa el mouse para moverte sobre los círculos. El círculo más cercano y debajo del mouse está lleno de blanco con alfa = 0.5
fuente
Bueno, el mouse se está moviendo y simplemente puede crear un Conjunto que contendrá objetos circulares que almacenarán los círculos en los que se encuentra:
y luego en el bucle:
y el
update
:fuente
Yo propondría lo siguiente:
Mantenga una pila de figuras con el orden de cómo se crearon (o cualquier otro orden significativo). Esto es necesario para detectar movimientos sobre figuras superpuestas.
Implemente una función / método que itere la pila y determine si el cursor está dentro de alguna de las figuras.
Recuerde el último estado, en la transición de estado dentro-> ouside desencadena un evento.
Ahora úsalo:
fuente