Angle to cursor, with different orientation of zero degrees

60 Views Asked by At

I'm trying to make a utility function to determine the angle from an element to the mouse cursor, but allow our devs to change where 0 is located. So this needs to return the angle as degrees between 0deg through to 360degs.

So I'm trying to write a function that can do that. I have it working for zero at due west, but need to get it working for zero at north, east and south.

It' surprisingly difficult. I have tried just adding 90deg to the radians with 90° × π/180 = 1.571rad but then struggled to get it back to degrees for the return.

function getAngleToCursor(el, evt, orientation = "north") {
    const mouseX = evt.clientX
    const mouseY = evt.clientY
    
    const elRect = el.getBoundingClientRect()
    const elX = elRect.left + elRect.width / 2
    const elY = elRect.top + elRect.height / 2

    const rads = Math.atan2(mouseY-elY, mouseX-elX)
    let angle = 0

    // Change where zero is located
    switch(orientation) {
        case "west":
            angle = rads * 180 / Math.PI + 180
            break;

        case "north":
            angle = ?
            break;  

        case "east":
            angle = ?
            break;  
        
        case "south":            
            angle = ?
            break;
    }

    return angle
}

Codepen here

1

There are 1 best solutions below

4
Joachim On BEST ANSWER

Skip to the ending: Final version of it is here for future reference: https://github.com/funkhaus/fuxt/blob/master/utils/angleDistanceToCursor.js

Okay, I think I get what you mean. I’ve posted the updated code below:

function getAngleToCursor(el, evt, orientation = "north") {
    // get normal angle from mouse to element
    const mouseX = evt.clientX
    const mouseY = evt.clientY
    const elRect = el.getBoundingClientRect()
    const elX = elRect.left + elRect.width / 2
    const elY = elRect.top + elRect.height / 2

    const rads = Math.atan2(mouseY-elY, mouseX-elX)
    let angle = rads
    const whole = Math.PI * 2

    // Change where zero is located
    switch(orientation) {
        case "west":
            angle -= whole / 4
            break

        case "north":
            angle += 0
            break

        case "east":
            angle += whole / 4
            break
        
        case "south":            
            angle += whole / 2
            break
    }

    // convert angle to range between 0 and 360 (although we’re working in radians, of course)
    angle = ((angle % whole) + whole) % whole

    // returns angle in degrees
    return angle * 180 / Math.PI
}

I haven’t tested this by the way, but the concept is pretty sound even if the code isn’t perfect.