Frontend Development 7 min read

Detect Clicks Inside Polygons on Canvas with Crossing & Winding Numbers

Learn how to capture click events on an HTML5 Canvas, compute the click coordinates, and determine whether the point lies inside a polygon using both the Crossing Number (even‑odd) method and the more robust Winding Number algorithm, complete with JavaScript code examples.

KooFE Frontend Team
KooFE Frontend Team
KooFE Frontend Team
Detect Clicks Inside Polygons on Canvas with Crossing & Winding Numbers

In Canvas‑based applications, clicking a shape often needs to trigger interaction, but Canvas does not support attaching events directly to drawn elements, so mathematical techniques are required.

Getting coordinates

Although Canvas cannot add events to individual shapes, you can listen to the Canvas element’s click event and calculate the click position relative to the canvas.

<code>canvas.addEventListener('click', (event) => {
  const rect = canvas.getBoundingClientRect();
  const x = event.clientX - rect.left;
  const y = event.clientY - rect.top;
  const point = { x, y };
  console.log(point); // prints click coordinates
});</code>

If the user clicks inside a shape, the click point will lie within that shape. For simplicity we discuss polygons only. Determining whether a point is inside a polygon can be done with the Crossing Number (even‑odd) method or the Winding Number method.

Crossing Number Method

The crossing number method casts a ray from the point; if the ray intersects the polygon edges an odd number of times, the point is inside, otherwise it is outside.

Typically a horizontal ray to the right (positive x‑axis) is used. The implementation is:

<code>function getCrossingNumber(point, lines) {
  let count = 0;
  for (let i = 0; i < lines.length; i++) {
    // o, d are the start and end points of a polygon edge
    const { o, d } = lines[i];
    // an intersection occurs only when the edge straddles the horizontal ray
    if ((o.y > point.y) ^ (d.y > point.y)) {
      const x = (point.y - o.y) * (d.x - o.x) / (d.y - o.y) + o.x;
      if (x > point.x) {
        count += 1;
      }
    }
  }
  return count;
}
</code>

The Fabric.js library uses this crossing‑number technique to test point‑in‑polygon (see its source code).

In some cases the crossing‑number method can give incorrect results; the winding‑number method is generally more reliable.

Winding Number Method

The winding number method also casts a horizontal ray to the right. When an edge crosses the ray upward, the winding number increments; when it crosses downward, the winding number decrements. A non‑zero winding number means the point is inside.

For humans, distinguishing upward versus downward crossings is intuitive, but in code it is easier to convert this vertical relationship into a left/right test. If an edge crosses upward, the point P lies to the left of edge AB; if it crosses downward, P lies to the right.

Using the right‑hand rule, when P is on the left side of AB the outward normal of AB and AP points outward; when P is on the right side, the normal points inward. The normal can be computed via the cross product of vectors AB and AP:

<code>vector AB = (x1, y1, 0)
vector AP = (x2, y2, 0)
AB × AP = (x1*y2 - x2*y1)k
// k is the unit vector along the z‑axis; the sign of (x1*y2 - x2*y1) indicates direction
</code>

From this we obtain:

If x1*y2 - x2*y1 > 0, P is on the left side of AB, winding number +1.

If x1*y2 - x2*y1 = 0, P lies on AB, winding number unchanged.

If x1*y2 - x2*y1 < 0, P is on the right side of AB, winding number -1.

Summary

Both algorithms allow you to determine whether a click on a Canvas falls inside a polygon and then trigger the appropriate interaction. The winding‑number method requires a bit more mathematical insight but is straightforward to implement.

References

https://blog.csdn.net/u013279723/article/details/106265948/

https://www.geeksforgeeks.org/even-odd-method-winding-number-method-inside-outside-test-of-a-polygon/

https://towardsdatascience.com/is-the-point-inside-the-polygon-574b86472119

JavaScriptCanvaspoint-in-polygoncrossing-numberwinding-number
KooFE Frontend Team
Written by

KooFE Frontend Team

Follow the latest frontend updates

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.