Les éléments internes du canevas ne peuvent pas ajouter d'écouteurs d'événements interactifs aussi facilement que les éléments DOM, car il n'y a pas de concept d'éléments dans le canevas, ce sont simplement des graphiques dessinés par le canevas. C'est un obstacle nécessaire au développement interactif. L'idée de surveiller l'événement de clic d'un graphique est très simple. Il suffit d'écouter l'événement de clic de l'élément canevas lui-même, puis de déterminer dans quel graphique se trouvent les coordonnées de clic, et alors l'événement de clic graphique peut être réalisé de manière déguisée. Cet article présente trois méthodes pour déterminer si le point de coordonnées est situé à l'intérieur d'un graphique de canevas.
AccordLes trois méthodes présentées dans cet article conviennent pour identifier les événements de clic graphiques avec des formes irrégulières et des positions irrégulières dans le canevas. Pour les scènes avec des formes ou des positions régulières, il doit y avoir des implémentations plus simples, qui ne seront pas abordées ici.
méthode des pixelsL'idée de la méthode de détection de pixels est de dessiner séparément plusieurs graphiques dans le canevas (s'il y en a plusieurs) hors écran, et d'utiliser la méthode getImageData() pour obtenir les données de pixels et les enregistrer. Lorsque l'élément canevas écoute un événement de clic, les coordonnées du clic peuvent être utilisées pour calculer directement le pixel sur le canevas où le clic s'est produit, puis parcourir les données graphiques précédemment enregistrées pour voir si la valeur alpha de ce pixel est 0. Si c'est 0, cela signifie que le point d'atterrissage n'est pas dans le chiffre actuel, sinon cela signifie que le point a atteint ce chiffre.
Méthode pour obtenir le numéro de pixel cliqué en fonction des coordonnées du clic :
Numéro de pixel = (ordonnée-1) * largeur du canevas + abscisse
Par exemple, si vous cliquez sur les coordonnées (3,3) sur une toile d'une largeur de 5, le nombre de pixels obtenu selon la formule ci-dessus est (3-1) * 5 + 3 = 18, comme indiqué sur la figure :
Étant donné que les données graphiques exportées par Canvas stockent chaque pixel dans un tableau de 4 nombres dans l'ordre rgba, donc si vous souhaitez accéder à la valeur alpha d'un pixel spécifié, il vous suffit de lire la valeur pIndex * 4 + 3 de ce tableau. , si cette valeur n'est pas 0, cela signifie que le pixel est visible, c'est-à-dire que l'on clique sur le graphique.
Cette méthode est, à mon avis, celle qui a les idées les plus directes et les résultats les plus précis, et n'a aucune exigence sur la forme des graphiques. Cependant, cette méthode a une limitation fatale lorsque les graphiques doivent être déplacés sur le canevas. , des caches de données doivent être créés fréquemment pour garantir la détection. Les résultats sont précis. Affectées par la taille du canevas et le nombre de graphiques, les performances de la méthode getImageData() deviendront un sérieux goulot d'étranglement. Donc, si le graphique du canevas est statique, cette méthode est très appropriée, sinon il n'est pas approprié d'utiliser cette méthode.
Méthode angulaireLe principe de la méthode de jugement d'angle est facile à comprendre. Si un point se trouve à l'intérieur d'un polygone, la somme de l'angle entre le point et tous les sommets du polygone doit être exactement de 360°.
Le processus de calcul peut être transformé en trois étapes suivantes :
1. Étant donné les sommets et les coordonnées connus du polygone, combinez les coordonnées et les sommets par paires pour former une file d'attente à trois points.
2. Pour trouver l’angle entre trois points connus, vous pouvez utiliser le théorème de Yu Xuan
3. Déterminez si la somme des angles inclus est de 360 °
Chaque étape est simple et se déroule comme suit :
//Calculer la distance entre deux points const getDistence = function (p1, p2) { return Math.sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2. y) * (p1.y - p2.y))};//La méthode de l'angle détermine que le point est à l'intérieur du polygone const checkPointInPolyline = (point, polylinePoints) => { let totalA = 0; const A = point; pour (soit i = 0; i < polylinePoints.length; i++) { let B, C; if (i === polylinePoints.length - 1) { B = { x: polylinePoints[i][0 ], y : polylinePoints[i][1] } ; C = { x : polylinePoints[0][0], y : polylinePoints[0][1] } else { B = { x : polylinePoints[i][0], y : polylinePoints[i][1] } ; C = { x : polylinePoints[i + 1][0], y : polylinePoints[i + 1][1] } ; } //Calculer l'angle const angleA = 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 } //Juger la somme de les angles renvoient totalA === 2 * Math.PI}Une des limites de cette méthode est que la forme doit être un polygone convexe. Si le polygone n'est pas un polygone convexe, il doit être découpé en polygone convexe avant le calcul, ce qui est plus compliqué.
Une idée similaire est la méthode des aires. Si un point se trouve à l'intérieur d'un polygone, alors la somme des aires du triangle formé par le point et de tous les sommets du polygone doit être égale à l'aire du polygone. très difficile de calculer d'abord l'aire du polygone, donc cette méthode Vous pouvez la transmettre directement.
Méthode des rayonsLa méthode des rayons est une méthode que je ne peux pas expliquer clairement mais qui est très simple à utiliser. Tant que le nombre de points d'intersection entre un point et un côté du polygone est un nombre impair, le point est à l'intérieur du polygone. Notez qu'il vous suffit de compter le nombre de points AF de n'importe quel côté, comme le côté gauche. Cette méthode ne limite pas le type de polygone, les polygones convexes, les polygones concaves ou même les anneaux sont acceptables.
C’est aussi très simple à mettre en œuvre :
const checkPointInPolyline = (point, polylinePoints) => { //Méthode Ray let leftSide = 0; const A = point; for (let i = 0; i < polylinePoints.length; i++) { let B, C; == 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] }; //Juge l'intersection gauche 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}Il existe un cas particulier de la méthode des rayons, qui nécessite un traitement particulier lorsque la pointe est sur une arête de déformations multiples. Mais en ingénierie, je pense que cela n'a pas besoin d'être traité, car si l'utilisateur clique sur la limite du graphique, alors le programme pense qu'il n'a pas cliqué et peut passer.
RésumerLes trois méthodes ci-dessus peuvent toutes réaliser une détection par clic de graphiques irréguliers dans le canevas. Parmi eux, l'avantage de la méthode des pixels est qu'elle ne sélectionne pas de formes et présente certains avantages en termes de performances dans les scènes statiques ; il faut dire que la méthode des angles n'a qu'une valeur théorique et qu'elle est peu pratique. La méthode la plus pratique en ingénierie est la méthode des rayons ; , qui présente peu de limitations et est facile à mettre en œuvre, il suffit la plupart du temps de connaître la méthode des rayons.