Canvas - transforming mouse coordinates on window resize - javascript

I'm working on a canvas project which includes some drag and drop functionality for some bitmap images on the canvas. I'm having trouble selecting images after the canvas has been resized.
At the minute what i've got is working fine for when the canvas is at it's default dimensions.
I'm drawing all my graphics to a canvas then drawing that image to another canvas and displaying that.
So I want to be able to 'select' an image on the canvas.
Obviously I do this by comparing the mouse coordinates with the coordinates of the object.
mouseX = mouse.x - window.offsetLeft; //I'm accounting for the offset
I'm then multiplying the mouse coordinates by (theVisibleCanvas.width / originalCanvas.width) to account for the scaling of the canvas.
This all works fine for when the window is maximized ( the default dimensions) but once I've resized the window the coordinates start getting further and further out.
Can anyone point out any steps involved in translating mouse coordinates in relation to the canvas resizing?

The line of you provided has little to do with canvas as it uses the offset of the window rather than the offset of the canvas.
To get the coordinates from the mouse adjusted to canvas you can use something like this:
function getXY(canvas, event){
var rect = canvas.getBoundingClientRect(), /// get absolute rect. of canvas
x = event.clientX - rect.left, /// adjust for x
y = event.clientY - rect.top; /// adjust for y
return {x:x, y:y}; /// return object
}
Now you can call this:
var pos = getXY(myCanvasElement, theEvent);
console.log(pos.x, pos.y); /// use the pos object for something
Of course, myCanvasElement is a reference to your actual canvas element and theEvent provided by the callback.

Related

Find a point old position after zoom using java script

I am working on this "simple" problem for hours with no success, although I tried many ways to solve it using all kind of solutions suggested in SO.
My problem is as follows:
I have a point on a canvas, which when I click on it my app does something, after identifying the point by comparing the mouse click coordinates to the stored position of the point.
After zooming into the point, using the mouse wheel, I click on the point again but the mouse coordinates no longer fits the stored position of the point.
I need to either transform the mouse coordinates to it's coordinates before the zoom, so I will be able to compare to the stored position, or to transform the stored position to the new canvas so it can be compare to the coordinates of the mouse. Any of the solution is fine by me.
I know the following data:
The "scale" value,
The size of the canvas (top, left, width, height),
The new origin of the canvas (top, left)
I would like a solution using java script.
Finally figured it out and it is quite simple, once I understood the concept.
Save the new canvas origin after doing the zoom (in JS it is calling ctx.translate() and ctx.scale(), where ctx is the canvas context.
When need to calculate the mouse position in the old coordinate system, one has to add back the moved origin of the canvas, and multiply by the scale factor.
seat.x = (-new_org.x + pos.x) / scale;
seat.y = (-new_org.y + pos.y) / scale;
where pos is the calculated mouse pointer
pos.x = event.clientX - .getBoundingClientRect().left;
pos.y = event.clientY - .getBoundingClientRect().top;

avoid distortion drawing lines in canvas

I need help trying to represent lines in a canvas. The lines are drawn with the mouse and my problem comes when I try to make the canvas responsive.
When I am drawing lines in the desktop you don't really see the distortion, but when the canvas is loaded in a mobile and I draw an horizontal line, turns out that it keeps the "round shape" of the point, but in vertical lines the point narrows on the sides so the line gets narrower. Because is difficult to explain I show up a picture where I can ilustrate you better:
I also include an example of the code I am using, so you have a better idea of what I am talking about:
//getting the mouse coords
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
scaleX = canvas.width / rect.width, /*relationship bitmap vs. element for X*/
scaleY = canvas.height / rect.height; /*relationship bitmap vs. element for Y*/
return {
x: Math.round((evt.clientX - rect.left)*scaleX),
y: Math.round((evt.clientY - rect.top)*scaleY)
};
}
and in the context of the canvas I say:
ctx.lineJoin="round";
The full code is here:
https://jsfiddle.net/rhwcbwwL/20/
Thank you in advance!!

Cursor do not follow the position of drawn rectangle in html5 canvas

