daniel metlitski daniel metlitski - 1 month ago 14
CSS Question

Javascript making image rotate to always look at mouse cursor?

I'm trying to get an arrow to point at my mouse cursor in javascript. Right now it just spins around violently, instead of pointing at the cursor.

Here is a fiddle of my code: https://jsfiddle.net/pk1w095s/

And here is the code its self:

var cv = document.createElement('canvas');
cv.width = 1224;
cv.height = 768;
document.body.appendChild(cv);

var rotA = 0;

var ctx = cv.getContext('2d');

var arrow = new Image();
var cache;
arrow.onload = function() {
cache = this;
ctx.drawImage(arrow, cache.width/2, cache.height/2);
};

arrow.src = 'https://d30y9cdsu7xlg0.cloudfront.net/png/35-200.png';

var cursorX;
var cursorY;
document.onmousemove = function(e) {
cursorX = e.pageX;
cursorY = e.pageY;

ctx.save(); //saves the state of canvas
ctx.clearRect(0, 0, cv.width, cv.height); //clear the canvas
ctx.translate(cache.width, cache.height); //let's translate


var centerX = cache.x + cache.width / 2;
var centerY = cache.y + cache.height / 2;



var angle = Math.atan2(e.pageX - centerX, -(e.pageY - centerY)) * (180 / Math.PI);
ctx.rotate(angle);

ctx.drawImage(arrow, -cache.width / 2, -cache.height / 2, cache.width, cache.height); //draw the image
ctx.restore(); //restore the state of canvas
};

Answer

In the first instance, get rid of the conversion to degrees - both the Math.atan2 and the ctx.rotate functions take radians.

That fixes the wild rotation - you still then have some math errors, which are most easily sorted out by splitting out the drawing from the math.

The function below draws the arrow following the normal cartesian convention that angles are measured counter-clockwise from the positive X axis.

// NB: canvas rotations go clockwise
function drawArrow(angle) {
    ctx.clearRect(0, 0, cv.width, cv.height);
    ctx.save();
    ctx.translate(centerX, centerY);
    ctx.rotate(-Math.PI / 2);  // correction for image starting position
    ctx.rotate(-angle);        // reverse direction
    ctx.drawImage(arrow, -arrow.width / 2, -arrow.height / 2);
    ctx.restore();
}

and likewise here, the angle is calculated taking into account that the canvas Y axis points in the wrong direction for normal cartesian math.

document.onmousemove = function(e) {
    var dx = e.pageX - centerX;
    var dy = e.pageY - centerY;
    var theta = Math.atan2(-dy, dx);  // y axis negative
    drawArrow(theta);
};

working demo at https://jsfiddle.net/alnitak/5vp0syn5/