Calculate the accurate x and y position of a div inside a rotated div - html

I've implemented a zoom and crop on the HTML5 Canvas. Zoom is actually increasing the height and width of the Canvas so that it looks zoomed. For crop, I wrote an algorithm to select a rectangular area using mouse and then crop it. Now, if I want to crop when the image is zoomed in or out, while selecting the crop area I have to consider the top and left position displacement caused due to the zoom , which works fine.
So I'm now implementing a rotate (using css3 transform: rotate). The problem is, when I rotate the image by a certain angle, the selection appears a little away from the actual mouse position. This used to happen for the zoom effect as well, but since I used to subtract the added left and top distance from the x and y position resp., I was able to draw the selection even when the image was zoomed. I don't understand how I should do it for a rotated image!
The following image might help you understand my problem a little more clearly:
There's a div around the canvas, reflecting the canvas. It'll have the same width, height, top, left properties as the canvas. This is done on purpose since I can't add the selection, which is absolute, as the child of the canvas. Now this cover, when selected in FireBug, still shows as a rectangle with increased width and height and changed top and left positions.
I understand I have to calculate the displacement like I'm already doing for zoom, but I don't know how to do it! I have spent a lot of time trying out stuff like Pythagoras algorithm and rotational matrix and blah blah!
Please help me out!

You can rotate each of the vertices using this function where "pnt" is a vertex, "pivot" is the point you're rotating around and "angle" is the angle in radians
function rotatePoint(pnt, pivot, angle){
var data = figureAngle(pivot, pnt),
theta = data.angle + angle,
rise = Math.sin(theta) * data.length,
run = Math.cos(theta) * data.length;
return {
x: pivot.x + run,
y: pivot.y + rise
}
}
function figureAngle(start, end){
var rise = (end.y - start.y),
run = (end.x - start.x),
length = Math.sqrt(Math.pow(rise, 2) + Math.pow(run, 2));
return {length: length, angle: Math.atan2(-rise, -run) + Math.PI};
}
Then your horizontal shift is going to be the smallest x of the 4 new vertices, and your vertical shift is going to be the smallest y.
EDIT: this assumes your top left coordinate is [0, 0] before you rotate. If not you need to subtract your starting coordinates from the results i.e. if your top-left corner starts at [50, 100], your horizontal shift would be xMin - 50, and your vertical would be yMin - 100

Related

Problem- can't get the accurate coordinates of mouse on page resize, when using html5 canvas

