I'm currently developing an image editor with HTML5 Canvas, and I'm having a problem detecting the image coordinates when mousing over the canvas.
I have replicated the problem in a code snipped with a rectangle:
When:
What I want and I don't know how to do it:
(0, 0)
of the canvas will become negative. And the displayed (0, 0)
on the bottom should correspond with the blue text.1
, but after changing to 0.5
or 1.5
should work in the same way.Here below I share the code snipped to see if anyone can help me with that because I'm a little frustrated and I'm sure it's silly. Thanks a lot!
const RECT_SIZE = 200
const ZOOM = 1
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
const svgPoint = svg.createSVGPoint()
const xform = svg.createSVGMatrix()
const canvas = document.querySelector('canvas')
const ctx = canvas.getContext('2d')
const res = document.querySelector('.res')
const pt = transformedPoint(canvas.width / 2, canvas.height / 2)
const X = canvas.width / 2 - RECT_SIZE / 2
const Y = canvas.height / 2 - RECT_SIZE / 2
function transformedPoint(x, y) {
svgPoint.x = x
svgPoint.y = y
return svgPoint.matrixTransform(xform.inverse())
}
function mousemove(e) {
const { left, top } = canvas.getBoundingClientRect()
res.textContent = `X: ${e.clientX - left} - Y: ${e.clientY - top}`
}
// SCALING CANVAS
ctx.translate(pt.x, pt.y)
ctx.scale(ZOOM, ZOOM)
ctx.translate(-pt.x, -pt.y)
// SETTING SOME DEFAULTS
ctx.lineWidth = 1
ctx.strokeStyle = 'green'
ctx.fillStyle = 'blue'
// DRAWING A REACTANGLE
ctx.beginPath()
ctx.strokeRect(X, Y, RECT_SIZE, RECT_SIZE)
ctx.font = "12px Arial";
ctx.fillText("0,0", X - 5, Y-10);
ctx.fillText("200,200", X + RECT_SIZE - 15, Y + RECT_SIZE + 15);
ctx.closePath()
canvas {
border: 1px solid red;
}
<canvas width="400" height="400" onmousemove="mousemove(event)"}></canvas>
<div class="res" />
Changing the line:
res.textContent = `X: ${e.clientX - left} - Y: ${e.clientY - top}`
to
res.textContent = `X: ${e.clientX - left - X} - Y: ${e.clientY - top - Y}`
Is displaying the correct coordinates when ZOOM = 1
. However, is not displaying the correct coordinates after change the zoom.
You have to add ZOOM value to the X and Y calculation like in the example below. I used Math.round method as the final X and Y value is a long fraction.
const RECT_SIZE = 200
const ZOOM = 1.4
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
const svgPoint = svg.createSVGPoint()
const xform = svg.createSVGMatrix()
const canvas = document.querySelector('canvas')
const ctx = canvas.getContext('2d')
const res = document.querySelector('.res')
const pt = transformedPoint(canvas.width / 2, canvas.height / 2)
const X = canvas.width / 2 - RECT_SIZE / 2;
const Y = canvas.height / 2 - RECT_SIZE / 2;
canvas.addEventListener('mousemove',(event)=>{
const {top, left} = event.target.getBoundingClientRect();
const zoomX = Math.round((event.clientX - left - (canvas.width / 2 - ((RECT_SIZE * ZOOM) / 2)))/ZOOM);
const zoomY = Math.round((event.clientY - top - (canvas.height / 2 - ((RECT_SIZE * ZOOM) / 2)))/ZOOM);
res.textContent = `X: ${zoomX} - Y: ${zoomY}`;
});
function transformedPoint(x, y) {
svgPoint.x = x
svgPoint.y = y
return svgPoint.matrixTransform(xform.inverse())
}
// SCALING CANVAS
ctx.translate(pt.x, pt.y)
ctx.scale(ZOOM, ZOOM)
ctx.translate(-pt.x, -pt.y)
// SETTING SOME DEFAULTS
ctx.lineWidth = 1
ctx.strokeStyle = 'green'
ctx.fillStyle = 'blue'
// DRAWING A REACTANGLE
ctx.beginPath()
ctx.strokeRect(X, Y, RECT_SIZE, RECT_SIZE)
ctx.font = "12px Arial";
ctx.fillText("0,0", X - 5, Y-10);
ctx.fillText("200,200", X + RECT_SIZE - 15, Y + RECT_SIZE + 15);
ctx.closePath()
canvas {
border: 1px solid red;
}
<canvas width="400" height="400"}></canvas>
<div class="res" />
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With