I wrote a function which allows me to draw circles on a canvas. Everything works fine, but the start position of my canvas is not the same position as my mouse position.
const stopDrawingCircle = () => {
setIsDrawing(false);
console.log(currentImage);
}
//Setting start position
const startDrawingCircle = (event:any) => {
currentImage.circle.x = event.clientX;
currentImage.circle.y = event.clientY;
currentImage.circle.radius = 0;
setIsDrawing(true);
};
const drawCircle = function(event:any){
if(!isDrawing)
return;
let canvas = canvasRef.current as HTMLCanvasElement | null;
let ctx = canvas?.getContext('2d')
//seems to be the problem console log at start says the result of this is zero
var currentX = currentImage.circle.x - event.clientX;
var currentY = currentImage.circle.y - event.clientY;
currentImage.circle.radius = Math.sqrt(currentX * currentX currentY * currentY)
if(canvas != null && ctx != null){
ctx.beginPath();
ctx.arc(currentImage.circle.x, currentImage.circle.y, currentImage.circle.radius, 0, Math.PI*2);
ctx.fill();
}
}
return(
<div className="main">
<div id="imageSection">
<canvas id="canvas"
onm ouseDown={startDrawingCircle}
onm ouseUp={stopDrawingCircle}
onm ouseMove={drawCircle}
ref={canvasRef}> </canvas>
</div>
</div>
)
The result of drawing a circle is like this:
I started with my mouse in the center of the image and he draws it in the "lower right corner"
CodePudding user response:
event.clientX
and event.clientY
are relative to the current screen, not element being clicked.
MDN MouseEvent.clientX docs:
clientX
A number, defaulting to 0, that is the horizontal position of the mouse event on the client window of user's screen;
Use event.offsetX
and event.offsetY
to get the mouse position relative to the event target.
However, since you're using React, you need to use event.nativeEvent.offsetX
and event.nativeEvent.offsetY
because react doesn't copy the offset properties onto their event proxy object.
Full code example:
import {useState, useRef} from "react";
const currentImage = {
circle: {
x: 0,
y: 0,
radius: 10,
}
};
export default function App() {
const [isDrawing, setIsDrawing] = useState(false);
const canvasRef = useRef<HTMLCanvasElement>(null);
const stopDrawingCircle = () => {
setIsDrawing(false);
// console.log(currentImage);
}
//Setting start position
const startDrawingCircle = (event:any) => {
currentImage.circle.x = event.nativeEvent.offsetX;
currentImage.circle.y = event.nativeEvent.offsetY;
currentImage.circle.radius = 0;
setIsDrawing(true);
};
const drawCircle = function(event:any){
if(!isDrawing)
return;
let canvas = canvasRef.current as HTMLCanvasElement | null;
let ctx = canvas?.getContext('2d')
//seems to be the problem console log at start says the result of this is zero
var currentX = currentImage.circle.x - event.nativeEvent.offsetX;
var currentY = currentImage.circle.y - event.nativeEvent.offsetY;
currentImage.circle.radius = Math.sqrt(currentX * currentX currentY * currentY)
if(canvas != null && ctx != null){
ctx.beginPath();
ctx.arc(currentImage.circle.x, currentImage.circle.y, currentImage.circle.radius, 0, Math.PI*2);
ctx.fill();
}
}
return(
<div className="main">
<div id="imageSection">
<canvas id="canvas"
onm ouseDown={startDrawingCircle}
onm ouseUp={stopDrawingCircle}
onm ouseMove={drawCircle}
ref={canvasRef}> </canvas>
</div>
</div>
)
}
CodePudding user response:
It's hard to run your example because it does not seem to be a complete one.
I suspect what your error is and I think this simple example will be enough for you to fix your issue.
const canvas = document.getElementById('canvas');
const drawCircle = function(event){
const ctx = canvas.getContext('2d');
const canvasClientRect = canvas.getBoundingClientRect();
const { clientX, clientY } = event; // absolute click pos
const x = clientX - canvasClientRect.left; // calculate relative x
const y = clientY - canvasClientRect.top; // calculate relative y
ctx.beginPath();
ctx.arc(x, y, 20, 0, Math.PI * 2);
ctx.fill();
}
canvas.addEventListener('click', drawCircle);
<div className="main">
<h1>
Example
</h1>
<div id="imageSection">
<canvas id="canvas" width="500px" height="500px" style="border: 1px solid red;"></canvas>
</div>
</div>
So as you can see getting the clicked X and Y coordinates is not enough and it's not relative to the canvas element and to draw on the canvas you need its relative coordinates.
If your canvas started at the very top left corner of your page it would not matter but if it's not there then it's important to get the canvas coordinates so you can calculate the click position properly.
So let's assume your canvas starts 50px from the top and 100px from the left. To each click on the canvas you need to subtract 50px for the X coordinate and 100px to the Y coordinate. With these relative values you can draw on canvas and the circle will be in the middle of your cursor every time.