Os elementos internos do Canvas não podem adicionar ouvintes de eventos interativos tão convenientemente quanto os elementos DOM, porque não há conceito de elementos no canvas, eles são apenas gráficos desenhados pelo canvas. Este é um obstáculo necessário para o desenvolvimento interativo. A ideia de monitorar o evento de clique de um gráfico é muito simples, basta ouvir o evento de clique do próprio elemento canvas e, em seguida, determinar em qual gráfico as coordenadas de clique estão localizadas. então o evento de clique gráfico pode ser realizado disfarçado. Este artigo apresentará três métodos para determinar se o ponto coordenado está localizado dentro de um gráfico de tela.
AcordoOs três métodos apresentados neste artigo são adequados para identificar eventos de clique gráfico com formas irregulares e posições irregulares na tela. Para cenas com formas regulares ou posições regulares, deve haver implementações mais simples, que não serão discutidas aqui.
método de pixelsA ideia do método de detecção de pixel é desenhar vários gráficos na tela (se houver vários) fora da tela separadamente e usar o método getImageData() para obter os dados de pixel e salvá-los. Quando o elemento canvas escuta um evento de clique, as coordenadas do clique podem ser usadas para calcular diretamente o pixel na tela onde o clique ocorreu e, em seguida, percorrer os dados gráficos salvos anteriormente para ver se o valor alfa desse pixel é 0. Se é 0, significa que o ponto de aterrissagem não está dentro do valor atual, caso contrário significa que o ponto atingiu este valor.
Método para obter o número de pixels clicados com base nas coordenadas do clique:
Número do pixel = (ordenada-1) * largura da tela + abscissa
Por exemplo, se você clicar nas coordenadas (3,3) em uma tela com largura 5, o número de pixels obtido de acordo com a fórmula acima é (3-1) * 5 + 3 = 18, conforme mostrado na figura:
Como os dados gráficos exportados pelo canvas armazenam cada pixel em um array de 4 números na ordem rgba, então se você quiser acessar o valor alfa de um pixel especificado, você só precisa ler o valor pIndex * 4 + 3 deste array. , se esse valor não for 0, significa que o pixel está visível, ou seja, o gráfico foi clicado.
Este método é aquele que considero ter as ideias mais diretas, os resultados mais precisos e não possui nenhum requisito quanto ao formato dos gráficos. No entanto, esse método tem uma limitação fatal quando os gráficos precisam ser movidos na tela. caches de dados devem ser criados com frequência para garantir a detecção. Afetado pelo tamanho da tela e pelo número de gráficos, o desempenho do método getImageData() se tornará um sério gargalo. Portanto, se o gráfico da tela for estático, este método é muito adequado, caso contrário não é adequado usar este método.
Método de ânguloO princípio do método de julgamento de ângulo é fácil de entender. Se um ponto estiver dentro de um polígono, o ângulo entre o ponto e todos os vértices do polígono deve somar exatamente 360°.
O processo de cálculo pode ser transformado nas três etapas a seguir:
1. Dados os vértices do polígono e as coordenadas conhecidas, combine as coordenadas e os vértices em pares para formar uma fila de três pontos.
2. Para encontrar o ângulo entre três pontos conhecidos, você pode usar o teorema de Yu Xuan
3. Determine se a soma dos ângulos incluídos é 360°
Cada etapa é simples e é implementada da seguinte forma:
//Calcula a distância entre dois pontos const getDistence = function (p1, p2) { return Math.sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2. y) * (p1.y - p2.y))};//O método angle determina que o ponto está dentro do polígono const checkPointInPolyline = (point, polylinePoints) => { let totalA = 0; const A = ponto; for (deixe i = 0; i < polylinePoints.length; i++) { deixe B, C; ], y: polylinePoints[i][1] }; C = { x: polylinePoints[0][0], y: polylinePoints[0][1] }; { x: polylinePoints[i][0], y: polylinePoints[i][1] }; C = { x: polylinePoints[i + 1][0], y: polylinePoints[i + 1][1] }; } //Calcula o ângulo const ânguloA = Math.acos((Math.pow(getDistence(A, C), 2) + Math.pow(getDistence(A, B), 2) - Math.pow(getDistence(B, C), 2)) / (2 * getDistence(A, C) * getDistence(A, B))) totalA += angleA } //Julgue a soma de ângulos retornam totalA === 2 * Math.PI}Uma limitação deste método é que a forma deve ser um polígono convexo. Se o polígono não for um polígono convexo, ele precisará ser cortado em um polígono convexo antes do cálculo, o que é mais complicado.
Uma ideia semelhante é o método da área. Se um ponto estiver dentro de um polígono, então a soma das áreas do triângulo formado pelo ponto e todos os vértices do polígono deve ser igual à área do polígono. É muito difícil calcular a área do polígono primeiro, então este método você pode passá-lo diretamente.
Método de raioO método do raio é um método que não consigo explicar claramente, mas é muito fácil de usar. Contanto que o número de pontos de intersecção entre um ponto e um lado do polígono seja um número ímpar, o ponto está dentro do polígono. Observe que você só precisa contar o número de pontos de foco em qualquer lado, como o lado esquerdo. Este método não limita o tipo de polígono, polígonos convexos, polígonos côncavos ou mesmo anéis são aceitáveis.
Também é muito simples de implementar:
const checkPointInPolyline = (point, polylinePoints) => { //Método Ray let leftSide = 0; == polylinePoints.length - 1) { B = { x: polylinePoints[i][0], y: polylinePoints[i][1] }; polylinePoints[0][0], y: polylinePoints[0][1] } else { B = { x: polylinePoints[i][0], y: polylinePoints[i][1] }; : polylinePoints[i + 1][0], y: polylinePoints[i + 1][1] } } //Juiz intersecção esquerda let sortByY = [By, Cy].sort((a,b) => ab) if (sortByY[0] < Ay && sortByY[1] > Ay){ if(Bx<Ax || Cx < Ax){ leftSide++ } } } return leftSide % 2 === 1}Existe um caso especial do método dos raios, que requer tratamento especial quando o ponto está na borda de uma multideformação. Mas na engenharia acho que não precisa ser processado, porque se acontecer do usuário clicar no limite do gráfico, o programa pensa que ele não clicou e pode passar.
ResumirOs três métodos acima podem realizar a detecção de cliques em gráficos irregulares na tela. Entre eles, a vantagem do método do pixel é que ele não escolhe formas e tem certas vantagens de desempenho em cenas estáticas. Deve-se dizer que o método do ângulo tem apenas valor teórico e pouca praticidade. O mais prático em engenharia é o método do raio; , que tem poucas limitações e é fácil de implementar. Simples, na maioria das vezes você só precisa conhecer o método ray.