Jordan Savant // Software Engineer

/*
   Return the angle between two vectors on a plane
   The angle is from vector 1 to vector 2, positive anticlockwise
   The result is between -pi -> pi
*/
function Angle2D(x1, y1, x2, y2) {
       let dtheta,theta1,theta2;

       theta1 = Math.atan2(y1,x1);
       theta2 = Math.atan2(y2,x2);
       dtheta = theta2 - theta1;
       while (dtheta > Math.PI)
              dtheta -= Math.PI * 2;
       while (dtheta < -Math.PI)
              dtheta += Math.PI * 2;
       return dtheta;
}

function InsidePolygon(polygon, p) {
    let i;
    let angle=0;
    let p1 = {}, p2 = {};
    let n = polygon.points.length;

    for (i=0; i < n; i++) {
        p1.h = polygon.points[i].x - p.x;
        p1.v = polygon.points[i].y - p.y;
        p2.h = polygon.points[(i+1)%n].x - p.x;
        p2.v = polygon.points[(i+1)%n].y - p.y;
        angle += Angle2D(p1.h,p1.v,p2.h,p2.v);
    }

    if (Math.abs(angle) < Math.PI)
        return false
    else
        return true
}

example of wired into mousemovement

c.onmousemove = function(e){
    if (!listening)
        return

    data.innerHTML = '';
    data.style.display = 'none';
    mouseX = e.clientX;
    mouseY = e.clientY;

    // convert to canvas coords
    let cpos = getOffset(c);
    let cx = mouseX - cpos.rawleft;
    let cy = mouseY - cpos.rawtop;

    if (cx > 0 && cx < cpos.rawwidth && cy > 0 && cy < cpos.rawheight) {
        // get mouse position in polygon
        let inside = false;
        for (let i=0; i < polygons.length; i++) {
            if (InsidePolygon(polygons[i], { x: cx, y: cy })) {
                // console.log("INSIDE ", polygons[i].id)
                data.innerHTML = '{{ $refName }} ' + polygons[i].id;
                inside = true;
            }
        }
        if (inside) {
            data.style.display = 'block';
            data.style.top = mouseY - 10;
            data.style.left = mouseX + 10;
        }
    }
}