I have a canvas on which I applied a few transformations (mostly translation to place the origin in the middle and a scale to zoom). I now want to find out if the cursor hovers an element drawn on the canvas.
The detection is quite simple: "is the cursor less than n screen pixels away from the center of the object".
How can I obtain the screen coordinates of an element that has had a transformation applied to it?
Here is what I’ve got so far: I do it the long way and it’s not suitable when I apply other transformations, such as scale.
In the following example, the yellow square is centered at (0;0)
but displayed in the middle of the screen due to ctx.translate()
.
const ctx = canv.getContext('2d')
ctx.fillRect(0, 0, canv.width, canv.height)
ctx.translate(canv.width / 2, canv.height / 2)
ctx.fillStyle = 'yellow'
ctx.fillRect(-4, -4, 8, 8) // centered at (0,0)
canv.addEventListener('mousemove', event => {
const dX = canv.width / 2 - event.offsetX
const dY = canv.height / 2 - event.offsetY
const distance = Math.sqrt(dX * dX + dY * dY)
coord.innerText = `Distance to square: ${distance}`
})
<canvas id="canv"></canvas>
<div id="coord"></div>
Is there a cleaner way to achieve this?
3
Answers
function invertTransform(point, invertedMatrix) {
const x = point.x * invertedMatrix.a + point.y * invertedMatrix.c + invertedMatrix.e
const y = point.x * invertedMatrix.b + point.y * invertedMatrix.d + invertedMatrix.f
point.x = x
point.y = y
return point
}
Your 2D context has a
getTransform()
method, that does return aDOMMatrix
object. From that matrix you can perform all your transformations. In your case, you’ll need the invert matrix, and then usetransformPoint()
to apply that transformation over the point relative to your canvas element.