Quando um mouse está pairando uma imagem. Ele é detectado por esta instrução if:
if ((distance(circles[this.index].x, circles[this.index].y, mouse.x, mouse.y)) < circles[this.index].radius)
Também quero detectar quando um mouse está fora de uma imagem. Após essa instrução if anterior, não posso usar mais o motivo:
Quando gero várias imagens na tela e quando o mouse passa o mouse sobre 1 imagem. Ele passa o mouse sobre a imagem e o código a detecta, mas também não passa sobre todas as outras imagens. Essa é a razão que é exibida 4 vezes "fora do círculo" e 1 vez "dentro do círculo"
Como visto no log:
Saída do Console.log:
Mouse inside circle
Mouse outside circle 4
Mouse inside circle
Mouse outside circle 4
Estou procurando uma maneira de detectar quando o mouse está deixando um círculo.
Você pode encontrar o código com o qual estou trabalhando abaixo:
PS: é importante detectar em que círculo (índice) o mouse está e sai. Quero criar uma enorme quantidade de fotos, mas no código abaixo usei 5 para fins de demonstração.
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>
fonte
Ambiguidades
Não está claro o que você precisa em relação a círculos e algum ponto (neste ponto de resposta é um substituto para o mouse e requer apenas que ele tenha as propriedades
x
ey
seja válido).A falta de informações na sua pergunta diz respeito aos fatos
que muitos círculos podem estar sob o ponto ao mesmo tempo.
e que mais de um círculo pode passar de baixo para fora ou de fora para baixo no ponto por quadro.
o teor da pergunta sugere que você está atrás de apenas um círculo que entra em conflito com as duas preocupações acima.
Premissas
Assumirei que a interação com os círculos é mais do que uma simples sub-evento como a interação. Que eles podem incluir comportamentos relacionados à animação que são acionados pelo estado relacionado ao ponto.
Suponho que a ordem visual dos círculos determinará como você seleciona os círculos de interesse.
Todos os círculos por quadro que atendem às condições necessárias e podem ser acessados rapidamente.
Esse desempenho é importante, pois você deseja ter muitos círculos que interagem com um ponto.
Que existe apenas um ponto (mouse, toque, outra fonte) por quadro que interage com os círculos
Não há requisito para interação com círculo
Solução
O exemplo abaixo cobre as suposições acima e resolve quaisquer ambiguidades na pergunta. Ele foi projetado para ser eficiente e flexível.
Os círculos são armazenados em uma matriz que teve suas propriedades estendidas chamadas
circles
Conjuntos de renderização e estado
A função
circles.updateDraw(point)
atualiza e desenha todos os círculos. O argumentopoint
é um ponto no qual comparar o círculo. O padrão é omouse
.Todos os círculos são desenhados com um contorno. Os círculos abaixo do ponto (por exemplo, mouse) são preenchidos em verde; os círculos apenas movidos para abaixo do ponto (por exemplo, onMouseOver) são preenchidos em amarelo; os círculos que acabam de sair de baixo são preenchidos com vermelho.
Existem três matrizes como propriedades de círculos que contêm círculos como definem ...
circles.under
Todos os círculos abaixo do pontocircles.outFromUnder
Todos os círculos apenas abaixo do pontocircles.newUnder
Todos os círculos novos abaixo do pontoEssa matriz é preenchida pela função
circles.updateDraw(point)
Consultar todos os círculos apontam estado
Os círculos também têm três funções que se referem às matrizes acima como
set
o conjunto padrãocircles.under
.As funções são ..
circles.firstInSet(set)
Retorna o primeiro círculo (a parte inferior visual mais) emset
ouundefined
circles.lastInSet(set)
Retorna o último círculo (a parte superior visual) emset
ouundefined
circles.closestInSet(set)
Retorna o círculo mais próximo ao ponto emset
ouundefined
Por exemplo, para obter o círculo visual mais alto logo abaixo do mouse que você chamaria
circles.lastInSet(circles.newUnder)
ou para obter o círculo mais próximo do mouse de todos os círculos sob o mouse que você chamariacircles.closestInSet(circles.newUnder)
(ou como o padrão é definir aunder
chamadacircles.closestInSet()
)Circunde estados adicionais
Cada círculo tem algumas propriedades adicionais.
Circle.distSqr
é o quadrado da distância do pontoCircle.rSqr
é o quadrado do raio calculado quando construído.Circle.underCount
Este valor pode ser usado para aplicar animações ao círculo com base em seu estado relativo ao ponto.Executando demonstração
Use o mouse para mover sobre círculos. O círculo mais próximo e abaixo do mouse é preenchido com branco com alfa = 0,5
fonte
Bem, o mouse está se movendo e você pode simplesmente criar um conjunto que conterá objetos de círculo que armazenarão o (s) círculo (s) em que você está:
e depois no loop:
e o
update
:fonte
Eu proporia o seguinte:
Mantenha uma pilha de figuras com a ordem de como elas foram criadas (ou qualquer outra ordem significativa). Isso é necessário para detectar movimentos sobre figuras sobrepostas.
Implemente uma função / método que itera a pilha e determina se o cursor está dentro de qualquer uma das figuras.
Lembre-se do último estado, na transição de estado dentro -> ouside desencadeia um evento.
Agora use-o:
fonte