I have this code that let me draw rectangle on canvas:
https://jsfiddle.net/6u7bLkwc/4/
In order to draw a rectangle on the canvas, click on the image and then drag your mouse.
To reproduce my problem please follow this steps:
Draw a rectangle like mentionned in the top.
And then click on ADD TEXT button.
Now try to draw another rectangle, you will see that your cursor are not in the same way with the rectangle.
How to make my code work even if i add or remove any elements on the page dynamically?
I tried to do like this:
var shape = new Shape(mouseDownX - canvasOffset.left, mouseDownY - canvasOffset.top, mouseX - mouseDownX, mouseY - mouseDownY, color);
But didn't resolved it.
Something like updating new positions will solve it, but not have idea about how to process.
check the solution over here : https://jsfiddle.net/6u7bLkwc/9/
the problem is that you are not calculating the PageX and PageY relative to the canvas position, but instead to the whole page which is giving you wrong coordinates.
I have just changed these:
mouseDownX = e.pageX;
mouseDownY = e.pageY;
to this:
mouseDownX = e.pageX - this.offsetLeft;
mouseDownY = e.pageY - this.offsetTop;
UPDATE
For some other cases you should just use getBoundingClientRect() method on the canvas to get the element position relative to the viewport as the following jsfiddle shows sfiddle.net/dkboaq7p/2
// Get Element's relative position
var canvasPosition=document.getElementById("canvas").getBoundingClientRect();
mouseDownX = e.pageX - canvasPosition.left;
mouseDownY = e.pageY - canvasPosition.top;

How to detect where a stretched canvas was clicked?

I have a canvas that is stretched out since I am making a sandbox game. I can not use the normal method of detecting the pixel on the page a canvas is clicked because I need to know which stretch pixel was clicked. Hopefully this makes sense?
All you have to do is scale the position based on your current canvas size and original canvas size.
function scaleCursorPoint(int mouseX, int mouseY, ctx) {
return {
x: mouseX * (ctx.canvas.width / ctx.width),
y: mouseY * (ctx.canvas.height / ctx.height)
};
}
ctx (which is gotten with canvas.getContext('2d') has the width of the original unstretched. ctx.canvas gets the original canvas DOM element. ctx.canvas.width is the size of the DOM element (the stretched size).
Divide the two and you get the scale value. Then just multiple that scale value with the points you got and you're good

Getting the Screen Pixel coordinates of a Rect element

I am trying to get the screen pixel coordinates of a rectangle in SVG via java script.
When the rectangle has been clicked, I can figure out its width, height, x and y position with getBBox().
But these positions are the original positions. I want the screen position.
For example if I manipulate the viewBox of the whole SVG, these getBBox coordinates are not any more the same than the screen pixels. Is there a function or way to get the
coordinates considering the current viewBox and the pixel size of svg element?
Demo: http://phrogz.net/SVG/screen_location_for_element.xhtml
var svg = document.querySelector('svg');
var pt = svg.createSVGPoint();
function screenCoordsForRect(rect){
var corners = {};
var matrix = rect.getScreenCTM();
pt.x = rect.x.animVal.value;
pt.y = rect.y.animVal.value;
corners.nw = pt.matrixTransform(matrix);
pt.x += rect.width.animVal.value;
corners.ne = pt.matrixTransform(matrix);
pt.y += rect.height.animVal.value;
corners.se = pt.matrixTransform(matrix);
pt.x -= rect.width.animVal.value;
corners.sw = pt.matrixTransform(matrix);
return corners;
}
The magenta squares are absolutely-positioned divs in the HTML element, using screen space coordinates. When you drag or resize the rectangles this function is called and moves the corner divs over the four corners (lines 116-126). Note that this works even when the rectangles are in arbitrary nested transformation (e.g. the blue rectangle) and the SVG is scaled (resize your browser window).
For fun, drag one of the rectangles off the edge of the SVG canvas and notice the screen-space corners staying over the unseen dots.
You can also check for the existence of the elm.getScreenBBox() method, which does what it sounds like. It's defined in SVG Tiny 1.2.
See the files here, which include a fallback implementation of getScreenBBox that should work in all browsers.

Categories