I wanted to create this Pixel Effect from Frontend Expert.
Although I was able to implement the entire pixel effect on a full screen canvas:
const canvas = getElementById('canvas');
canvas.height = window.innerHeight; // Gives the canvas height of fullscreen
canvas.width= window.innerWidth; // Gives the canvas width of fullscreen
and got the coordinates of the mouse pretty easily
const mouse = {
x: undefined,
y: undefined
}
canvas.addEventListner('mousemove', function(e) {
mouse.x = e.x;
mouse.y = e.y;
}
About now the canvas width and height was equal to that of the document, therefore, it was pretty easy to get the exact coordinates of the mouse.
But when I tried to implement it with 800px X 400px dimensions and used a flexbox with it (like shown in the website) my mouse coordinates got completely messed up and I spent hours in fixing but wasn't able to get the accuracy as shown in the above website. Also there were some issues related to resize.
I would like to know how can I preserve the mouse accuracy.
Your help is much appreciated.
I believe when you use e.x and e.y, even though used in an event listener for tha canvas, they return the mouse coordinate relative to the top-left pixel of the entire page, not just the canvas. If by messed up, you mean that anywhere you click, the pixel effect is offset in some constant direction, this may be your issue and you should replace e.x and e.y with e.clientX and e.clientY. The ‘client’ in e.clientX refers to which element the listener is for and specifies to give event coordinates relative to that element instead of the page. If it is messed up in some other way, then I don’t think I have an answer for that.

Canvas drawImage() method - how to offset source image in a scaled and offset origin?

PROBLEM
Source image dimensions:
width: 2448
height: 2448
Canvas dimensions:
width: 323
height: 323
Image position and scale on the canvas
x: 141.8 (x coordinate where to place the image on the canvas)
y: 214.55 (y coordinate where to place the image on the canvas)
width: 178.7 (the width of the image to use (stretch or reduce the image)
height: 134.1 (the height of the image to use (stretch or reduce the image)
I have called drawImage like this:
ctx.drawImage(img, x, y, width, height)
ctx.drawImage(img, 141.8, 214.55, 178.7, 134.1);
yes! the image is scaled and positioned correctly on the canvas.
but oh no! it is cutting off the face of my subject! I need to offset the source image while maintaining the positioning and scaling I had on the canvas.
I know that I need to use
context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height);
// sx: x coordinate where to start clipping
// sy: y coordinate where to start clipping
// swidth: The width of the clipped image
// height: The height of the clipped image
I need to offset in the x direction by 158 of the original source image (2448 of width)
After hours and hours of trying different equations and reading the documentation to find the correct numbers to fill in the missing variables, I couldn't figure it out how to offset the source image without altering the positioning and scaling I already had.
I referred to documentation here: https://www.w3schools.com/tags/canvas_drawimage.asp
and tried to experiment here https://www.w3schools.com/tags/tryit.asp?filename=tryhtml5_canvas_drawimage2
need the equations and explanation to calculate sx, sy, swidth, and sheight!

Does an offscreen canvas have as much "space" as a normal one?

I have a situation similar to this question about copying data between canvases, but in my case I think I'm running into issues with the canvas engine itself and I'd like some understanding/guidance on what I might be doing wrong.
I'm creating an offscreen canvas with the same width and height as the onscreen canvas.
#offscreenCanvas = document.createElement('canvas')
# assign same dimensions as onscreen canvas
#offscreenCanvas.width = canvas.width
#offscreenCanvas.height = canvas.height
Then I'm drawing from the offscreen canvas to the onscreen one like this:
# grab the width and height of the canvas
{ width, height } = #canvasElement
{ x, y } = offset
# copy image from layer into canvas
#context.drawImage
#offscreenContext.canvas, -x, -y, width, height, -x, -y, width, height
The offset is also the argument into a function which translates the "live" canvas context before all this drawing takes place.
#context.save()
#context.translate(#offset.x,#offset.y)
#renderer.draw(world, #offset)
#context.restore()
In other words we're trying to grab the section of the offscreen context that corresponds to the translated offset of the on-screen context.
This has some issues. When the offset moves the 'camera' far from the origin, you encounter the 'edges' of the offscreen canvas.
Note that when I do the same rendering operations against the onscreen canvas, the elements are fine.
It seems like the offscreen canvas isn't quite as good about handling drawing off its "edges" the same way the canvas is (silently ignores drawing commands outside of its defined region.) In other words, the offscreen canvas doesn't seem to reflect any drawing I've done above or to the left of [0,0] (or alternatively, below or to the right of [width,height].) Are there ways of accommodating this?
Things I've tried:
adjusting up the width and height of the offscreen canvas (this unfortunately seems to have a hard-to-predict impact on coordinates)
I've been able to address the issue by indicating a larger offscreen canvas size. The issue with coordinates seemed to be about Isomer's origin position (which you can override by passing in a different origin.)
A minor note: as per MDN's article on canvas optimization you need to ensure the coordinates and dimensions you pass to drawImage aren't floating point (i.e, call Math.floor on them.) I was running into odd antialiasing artifacts without this.

Scaling photo image on html5 canvas at preset location

I have been struggling with this problem for sometime, I hope someone would be able to help me out on this.
I have added canvas object in my html code, in which I load a photo image. I am trying to scale the image at some random coordinates, but the scaling happens only from the center of the canvas. If I use translate the whole image moves as the origin changes. I have also tried transform but that too doesn't give the desired result.
use context.drawImage() + extended parameters to scale your original image onto your canvas
context.drawImage(srcImage, srcX, srcY, srcWidth, srcHeight,
canvasX, canvasY, scaledWidth, scaledHeight)
Where:
srcImage = your source image
srcX = the X-coord on your source image you want to start grabbing pixels from
srcY = the Y-coord on your source image you want to start grabbing pixels from
srcWidth = width of a rectangle of pixels you want to start grabbing from the source image
srcHeight = height of a rectangle of pixels you want to start grabbing from the source image
canvasX - the X coord on the canvas where you want to start painting your pixel rectangle
canvasY - the Y coord on the canvas where you want to start painting your pixel rectangle
scaledWidth - scale the source pixel rectangle to this width before painting to the canvas
scaledHeight - scale the source pixel rectangle to this height before painting to the canvas
For example:
context.drawImage(myMap, 50,50,100,150, 20,20,200,300)
This will grab a 100x150px rectangle of pixels from myMap image object starting at coordinate [50,50].
Then it will scale the pixel rectangle to 200x300px.
And finally, it will paint the scaled-up pixel rectangle at coordinate [20,20] on the canvas

scaling in sprite that preserves central point of it's visible part

I'm having a sprite (canvas) which is being scaled. The canvas has a mask. The problem is that simple scaling (scaleX=newScale; scaleY=newScale;) takes the part of canvas under mask beyound the mask. So I need to move canvas after scaling in such a way that point of canvas under mask remain in the same place. I'm trying to do something like the following:
var deltaScale = newScale / scale;
//w and h are width and height of mask
canvas.scaleX = newScale;
canvas.scaleY = newScale;
canvas.x += (canvas.x + w/2) - (canvas.x + w/2) / deltaScale;
canvas.y += (canvas.y + h/2) - (canvas.y + h/2) / deltaScale;
still after that central point do not remain on the same place. Can somebody prompt me how should I move canvas after scaling?
PS: width and height of canvas is extremely big (some of 25000) if that helps.
UPD: Canvas with it's mask are added on Sprite, mask is having the same sizes as that parent sprite, canvas.x and canvas.y are negative.
The way I did something similar before was to put the canvas sprite inside another sprite eg. zoom which has its reg point in the centre of the screen (or where ever needed). You can then move canvas around inside the zoom sprite (in my case it was draggable) and scale the outer sprite so the centre is zoomed into.
Scaling and positioning different sprites I found much easier than doing an offset.