Trouver si un point est sur une ligne

Disons que j'ai une ligne dessinée comme dans HTML5 Canvas:

... ctx.beginPath(); ctx.moveTo(x,y); ctx.lineTo(x1,y1); ctx.closePath(); ... 

Je veux savoir si l'événement de la souris a eu lieu sur cette ligne, et j'ai un code comme celui-ci:

 var handleMouseDown = function(e) { var coords = translateCoords(ex,ey); ... if (ctx.isPointInPath(coords.x, coords.y) { ... 

Maintenant, ce code fonctionne bien dans le cas des cercles et des rectangles, mais pas pour les lignes. J'ai deux questions:

  1. Je pense que peut-être appeler closePath () sur une ligne elle-même est incorrect. Question – Comment vérifier si l'événement de la souris est arrivé sur cette ligne?

  2. Comment puis-je étendre cela pour savoir si l'événement de la souris est passé près de la ligne?

La première étape consiste à trouver la projection normale du point sur la ligne. C'est en fait assez simple: prenez la distance du point 1 à la cible, et le point 2 vers la cible, et appelez-les respectivement D1 et D2. Ensuite, calculer D1+(D2-D1)/2 . C'est la distance au point projeté sur la ligne du point 1.

Vous pouvez maintenant trouver ce point, et obtenir la distance de ce point à la cible. Si la distance est nulle, la cible est exactement sur la ligne. Si la distance est inférieure à 5, alors la cible était inférieure à 5px, et ainsi de suite.

EDIT: Une image vaut mille mots. Voici un diagramme:

Diagramme http://adamhaskell.net/img/schematic.png

(En recul, probablement aurait dû faire de ces cercles une couleur différente … De plus, la ligne pourpre est censée être perpendiculaire à la ligne AB. Blâmez mon terrible but avec la ligne bleue!)

Voici l'approche tirée de l'article Wikipedia Distance d'un point à une ligne (ligne définie par deux points)

  var Dx = x2 - x1; var Dy = y2 - y1; var d = Math.abs(Dy*x0 - Dx*y0 - x1*y2+x2*y1)/Math.sqrt(Math.pow(Dx, 2) + Math.pow(Dy, 2)); 

Où (x0, y0) est vos coordonnées de points et votre ligne est ((x1, y1), (x2, y2)). Cependant, cela ne vérifie pas les limites de la ligne, donc j'ai dû ajouter une autre vérification.

  function inBox(x0, y0, rect) { var x1 = Math.min(rect.startX, rect.startX + rect.w); var x2 = Math.max(rect.startX, rect.startX + rect.w); var y1 = Math.min(rect.startY, rect.startY + rect.h); var y2 = Math.max(rect.startY, rect.startY + rect.h); return (x1 <= x0 && x0 <= x2 && y1 <= y0 && y0 <= y2); } 

Où votre ligne est définie comme rectangle. J'espère que cela t'aides.

Vous avez deux options pour cela. Votre option "simple" consiste à utiliser la toile pour le faire – Lisez les données de pixels partout où la souris est et si elle est de la même couleur que votre ligne, l'utilisateur a cliqué sur la ligne. Cela fait beaucoup d'hypothèses, cependant, de sorte que tout sur votre toile est rendu dans une couleur unie différente. Ceci est possible, cependant, comme une astuce commune est de rendre tout à une toile hors écran dans une couleur unie différente. Ensuite, lorsque l'utilisateur clique quelque chose, vous savez exactement ce que c'est en lisant la couleur de ce pixel et en le mappant à l'objet d'origine.

Mais ce n'est pas exactement ce que vous avez demandé 🙂

Vous ne voulez pas savoir si l'utilisateur a cliqué sur une ligne car ils ne le veulent presque jamais. Une ligne est infiniment mince, donc, à moins qu'elle soit exactement horizontale ou exactement verticale, elle ne clique jamais dessus. Ce que vous voulez plutôt, c'est de voir à quelle distance la souris est en ligne. Kolink vient de répondre à cette partie, alors je vais m'arrêter ici 🙂