I am trying to treat a rectangle in canvas as a piece of paper, and get the same relative coordinates returned when I hover over the same point regardless of scale, rotation, or translation of the page.
Currently I get accurate results when in portrait or inverted portrait rotations and regardless of scale/translation. However, when I switch to landscape or inverted landscape my results are off.
I've attempted to switch to rotating mouse coordinates with some trigonometric functions I found, but math is not my strong suit and it didn't work.
If someone could point me in the right direction, I would be grateful. I suspect I need to swap axis or height/width when rotating landscape but that hasn't been fruitful either.
R key rotates the "page" through 4, 90 degree changes. Coordinates of your mouse relative to the page, clamped to the page's width/height are displayed in console.
https://jsfiddle.net/2hg6u3wd/2/ (Note, JSFiddle offsets coordinates slightly for an unknown reason)
const orientation = Object.freeze({
portrait: 0,
landscape: -90,
invertedPortrait: 180,
invertedLandscape: 90
});
function CameraRotate(rotation) {
// Rotates using the center of target as origin.
ctx.translate(target.width / 2, target.height / 2);
ctx.rotate(-(currentRot * Math.PI / 180)); // Negate currentRot because ctx.rotate() is additive.
ctx.rotate(rotation * Math.PI / 180);
ctx.translate(-(target.width / 2), -(target.height / 2));
currentRot = rotation;
}
function CameraCalcRelTargetCoords(viewX, viewY) {
return {
x: clamp((viewX - ctx.getTransform().e) / ctx.getTransform().a, 0, page.width),
y: clamp((viewY - ctx.getTransform().f) / ctx.getTransform().d, 0, page.height)
};
}
function clamp(number, min, max) {
return Math.max(min, Math.min(number, max));
}
canvas.addEventListener(`mousemove`, function(e) {
console.log(CameraCalcRelTargetCoords(e.x, e.y));
});
When rotating (-)180 degrees, the scale is stored as skew since the axis are flipped. Thus you must divide by m12 and m21. This flipping also means x and y mouse coordinates need to be swapped as well.
Here is my solution:
function CameraCalcRelTargetCoords(viewX, viewY) {
// Mouse coordinates are translated to a position within the target's rectangle.
let relX, relY
if (currentRot == orientation.landscape || currentRot == orientation.invertedLandscape) {
// Landscape rotation uses skewing for scale as X/Y axis are flipped.
relX = clamp((viewY - ctx.getTransform().f) / ctx.getTransform().b, 0, target.width);
relY = clamp((viewX - ctx.getTransform().e) / ctx.getTransform().c, 0, target.height);
} else {
relX = clamp((viewX - ctx.getTransform().e) / ctx.getTransform().a, 0, target.width),
relY = clamp((viewY - ctx.getTransform().f) / ctx.getTransform().d, 0, target.height)
}
return {x: relX, y: relY};
}